jfinal 事务回滚bug. 400 请求出错  -问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

jfinal 事务回滚bug. 400 请求出错 

kun坤 2020-05-25 20:36:03 171

在学习和使用jfinal 框架,写了一个类TestService 想做中间层。里面有两个 model test 和test2 。 在TestService中分别new 出两个model 然后做数据库插入操作,在test 插入操作之后抛出sqlException("出错")  在类中用的是@Brfore(Tx.class)的注解。 不知为何不会回滚

代码如下:

package com.woniu157.sys.test;

import java.sql.Connection;

import com.jfinal.aop.Before;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.woniu157.sys.user.User;

public class TestService {
	@Before(Tx.class)
	public void testTran() throws Exception{
		//DbKit.setThreadLocalConnection(null);
		Test t=new Test();
		Test2 t2=new Test2();
		t2.getsomeThine();
		t.getsomeThine();
	}
	
	

}
package com.woniu157.sys.test;

import java.sql.SQLException;

import com.jfinal.plugin.activerecord.Model;

public class Test2 extends Model<Test2> {
	public static final Test2 dao=new Test2();
	
	public void getsomeThine() throws SQLException{
		dao.set("id", 1);
		dao.set("name", "zm33m");
		dao.save();
		throw new SQLException("");
	}
}
package com.woniu157.sys.test;

import com.jfinal.plugin.activerecord.Model;

public class Test extends Model<Test> {
	public static final Test dao=new Test();
	
