1

So I come from Spring Boot background and I was really impressed how Spring @Transactional annotation just worked seamlessly along with Hibernate. I am working on a Dropwizard application now that is using Jdbi3. And I have found a similar @Transaction annotation that works quite the same way as Spring but with some pre conditions.

Spring

So according to Spring Guidelines, Repository and Controller are the two interfaces which communicates to the database and HTTP requests respectively, Service Layer was the place where all the business logic belongs. There was always a case where a single method in service does CRUD operations using multiple repositories. Thus it makes so much sense to make the service method annotate with @Transational.

Jdbi with Dropwizard

So correct me if I am wrong. Here in Jdbi the Repository becomes Dao, Controller becomes Resource and Service remains Service. Maybe different people use different layer architecture, but let's just assume this is the case where my problem lies in.

Problem statement

I wish to achieve the same Transaction Handling in Jdbi as in Spring ideologically because it makes much more sense to me without adding any extra layer. Here's I'll throw some code, what I wish to achieve:

Dao1.kt

 interface Dao1{
    @SqlUpdate("INSERT INTO table1...")
    fun insert() : Int
 }

Dao2.kt

 interface Dao2{
    @SqlUpdate("INSERT INTO table2...")
    fun insert() : Int
 }

Service.kt

class Service{
  @Transaction
  fun save() {
    Dao1 =Dao1() //What should be expected way to instantiate
    Dao2 =Dao2() //What should be expected way to instantiate
    dao1.insert()
    dao2.insert()
  }
}

Few points to note

  • I am aware that onDemand can only be used on abstract class or interface, thus I cannot instantiate Service using onDemand. Also i cannot make my Service abstract.

  • Few articles suggests to make an abstract Repository and use Transaction there. But as per my thought when I think of repository, I see it has a one-to-one mapping with the entity/table. Or maybe related entities. So if I want to update movie and user table in the same service method, putting these two transaction statement under a method in some XRepository sounds very absurd to me. Its a part of business logic and should reside in Service.

  • I think I can use jdbi.inTransaction and jdbi.useTransaction. But in that case I have to attach each and every Dao manually. Is there a better way to do that?

Thanks

Prince Bansal
  • 1,635
  • 15
  • 24

1 Answers1

0

You can use Jdbi's @Transaction to decorate method in your bizlogic classes. It will run underlying db queries in transaction.

Assuming Repository can be composed of multiple Dao's & assuming the flow of control like this, here is how one way to structure your bizlogic (business logic classes) and repositories.

Resource -> BizLogic -> Repository -> Dao 

For instance (Kotlin + Dropwizard + Jdbi):

Resource

    @GET
    @Path("{Id}")
    @Produces(MediaType.APPLICATION_JSON)
    fun getAccount(
            @PathParam("Id") Id: String,
            @Suspended asyncResponse: AsyncResponse
    ) = asyncResponse.with {
        accountManager.getAccount(Id)
    }

method in BizLogic

    @Transaction
    suspend fun getAccount(Id: String): List<Account> = 
       accountRepository.getAccountsById(Id) ?: emptyList()

method in Repository

    suspend fun getAccountsById(Id: String): List<Account>? = withContext(Dispatchers.IO){
        accountDao.lookupById(Id)
    }

Dao

        @SqlQuery("select user_id, name, email from users where user_id = :id")
        fun lookupById(@Bind("id") Id: String): List<Account>?

Ps: you will need to handle binding of repository/dao with jdbi instance with guice or spring-di

0case
  • 443
  • 7
  • 13
  • I see that you use `@Transaction` in `BizLogic` (Service) layer. That's what I am looking for. Can you elaborate the above answer using two repositories, making transaction in two different tables. And assume that 2nd transaction depends on some business logic involving the result of 1st transaction. – Prince Bansal May 07 '20 at 06:59
  • You can place repository calls in the service layer method (annotated with `@Transaction`) sequentially and they will execute in order, so you can wait for the result of 1st repository call to use it in 2nd and so on. With kotlin coroutines, even if your repository methods (like in the snippets I've shared) are dispatched to different thread pools but their call site will still remain sequential. – 0case May 08 '20 at 07:37
  • > you will need to handle binding of repository/dao with jdbi instance with guice or spring-di How to handle the binding was the thing I was looking for ... :( – oligofren Jun 07 '22 at 07:46