【问题标题】:Using Transaction with JDBI / IDBI / Dropwizard -- rollback problems将事务与 JDBI / IDBI / Dropwizard 一起使用——回滚问题
【发布时间】:2014-01-14 17:01:33
【问题描述】:

我在使用 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;
        }
    });
}

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

【问题讨论】:

  • 老兄,我尝试使用相同的代码,它确实回滚了插入的行。

标签: java mysql transactions dropwizard jdbi


【解决方案1】:

这与您的问题无关,但我将其添加为答案,因为您的问题在 Google 搜索结果中排名靠前,并且没有很多示例。

使用 JDBI v2,您可以使用@Transaction annotation 来简化您的代码。只需用注解装饰公共方法,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;
    }
}

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

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

@Transaction(TransactionIsolationLevel.REPEATABLE_READ)

【讨论】:

  • 很好的例子,谢谢。但是,如果我想在一个事务服务调用中组合多个 DAO/存储库?
  • @Transaction 注释不适合跨多个存储库/表的事务。我在 JDBI google 组中找到了this thread,它提供了前进的方向。
【解决方案2】:

我想通了。事实证明,我正在测试的表使用 MyISAM 而不是 InnoDB 作为存储引擎。 MyISAM 不支持事务。我使用 InnoDB 重建了表,上面的代码运行良好。

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

show create table <tablename>;

应该看到类似:

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

【讨论】:

    猜你喜欢
    • 2016-03-04
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多