	public void getsomeThine(){
		dao.set("id", 1);
		dao.set("name", "zmm");
		dao.save();
	}
}
分享到
取消 提交回答
全部回答(1)
  • kun坤
    2020-05-26 13:14:53

    "

        建议仔细看一下 jfinal 手册,一共才30 多页,而且大部分是代码示例。楼主碰到的问题在jfinal 手册第25页有如下说明:

    <img src=""http://static.oschina.net/uploads/space/2014/0113/181020_reqX_201137.png"" alt="""" />

    ######<div class=""ref"">

    引用来自“JFinal”的答案

        建议仔细看一下 jfinal 手册,一共才30 多页,而且大部分是代码示例。楼主碰到的问题在jfinal 手册第25页有如下说明:


    我还有个三个问题,还望赐教

    问题1 :即使我把上面保存方法换成new Model.Set(...),在最后抛出错误 ,数据库依然能够保存成功。

    @Before(Tx.class)
    public void doSomeThine(){
    
      Test t=new Test();
      t.set("id",1111);
      t.set("name","zhoumaomao");
      t.save();
      Test2 t=new Test2();
      t2.set("id",33333);
      t2.set("name","zmm");
      t2.save();
      throw new sqlException("出错啦...");
    }
    问题二:如果我改用db.tx(obj instance IAtom) 就能够原子执行,我看您的源码都是从线程中获取conn 。不知为何

    问题三:我看您的@Before(Tx.class)都写在Action 层,那这样 假设我手动抛出异常,在Action层如果手动捕捉,那Tx 就捕捉不到,如果再往上抛出,那则遇到“系统错误”请问这种情况该怎么处理?

    ######

    引用来自“zhoumaomao”的答案

    引用来自“JFinal”的答案

        建议仔细看一下 jfinal 手册,一共才30 多页,而且大部分是代码示例。楼主碰到的问题在jfinal 手册第25页有如下说明:


    我还有个三个问题,还望赐教

    问题1 :即使我把上面保存方法换成new Model.Set(...),在最后抛出错误 ,数据库依然能够保存成功。

    @Before(Tx.class)
    public void doSomeThine(){
    
      Test t=new Test();
      t.set("id",1111);
      t.set("name","zhoumaomao");
      t.save();
      Test2 t=new Test2();
      t2.set("id",33333);
      t2.set("name","zmm");
      t2.save();
      throw new sqlException("出错啦...");
    }
    问题二:如果我改用db.tx(obj instance IAtom) 就能够原子执行,我看您的源码都是从线程中获取conn 。不知为何

    问题三:我看您的@Before(Tx.class)都写在Action 层,那这样 假设我手动抛出异常,在Action层如果手动捕捉,那Tx 就捕捉不到,如果再往上抛出,那则遇到“系统错误”请问这种情况该怎么处理?

    try {
    conn = DbKit.getConnection();
    autoCommit = conn.getAutoCommit();
    DbKit.setThreadLocalConnection(conn);
    conn.setTransactionIsolation(getTransactionLevel()); // conn.setTransactionIsolation(transactionLevel);
    conn.setAutoCommit(false);
    invocation.invoke();
    conn.commit();
    } catch (Exception e) {
    if (conn != null)
    try {conn.rollback();} catch (Exception e1) {e1.printStackTrace();}
    throw new ActiveRecordException(e);

    }

    的确,事务的回滚在拦截器那边,如果action层捕获异常,则事务无法回滚了..在该怎么解决?

    ######

    引用来自“huson”的答案

    引用来自“zhoumaomao”的答案

    引用来自“JFinal”的答案

        建议仔细看一下 jfinal 手册,一共才30 多页,而且大部分是代码示例。楼主碰到的问题在jfinal 手册第25页有如下说明:


    我还有个三个问题,还望赐教

    问题1 :即使我把上面保存方法换成new Model.Set(...),在最后抛出错误 ,数据库依然能够保存成功。

    @Before(Tx.class)
    public void doSomeThine(){
    
      Test t=new Test();
      t.set("id",1111);
      t.set("name","zhoumaomao");
      t.save();
      Test2 t=new Test2();
      t2.set("id",33333);
      t2.set("name","zmm");
      t2.save();
      throw new sqlException("出错啦...");
    }
    问题二:如果我改用db.tx(obj instance IAtom) 就能够原子执行,我看您的源码都是从线程中获取conn 。不知为何

    问题三:我看您的@Before(Tx.class)都写在Action 层,那这样 假设我手动抛出异常,在Action层如果手动捕捉,那Tx 就捕捉不到,如果再往上抛出,那则遇到“系统错误”请问这种情况该怎么处理?

    try {
    conn = DbKit.getConnection();
    autoCommit = conn.getAutoCommit();
    DbKit.setThreadLocalConnection(conn);
    conn.setTransactionIsolation(getTransactionLevel()); // conn.setTransactionIsolation(transactionLevel);
    conn.setAutoCommit(false);
    invocation.invoke();
    conn.commit();
    } catch (Exception e) {
    if (conn != null)
    try {conn.rollback();} catch (Exception e1) {e1.printStackTrace();}
    throw new ActiveRecordException(e);

    }

    的确,事务的回滚在拦截器那边,如果action层捕获异常,则事务无法回滚了..在该怎么解决?

         对于 web 项目来说通常让异常抛出,跳到 500 页面即可,如果还干预更多,可以 Tx 拦截器前面再设置个拦截器在更外层捕获到异常再做后续处理。之所以是异常理应很少出现,意外出现跳去 error 500 并做了日志,已经比较合理

        另外还可以使用boolean result = Db.tx(...) 方法来得到事务是否成功的结果,也可以在外层捕获异常再继续做处理

    ######

    引用来自“zhoumaomao”的答案

    引用来自“JFinal”的答案

        建议仔细看一下 jfinal 手册,一共才30 多页,而且大部分是代码示例。楼主碰到的问题在jfinal 手册第25页有如下说明:


    我还有个三个问题,还望赐教

    问题1 :即使我把上面保存方法换成new Model.Set(...),在最后抛出错误 ,数据库依然能够保存成功。

    @Before(Tx.class)
    public void doSomeThine(){
    
      Test t=new Test();
      t.set("id",1111);
      t.set("name","zhoumaomao");
      t.save();
      Test2 t=new Test2();
      t2.set("id",33333);
      t2.set("name","zmm");
      t2.save();
      throw new sqlException("出错啦...");
    }
    问题二:如果我改用db.tx(obj instance IAtom) 就能够原子执行,我看您的源码都是从线程中获取conn 。不知为何

    问题三:我看您的@Before(Tx.class)都写在Action 层,那这样 假设我手动抛出异常,在Action层如果手动捕捉,那Tx 就捕捉不到,如果再往上抛出,那则遇到“系统错误”请问这种情况该怎么处理?

        问题一:Tx 拦截器只要捕获到异常就一定会回滚事务,检查一下数据库引是否为 innodb(对于mysql来说),myisam不支持事务

        问题二:从 ThreadLocal 中获取 conn 是为了实现事务控制,当ThreadLocal中能取到conn,证明是在事务之中,证明本线之前有数据库操作并获取过 conn,那么本线程当前的数据库操作就不必再从 DataSource中获取 conn,使用本线程已有 conn , 好让多次数据库操作使用同一个conn,从而可以实现统一 commit()

        问题三:在 Tx 拦截器再放置一个拦截器再次捕获 Tx 的往上抛出的异常。也可以用一个独立的拦截器使用 Db.tx(...) 来包裹 ai.invoke(),实现事务,并在 Db.tx(...)捕获异常

    ######不知道楼主用的是那个版本,在Tx.class里面有个NestedTransactionHelpException,可以在自己的异常处理中中catch抛出这个异常,这样可以自己处理异常并可以回滚数据。 ######

    引用来自“zeroman1212”的评论

    不知道楼主用的是那个版本,在Tx.class里面有个NestedTransactionHelpException,可以在自己的异常处理中中catch抛出这个异常,这样可以自己处理异常并可以回滚数据。
    真的吗?我用的是1.8,感觉不行呀
    0 0
云计算
使用钉钉扫一扫加入圈子
+ 订阅

时时分享云计算技术内容,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

推荐文章