简体   繁体   English

使用带有JDBI / IDBI / Dropwizard的事务 - 回滚问题

[英]Using Transaction with JDBI / IDBI / Dropwizard — rollback problems

I'm having a lot of trouble getting transactions to work with IDBI. 我在使用IDBI处理事务时遇到了很多麻烦。 We're using the dropwizard framework and simple inserts, updates, selects, and deletes have worked find but now we cannot seem to get the transactions to work correctly. 我们正在使用dropwizard框架,简单的插入,更新,选择和删除已找到工作,但现在我们似乎无法使事务正常工作。 Here is what I'm trying 这是我正在尝试的

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); 
   } 
}

And here is my JustinTest2 class 这是我的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;
    }
}

I've also tried implementing writeJustin like : 我也尝试过实现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;
        }
    });
}

I cannot seem to get the transaction to rollback, in each of these ways the inserted row is always there after the rollback, whether I try directly through the handle or whether I use inTransaction (which from my understanding should not commit the transaction if an exception is thrown within the call back) Anyone have any idea what I might be doing wrong? 我似乎无法让事务回滚,在每种方式中插入的行总是在回滚之后,无论我是直接尝试通过句柄还是我使用inTransaction(从我的理解不应该提交事务,如果异常在回调中被抛出)任何人都知道我可能做错了什么?

This is tangential to your question, but I'm adding it as an answer because your question is high on the Google results and there aren't a lot of examples of it out there. 这与您的问题相关,但我将其添加为答案,因为您的问题在Google搜索结果中很高,并且没有很多示例。

With JDBI v2, you can use the @Transaction annotation to simplify your code. 使用JDBI v2,您可以使用@Transaction批注来简化代码。 Just decorate the public method with the annotation and JDBI will handle the begin, commit and rollback behind the scenes. 只需使用注释修饰public方法,JDBI将在后台处理begin,commit和rollback。

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;
    }
}

Note that I made the insert and findByStyleId methods protected; 请注意,我使insertfindByStyleId方法受到保护; down from public to enforce they be done together in a transaction (in the public doStuff method); public到执行,他们在一个交易中一起完成(在公共doStuff方法中); not private because the JDBI auto-generated implementation would not be able to override them (having methods be private abstract doesn't work for that reason - you'd be forcing the compiler to accept a method without a body). 不是private因为JDBI自动生成的实现无法覆盖它们(由于这个原因,方法是private abstract不起作用 - 你要强制编译器接受没有主体的方法)。

You can also specify a TransactionIsolationLevel in the annotation to override your database's defaults. 您还可以在注释中指定TransactionIsolationLevel以覆盖数据库的默认值。

@Transaction(TransactionIsolationLevel.REPEATABLE_READ)

I figured this out. 我想通了。 It turns out the table I was testing was using MyISAM and not InnoDB as the storage engine. 事实证明我正在测试的表是使用MyISAM而不是InnoDB作为存储引擎。 MyISAM does not support transactions. MyISAM不支持交易。 I rebuilt the table using InnoDB and the code above worked fine. 我使用InnoDB重建了表,上面的代码运行正常。

For anyone who doesn't know you can see which engine a table is using by using: 对于任何不知道的人,您可以通过以下方式查看表正在使用的引擎:

show create table <tablename>;

Should see something like: 应该看到类似的东西:

CREATE TABLE `grades` (
    `id` int(11) NOT NULL,
    `percent` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM