12

I hava two jdbi dao like these:

public interface dao1 {
  @Query("insert into table1 ...")
  findByid(myBean1);
}

public interface dao2 {
  @Query("insert into table2 ...)
  save(myBean2;
  }
}

i want to execute save of two dao in one transaction like:

dao1.save();
dao2.save();

With spring i have used @transactional annotation. What can i do with dropwizard and jdbi ?

LucaA
  • 603
  • 2
  • 7
  • 18

5 Answers5

12

You can use @Transaction in JDBI. I have blogged about it here. http://manikandan-k.github.io/2015/05/10/Transactions_in_jdbi.html

Manikandan
  • 2,655
  • 2
  • 16
  • 26
  • Hi, thanks this is what i need, but how can i test the class that implements GetHandle interface? Or if a need to use different repository object in the same transaction? – LucaA Dec 03 '15 at 11:55
  • We can't use two different repository in same transaction. If you want use two different Dao's create a repository containing those two Daos. For testing the class, What is the difficulty you are facing ? – Manikandan Dec 03 '15 at 12:00
  • we can't mock daos in repository 's unit test, because they are injected by jdbi @SqlCreateObject annotation and jdbi.onDemand method. It's true? – LucaA Dec 03 '15 at 13:50
  • Since repository is abstract class, you need to have a implementation when writing unit test. When you give implementation you can inject mocks for abstract methods – Manikandan Dec 03 '15 at 13:57
  • Hi @Manikandan, I went through your blog and tried to save the transaction using Repository class but no luck. This is my run method : – Santosh Mohanty Dec 07 '16 at 10:56
  • `public void run(ServiceConfiguration configuration, Environment environment) throws Exception { final DBIFactory factory = new DBIFactory(); final DBI jdbi = factory.build(environment, configuration.dataBase(), "mysql"); final AppsMessageDao appsMessageDao = jdbi.onDemand(AppsMessageDao.class); final MessageDao messageDao = jdbi.onDemand(MessageDao.class); }` When I use the repository Class , I get error connection already closed . – Santosh Mohanty Dec 07 '16 at 11:06
  • 1
    I am quite surprised why such this important information is not a part of official document form JDBI. – Surasin Tancharoen Jun 12 '17 at 11:55
  • This doesn't seem to work for me. The first method always goes through (no-rollbacks) whenever the next/last method throws exceptions. I was hoping `@Transaction` annotation would solve that. – TheRealChx101 Nov 17 '18 at 00:40
2

The SQL Object API Overview shows the possibility to bind two instances to the same handle. This way you can both save() calls as part of the same transaction:

// TODO: add try/catch/finally to close things properly
DBI dbi = new DBI("jdbc:h2:mem:test");
Handle h = dbi.open();
h.begin();
Dao1 dao1 = h.attach(Dao1.class);
Dao2 dao2 = h.attach(Dao2.class);
dao1.save(myBean1);
dao2.save(myBean2);
h.commit();
h.close();

If you use onDemand instead of open and hesitate to get try/catch right, you might want to consider something like this:

// add some more interfaces
public interface Dao1 extends GetHandle, Transactional<Dao1> {
   @Query("insert into table1 ...")
   save(myBean1);
}

DBI dbi = new DBI("jdbc:h2:mem:test");
Dao1 dao1 = dbi.onDemand(Dao1.class);

// no try/catch necessary here
dao1.inTransaction(transactional, status) -> {
    transactional.save(myBean1);
    transactional.withHandle((h) -> h.attach(Dao2.class)
       .save(myBean2));
    return null; // return is enforced by the interface
});

Please double-check the functionality with a unit test.

Jonathan
  • 18,696
  • 6
  • 62
  • 66
ahus1
  • 5,249
  • 22
  • 39
0

As per the jdbi docs,

Update, insert, and data definition statements are indicated in the SQL Object API via the @SqlUpdate annotation. The methods for these statements must have either void or int return types. If the return type is int, the the value will be the number of rows changed.

Annotate with @SqlUpdate. Here's a sample usage using h2 as the DB.

DBI dbi = new DBI("jdbc:h2:mem:test");
Handle h = dbi.open();
Dao1 dao1 = h.attach(Dao1.class);
dao1.save(myBean1);

Reference: http://jdbi.org/jdbi2/sql_object_api_dml

Jonathan
  • 18,696
  • 6
  • 62
  • 66
dkulkarni
  • 2,585
  • 4
  • 24
  • 36
0

You can use transaction callback on DBI:

dbi.useTransaction((handle, transactionStatus) -> {
    Dao1 dao1 = handle.attach(Dao1.class);
    Dao2 dao2 = handle.attach(Dao2.class);
    dao1.save();
    dao2.save();
});

Assuming you're using JDBI v2.x

Slava Medvediev
  • 994
  • 9
  • 27
-5

Use @UnitOfWork

Example:

@POST
@UnitOfWork
public Role create(@Valid RoleApi roleApi) {
    return roleService.create(roleApi);
}