关于Db.tx事务问题

vekygg 发布于 2013/12/19 10:34
阅读 1K+
收藏 0

@JFinal 你好,想跟你请教个问题:

例如我现在有50个订单要批量审批,循环过程中程序有异常的回滚,没有问题的继续执行,请问怎么处理?我尝试过如下代码,发现总是提示错误,不知道是不是我哪里写的有问题,请指教下!

1、public class Order_Head extends Model<Order_Head>{......}

2、以下在Db.tx里面调用head.save()提示错误

for(int i =0;i < 50;i++){    

    try{

        Order_Head head = new Order_Head();
        head.set("order_id","sq_order_head.nextval");
        .....
        Db.tx(new IAtom() {     
            public boolean run() throws SQLException {
               boolean b = head.save();
               return b;
            }
        });

    }catch(Exception e){

    }

}

加载中
0
JFinal
JFinal
提示什么错误呢? 是 sq_order_head 这个序列没有创建?
0
vekygg
vekygg

提示错误如图:

 

0
JFinal
JFinal

引用来自“vekygg”的答案

提示错误如图:

 

给出两种写法:

1:添加 final 关键字

final Order_Head head = new Order_Head();
head.set("order_id","sq_order_head.nextval");
.....
Db.tx(new IAtom() {     
  public boolean run() throws SQLException {
    boolean b = head.save();
    return b;
  }
});



2:将对象创建移入 run 方法

.....
Db.tx(new IAtom() {     
  public boolean run() throws SQLException {
    Order_Head head = new Order_Head();
    head.set("order_id","sq_order_head.nextval");
    boolean b = head.save();
    return b;
  }
});

0
vekygg
vekygg

引用来自“JFinal”的答案

引用来自“vekygg”的答案

提示错误如图:

 

给出两种写法:

1:添加 final 关键字

final Order_Head head = new Order_Head();
head.set("order_id","sq_order_head.nextval");
.....
Db.tx(new IAtom() {     
  public boolean run() throws SQLException {
    boolean b = head.save();
    return b;
  }
});



2:将对象创建移入 run 方法

.....
Db.tx(new IAtom() {     
  public boolean run() throws SQLException {
    Order_Head head = new Order_Head();
    head.set("order_id","sq_order_head.nextval");
    boolean b = head.save();
    return b;
  }
});

其实我的意图是:例如有50个订单要批量审批,那么程序就会循环50次,每次循环都有相同的逻辑判断和修改表(修改多个表)的动作,那么我想要的是,这50个订单中假如循环到第40个的时候出现异常,那么只许回滚第40个订单的相关修改,之前的1~39个订单不许回滚并且41、42、43......继续循环审批。如果我把循环放到Db.tx里面,如:

Db.tx(new IAtom() {    
      public boolean run() throws SQLException {
      for(int i=0;i< 50;i++){
          ....//一系列判断
          table1 t1 = new table1();
            head.set("table1_id","sq_order_head.nextval");
          ...//其他字段
            boolean a = t1.save();
          ...//一系列判断
          table2 t2 = new table2();
            head.set("table2_id","sq_order_head.nextval");
          ...//其他字段
            boolean b = t2.save();
          ...//一系列判断
          table3 t3 = new table3();
            head.set("table3_id","sq_order_head.nextval");
          ...//其他字段
            boolean c = t3.save();                              
            return a&&b&&c;
      }
        
      }
}); 程序将回滚所有(1~50个订单都回滚)的审批,那么这样就达不到我要的效果;如果我把Db.tx放到循环里面,那么所有传入Db.tx的变量都要定义成final类型包括循环变量for(final int i=0;i<50; i++ ),红色部分会提示错误,例如:

public void myAudit(JSONObject jsonObj){
    //前台传过来要批量审批的订单ID
    JSONArray jsonArray = jsonObj.getJSONArray("order_head_ids");
    for (final int i = 0; i < jsonArray.size(); i++) {
      try{           
        Db.tx(new IAtom() {    
              public boolean run() throws SQLException {
                  //关键是这里,无奈这里取Db.tx外面的变量都要加final才能读取,包括循环变量i,如果定义成final类型,还能改变他们的值吗
                  int id = (Integer) jsonArray.get(i);
                  ....//一系列判断
                  table1 t1 = new table1();
                  head.set("table1_id","sq_order_head.nextval");
                  ...//其他字段
                  boolean a = t1.save();
                  ...//一系列判断
                  table2 t2 = new table2();
                  head.set("table2_id","sq_order_head.nextval");
                  ...//其他字段
                  boolean b = t2.save();
                  ...//一系列判断
                  table3 t3 = new table3();
                  head.set("table3_id","sq_order_head.nextval");
                  ...//其他字段
                  boolean c = t3.save();                              
                  return a&&b&&c;
              }
        });
       }catch(Exception e){
       
       }        
    }

}


