jfinal事务传播

天为之殇 发布于 2015/06/16 15:20
阅读 452
收藏 1

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

在Controller里的方法A上加了

@Before(Tx.class)
public void A(){
    Db.use("DBNAME").update(...);
    new Helper().save();
    ...
}


public class Helper{
    public boolean save(){
        return Db.use("DBNAME").update(...) > 0;
    }
 }

怎么让这两个update用同一个事务?

加载中
0
铂金蛋蛋
铂金蛋蛋

我用的这种方式

DB.tx(new IAtom(){.....})

IAtom中的run方法返回boolean类型,通过这个来决定提交还是回滚.比较灵活

例:

private void addSystemAttachmentFile(final Uploader up) throws Exception {
        /**
         * 上传失败不记录
         * 如果出现文件上传,但是数据库中无记录,则视为脏数据。
         */
        if(!up.getState().equals("SUCCESS")) return ;
        final String path=up.getUrl().substring(0,up.getUrl().lastIndexOf("/")+1);
        /**
         * 声明事务
         * 因两步数据库操作存在嵌套,所以不能使用 @Before(Tx.class) 这种方式
         */
        boolean tx = Db.tx(new IAtom() {
            @Override
            public boolean run() throws SQLException {
                SystemAttachmentFile saf = new SystemAttachmentFile();
                saf.set("srctype", "umedior-tips");  //上传源
                saf.set("path", path);               //路径 upload/20140824/ 不含文件名
                saf.set("filename", up.getFileName().replaceAll("\\..*", "")); //文件名 11181408870800858
                saf.set("suffix", up.getType());     //后缀 .jpg
                saf.set("filelength", up.getSize()); //
                saf.set("mimetype", ContentTypeKit.get(up.getType().replace(".", "")));
                saf.set(SystemAttachmentFile.COL_LIVEFLAG, 1);
//                saf.set("createtime", DateTimeKit.getDate());
                boolean status = saf.save();

                String cookie = "";
                String useruuid = "";
                boolean status2 = false;
                if (status) {
                    cookie = getCookie(CookiesKit.COOKIES_AUTHMARK);//获取cookies
                    useruuid = CookiesKit.getSystemUserUUID(cookie);//获取用户的uuid
                    try {
                        SystemUser.dao.addAttachmentFiles(useruuid, saf.getUUID());
                        status2 = true;
                    } catch (Exception e) {
                        e.printStackTrace();
                        logger.error("useruuid:" + useruuid + "||cookie:" + saf.getUUID(), e);
                        status2 = false;
                    }
                }
                //如果保存成功,则将文件保存到真实文件目录
                if(status && status2){
                    try {
                        //此处用url而不是filename是因为
                        //url规则以生成upload/20140824/84791408810118438.jpg
                        //用这种方式直接copy
                        FileKit.moveTmpToReal(up.getUrl());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                return status && status2;
            }
        });

    }

Jfinal中相关关键代码DbPro.java - line:637

Boolean autoCommit = null;
		try {
			conn = config.getConnection();
			autoCommit = conn.getAutoCommit();
			config.setThreadLocalConnection(conn);
			conn.setTransactionIsolation(transactionLevel);
			conn.setAutoCommit(false);
			boolean result = atom.run();
			if (result)
				conn.commit();
			else
				conn.rollback();
			return result;
		} catch (NestedTransactionHelpException e) {
			if (conn != null) try {conn.rollback();} catch (Exception e1) {e1.printStackTrace();}
			return false;
		} catch (Throwable t) {
			if (conn != null) try {conn.rollback();} catch (Exception e1) {e1.printStackTrace();}
			throw t instanceof RuntimeException ? (RuntimeException)t : new ActiveRecordException(t);
		} finally {
			try {
				if (conn != null) {
					if (autoCommit != null)
						conn.setAutoCommit(autoCommit);
					conn.close();
				}
			} catch (Throwable t) {
				t.printStackTrace();	// can not throw exception here, otherwise the more important exception in previous catch block can not be thrown
			} finally {
				config.removeThreadLocalConnection();	// prevent memory leak
			}
		}



铂金蛋蛋
铂金蛋蛋
这种方式虽然麻烦一些,但是比较灵活,可以根据业务需要来定
天为之殇
天为之殇
只能这样手动写事务嵌套,判断了。
天为之殇
天为之殇
用 声明式的事务 可以传播进调用的函数里么?我试试~
0
JFinal
JFinal

在 jfinal 中事务传播只有两个规则:

1:某个方法使用了事务拦截器,那么此方法内部再操作数据库也具有同样的事务级别,事务会自动传播到后续被调用的方法中

2:假如内层方法重新开启了事务,如果事务级别比外层高,那么外层事务级别会一并提升,如果比外层低那么会提升至外层事务相同级别,这样就保障了事务级别的安全性

JFinal
JFinal
回复 @Mr.CT : 可配置ActiveRecordPlugin 的默认事务级别,也可以在做事务的时候用参数临时指定。
AntMaster
AntMaster
那样,如何定义事务级别呢?
0
slliver
slliver
这个不错
返回顶部
顶部