关于声明式事务的问题

以下是说明文档里 声明式事务的源码:

@Before(Tx.class)
public void trans_demo() {
    // 获取转账金额
    Integer transAmount = getParaToInt("transAmount");
    // 获取转出账户id
    Integer fromAccountId = getParaToInt("fromAccountId");
    // 获取转入账户id
    Integer toAccountId = getParaToInt("toAccountId");
    // 转出操作
    Db.update("update account set cash = cash - ? where id = ?",
    transAmount, fromAccountId);
    // 转入操作
    Db.update("update account set cash = cash + ? where id = ?",
    transAmount, toAccountId);
}

以下是我的部分源码:

问题:直接用model的save和update是不是无法支持事务?我现在碰到的问题就是保存和更新的时候 ,出错后前面执行的数据都没有回滚。如果这样不行的话 ,该怎么通过model的方法去控制事务?

public class PayController extends Controller {
    PayService payService = Enhancer.enhance(PayService.class,Tx.class);
    public void addPay() {
		Pay pay = getModel(Pay.class, "pay");
		pay.setIndate(new Date());
		boolean flag = payService.savePay(pay);
		if (flag)
		    payManage();
	}
}
public class PayService {
	// 分发资金
	@Before(Tx.class)
	public boolean savePay(Pay pay) {
	boolean flag = false;
	try {
	    if (pay == null) {
		return flag;
	    }
	    flag = pay.save();
	    if (flag) {
	        // 更新预约状态为已缴费
	        Appoint appoint = Appoint.dao.findById(pay.getAid());
    	        appoint.setStatus(2);// 已缴费
    	        flag = appoint.update();
    	    }
	    // 生成一级机构资金记录
	    Integer agid = pay.getAgid();
	    if (flag && agid != null) {
		Assetsin assetsin = new Assetsin();
		// 查询机构详细信息
		Agency agency = Agency.dao.findById(agid);
		if (agency != null) {
		    // 机构id
		    assetsin.setAid(agid);
		    // 预约id
		    assetsin.setApptid(pay.getAid());
		    // 机构名称
		    assetsin.setAname(pay.getAgname());
		    // 机构编号
		    assetsin.setAcode(pay.getAcode());
		    // 客户id
		    assetsin.setCid(pay.getCid());
		    // 客户姓名
		    assetsin.setCname(pay.getCname());
		    // 发放标识 默认未发放
		    assetsin.setFlag(false);
		    // 资金总额
		    Double sum = pay.getSum();
		    assetsin.setSum(sum);
		    // 查询
		    List<Rate> rateList = Rate.dao.find("select rate,level from rate");
		    double rate1 = 0D;
		    double rate2 = 0D;
		    for (Rate rate : rateList) {
			if (rate.getLevel() == 1)
				rate1 = rate.getRate();
			if (rate.getLevel() == 2)
				rate2 = rate.getRate();
		    }
		// 比例
		assetsin.setRate(rate1);
		Double amount = sum * rate1 / 100;
		assetsin.setAmount(amount);
		flag = assetsin.save();
		if (flag) {
		// 给上级机构记录资金明细
			Integer parentid = agency.getParentid();
			if (parentid != null) {
				agency = Agency.dao.findById(parentid);
			if (agency != null) {
				assetsin.setId(null);
				assetsin.setAid(parentid);
				assetsin.setAname(agency.getName());
				assetsin.setAcode(agency.getCode());
				assetsin.setRate(rate2);
				amount = sum * rate2 / 100;
				assetsin.setAmount(amount);
				flag = assetsin.save();
			}
		}
	}
}
}
	return flag;
} catch (Exception e) {
	e.printStackTrace();
}
return flag;
}
}


新人学习jfinal中,希望大神不吝赐教,在此感谢!

最后感谢詹总提供这么好的框架和平台!

评论区

JFinal

2017-03-21 21:51

使用拦截器支持事务时,不要将内部的异常吃掉,所以 try catch 中需要将异常再次抛出来,这个可能是在你的代码中没有支持事务的根本原因

此外,还要注意 mysql 只有 innodb 引擎才支持事务,myisam 天然不支持事务,还要注意事务级别是否匹配当前的数据库操作,如果是 jfinal 3.0 版本,默认级别比较高,一般不需要调整

最后,上面的代码中,既然 savePay 中已经使用了 @Before 声明了事务,那么在 enhance 时就不需要添加 Tx.class 这个参数了

最后的最后,个人一般建议直接使用 Db.tx(...) 的方式支持事务,控制起来更加方便,例如,可以 try catch,然后在 catch 中 return false 就可以控制事务回滚了,然后通过得到 Db.tx(...) 方法的返回值再控制对上层响应什么返回值会更方便

zhongshg

2017-03-22 09:21

首先谢谢大神的解答! 我发现了两个错误,第一个错误是其中一个表的引擎是myisam,第二个错误是try-catch,经过测试,这两个都会导致事务统一,修改这两个错误后
主动添加异常测试:
if (flag) {
throw new IllegalArgumentException("autoCreate Exception success!");
}
已经回滚正常。再次感谢!

zhongshg

2017-03-22 09:37

Db.tx(...) 我会再使用,现在还在慢慢了解jfinal框架中

JFinal

2017-03-22 12:10

@zhongshg 还好我的回复比较详细,要不然只发现部分原因,仍然无法解决,多多支持社区发展

zhongshg

2017-03-22 17:04

@JFinal 我看加入俱乐部年费是199,现在加入是不是到下年这个时间到期?

JFinal

2017-03-22 17:49

@zhongshg 对的,按年订阅

热门反馈

扫码入社