Java 将事务与JDBI/IDBI/Dropwizard一起使用--回滚问题

Java 将事务与JDBI/IDBI/Dropwizard一起使用--回滚问题,java,mysql,transactions,dropwizard,jdbi,Java,Mysql,Transactions,Dropwizard,Jdbi,我很难让事务与IDBI一起工作。我们正在使用dropwizard框架,简单的插入、更新、选择和删除都可以找到,但现在我们似乎无法让事务正常工作。这就是我正在尝试的 public class JDb { private JustinTest2 jTest2 = null; private Handle dbHandle = null; public JDb(final IDBI idbi) { try { dbHandle = id

我很难让事务与IDBI一起工作。我们正在使用dropwizard框架,简单的插入、更新、选择和删除都可以找到,但现在我们似乎无法让事务正常工作。这就是我正在尝试的

public class JDb {
    private JustinTest2 jTest2 = null;
    private Handle dbHandle = null;

    public JDb(final IDBI idbi) {
        try {
            dbHandle = idbi.open();
            dbHandle.getConnection().setAutoCommit(false);
            jTest2 = dbHandle.attach(JustinTest2.class);
        } catch( SQLException e ) {

        }
    }

   public void writeJustin(final int styleId, final int eventId) {
        dbHandle.begin();
        int num = jTest2.findByStyleId(styleId);

        try {
            jTest2.doStuff(styleId, eventId);
            dbHandle.commit();
        } catch(Exception e) {
            dbHandle.rollback(); // Never rolls back here, always get the inserted row!
        }

        num = jTest2.findByStyleId(styleId); 
   } 
}
这是我的JustinTest2课程

public abstract class JustinTest2 {

    @SqlUpdate("INSERT INTO jTest2 (styleId, jNum) VALUES (:styleId, :jNum)")
    public abstract void insert(@Bind("styleId") int styleId, @Bind("jNum") int jNum);

    @SqlQuery("SELECT count(styleId) " +
            "FROM jTest2 " +
            "WHERE styleId=:styleId")
    public abstract int findByStyleId(@Bind("styleId") int styleId);


    public int doStuff(int styleId, int eventId) throws Exception{
        int count = findByStyleId(styleId);

        insert(styleId, eventId);

        count = findByStyleId(styleId);

        if(count==1) {
            throw new Exception("Roll back");
        }

        return count;
    }
}
我还尝试过实现writeJustin,如:

public void writeJustin(final int styleId, final int eventId) throws Exception {
    int rows_updated = jTest2.inTransaction(new Transaction<Integer, JustinTest2>() {
        @Override
        public Integer inTransaction(JustinTest2 transactional, TransactionStatus status) throws Exception {

            jTest2.insert(styleId, eventId);
            int num = transactional.findByStyleId(styleId);

            try {
                if(num == 1) throw new Exception("BOOM");    
            } catch (Exception e) {
                transactional.rollback();
                throw e;
            }

            num = transactional.findByStyleId(styleId);
            return num;
        }
    });
}
public void writeJustin(final int styleId,final int eventId)引发异常{
int rows_updated=jTest2.inTransaction(新事务(){
@凌驾
公共整数内部事务(JustinTest2事务性,TransactionStatus状态)引发异常{
jTest2.insert(styleId,eventId);
int num=transactional.findByStyleId(styleId);
试一试{
如果(num==1)抛出新异常(“BOOM”);
}捕获(例外e){
transactional.rollback();
投掷e;
}
num=transactional.findByStyleId(styleId);
返回num;
}
});
}

我似乎无法让事务回滚,在这些方式中,插入的行总是在回滚后出现,无论我是直接尝试通过句柄还是使用内部事务(据我所知,如果在回调中引发异常,则不应提交事务)有人知道我可能做错了什么吗

我知道了。原来我测试的表使用的是MyISAM,而不是InnoDB作为存储引擎。MyISAM不支持事务。我使用InnoDB重建了表,上面的代码运行良好

对于任何不知道的人,您可以通过以下方式查看表正在使用的引擎:

show create table <tablename>;

这与你的问题无关,但我把它作为一个答案添加进来,因为你的问题在谷歌搜索结果中排名靠前,而且没有太多的例子

使用JDBIV2,您可以使用简化代码。只需用注释装饰公共方法,JDBI将在幕后处理开始、提交和回滚

public abstract class JustinTest2 {

    @SqlUpdate("INSERT INTO jTest2 (styleId, jNum) VALUES (:styleId, :jNum)")
    protected abstract void insert(@Bind("styleId") int styleId, @Bind("jNum") int jNum);

    @SqlQuery("SELECT count(styleId) " +
            "FROM jTest2 " +
            "WHERE styleId=:styleId")
    protected abstract int findByStyleId(@Bind("styleId") int styleId);

    @Transaction
    public int doStuff(int styleId, int eventId) throws Exception{
        int count = findByStyleId(styleId);

        insert(styleId, eventId);

        count = findByStyleId(styleId);

        if(count==1) {
            throw new Exception("Roll back");
        }

        return count;
    }
}
注意,我使
insert
findByStyleId
方法受到保护;从
public
向下,强制它们在一个事务中一起完成(在public
doStuff
方法中);不是
private
,因为JDBI自动生成的实现将无法覆盖它们(因此,将方法设置为
private abstract
不起作用-您将强制编译器接受没有主体的方法)

您还可以在注释中指定一个值来覆盖数据库的默认值

@Transaction(TransactionIsolationLevel.REPEATABLE_READ)

伙计,我用同样的代码试过了,它确实回滚了插入的行。很好的例子,谢谢。但是如果我想在一个事务服务调用中组合多个DAO/存储库,那么
@Transaction
注释不适合跨多个存储库/表的事务。我在JDBI上发现了一个google组,它提供了一条前进的道路。
@Transaction(TransactionIsolationLevel.REPEATABLE_READ)