0
JFinal
JFinal

先封装一个方法,在一个事务中专门处理一个审批操作,然后在外部用 for 循环调用这个审批方法,结构大至如下:

public void action() {
  for (int i=0; i<n; i++) {
    try {
      doit(...);
    }
    catch (Exception e) {
      System.out.println("审批出现异常,但仍然继续审批");
    }
  }
}

public void doit(...) {
  Db.tx(new IAtom() {
    public void run() throws SQLException {
      ......
    });
}



0
vekygg
vekygg

引用来自“JFinal”的答案

先封装一个方法,在一个事务中专门处理一个审批操作,然后在外部用 for 循环调用这个审批方法,结构大至如下:

public void action() {
  for (int i=0; i<n; i++) {
    try {
      doit(...);
    }
    catch (Exception e) {
      System.out.println("审批出现异常,但仍然继续审批");
    }
  }
}

public void doit(...) {
  Db.tx(new IAtom() {
    public void run() throws SQLException {
      ......
    });
}



按照这样做的话,封装方法传参数也是个麻烦事,参数要求final类型。

我现在的做法是这样:

public void action(...) {
  for (int i = 0; i < jsonArray.size(); i++) {
    if (DbKit.getThreadLocalConnection() != null)
        throw new ActiveRecordException("Nested .");
    Connection conn = null;
    try {
         // 事务
           conn = DbKit.getDataSource().getConnection();
	DbKit.setThreadLocalConnection(conn);
	conn.setTransactionIsolation(8);
	// 关键就是把自动提交变成false(即手动提交)
	conn.setAutoCommit(false);

	int id = (Integer) jsonArray.get(i);
	// ....//一系列判断
	table1 t1 = new table1();
	t1.set("table1_id", "sq_order_head.nextval");
	// ...//其他字段
	t1.save();
	// ...//一系列判断
	table2 t2 = new table2();
	t2.set("table2_id", "sq_order_head.nextval");
	// ...//其他字段
	t2.save();
	// ...//一系列判断
	table3 t3 = new table3();
	t3.set("table3_id", "sq_order_head.nextval");
	// ...//其他字段
	t3.save();

	// 提交
	conn.commit();
    } catch (Exception e) {
         e.printStackTrace();
	if (conn != null)
	try {
	    conn.rollback();
	} catch (SQLException e1) {	e1.printStackTrace();
	}
    } finally {
	try {
	    if (conn != null) {						conn.setAutoCommit(true);// 然后还原自动提交状态
		conn.close();
	     }
	} catch (Exception e) {
	     e.printStackTrace();
	} finally {
	     DbKit.removeThreadLocalConnection();
	}
    }
  }
}

波总,有没有必要把这个事务的打开、提交、回滚、释放写到Model里面并提供相应的方法,供我们开发时方便调用,例如:

public void action(...) {
  for (int i = 0; i < jsonArray.size(); i++) {
    try {
         // 事务打开
	this.openTransaction();

	int id = (Integer) jsonArray.get(i);
	// ....//一系列判断
	table1 t1 = new table1();
	t1.set("table1_id", "sq_order_head.nextval");
	// ...//其他字段
	t1.save();
	// ...//一系列判断
	table2 t2 = new table2();
	t2.set("table2_id", "sq_order_head.nextval");
	// ...//其他字段
	t2.save();
	// ...//一系列判断
	table3 t3 = new table3();
	t3.set("table3_id", "sq_order_head.nextval");
	// ...//其他字段
	t3.save();

	// 提交
	this.commit();
    } catch (Exception e) {
         e.printStackTrace();
	this.rollback();
    } finally {
	this.closeTransaction();
    }
  }
}


JFinal
JFinal
这样就违备了JFinal设计原则之一:避免问题而非解决问题。开发者如果在整个过程中出现失误,如忘了closeTransaction() 就会引发问题
返回顶部
顶部