关于jfinal事物的问题

詹总,你好,我用jfinal做的我们单位的一个项目运行了很久了,现在想问你连个问题:

    我这个项目有个后台对账服务,是用定时任务运行的,因为过程比较多用到了事物,并且我需要在子程序报错的时候把报错的业务信息抛出去,可以捕获异常的信息(这个事务中那个业务步骤报错,报的什么错误信息),jfinal本身的事务Db.tx的方式方便是方便,但是只能单纯的回退事务但是不能向上抛出异常的信息。这个现在最新的3.6有可行的解决方式吗。

我目前采用的方式是找的网上一个人解决方式:

public static void beginTran() {
        try {
            log.info("~~~~~~~~~~~~开启事务~~~~~~~~~~~~");
            DbKit.getConfig().setThreadLocalConnection(DbKit.getConfig().getConnection());
            DbKit.getConfig().getThreadLocalConnection().setAutoCommit(false);
        } catch (Exception e) {
            throw (new RuntimeException(e));
        }
    }
    
public static void commit() throws RuntimeException{
        try {
            log.info("~~~~~~~~~~~~结束事务:提交~~~~~~~~~~~~");
            DbKit.getConfig().getThreadLocalConnection().commit();
            DbKit.getConfig().getThreadLocalConnection().setAutoCommit(true);
            DbKit.getConfig().close(DbKit.getConfig().getThreadLocalConnection());
            DbKit.getConfig().setThreadLocalConnection(null);
        } catch (Exception e) {
            throw (new RuntimeException(e));
        }
    }
    
    public static void rollback(){
        try {
            log.info("~~~~~~~~~~~~结束事务:回滚~~~~~~~~~~~~");
            DbKit.getConfig().getThreadLocalConnection().rollback();
            DbKit.getConfig().getThreadLocalConnection().setAutoCommit(true);
            DbKit.getConfig().close(DbKit.getConfig().getThreadLocalConnection());
            DbKit.getConfig().setThreadLocalConnection(null);
 
        } catch (Exception e) {
            throw (new RuntimeException(e));
        }
    }


调用的时候

        try{
            JFinalTX.beginTran();
            cmerBatch=service.getSettleData(cmerBatch);
            checkChnlSettle(cmerBatch);
            JFinalTX.commit();
        }catch (BusiException e) {
            log.error("[{}][{}]对账发生错误",cmer.getCmerId(),cmerBatch.getBatchDate());
            JFinalTX.rollback();
            cmerBatch.setSttlAbs(e.getErrMsg());
            cmerBatch.setSttlStatus(CmerSttlStatus.错误.getCode());
            cmerBatch.setSttlDatetime(CMB.getCurrentDateTimeFull());
            e.printStackTrace();
            throw e;
        }catch (Exception e) {
            JFinalTX.rollback();
            log.error("[{}][{}]对账发生错误",cmer.getCmerId(),cmerBatch.getBatchDate());
            e.printStackTrace();
            cmerBatch.setSttlAbs(e.getMessage());
            cmerBatch.setSttlStatus(CmerSttlStatus.错误.getCode());
            cmerBatch.setSttlDatetime(CMB.getCurrentDateTimeFull());
            
            throw new BusiException(e.getMessage());
        }finally{
            cmerBatch.update();
        }

这种方式 开发测试时挺好用的,但是实际运营中经常出现卡死的现象,就是日志显示运行在代码开始的地方,然后就不动了,然后定时任务一次一次的触发,都卡到任务开始的地方 了,重启tomcat立马就好了。

是在找不到是什么原因,感觉是和数据库连接池有关,用的阿里的Druid,因为是对账,把批量插入放在了事务里,但数量级不多几k而已,好像和异常有关,出现异常后会更容易出现卡死现象。


评论区

JFinal

2019-03-07 13:49

你们的代码有很多问题,例如 commit() 和 rollback() 中在抛出那常的时候并没有关闭数据库连接,这样就会造成连接无法回收,慢慢连接会耗尽而项目挂掉

其实 Db.tx 已经很好支持你们的用法,Db.tx 本身就是先回滚事务,然后该抛什么异常就抛什么异常:
try {
Db.tx( () -> {
这里是业务代码
});
} catch (Exception e1) {
Exception e2 = e.getCause(); // 得到更内部的异常
}