概述
使用声明式事务
事务类本身就是一个拦截器,可以用注解的方式配置。方法内部的所有 DML 操作都将在本次事务之内。
配置代码如下:
@Before(Tx.class) public void savePost(){ //... }
事务配置就是这么简单任性。
声明式事务实现原理
上述配置中为 savePost() 配置了事务也就是拦截器 Tx,当调用到 savePost() 的时候,是会进入到 Tx 的 intercept 方法中的:
- 建立数据库连接;
- 设置事务隔离级别;
- 设置事务手动提交;
- 反射机制调用 savePost();
- 事务提交;
- 若事务失败,就回滚。
主要代码如下:
public void intercept(Invocation inv) { Config config = getConfigWithTxConfig(inv); if (config == null) config = DbKit.getConfig(); Connection conn = config.getThreadLocalConnection(); // 下面这段支持嵌套事务,可以忽略不看 if (conn != null) { try { if (conn.getTransactionIsolation() < getTransactionLevel(config)) conn.setTransactionIsolation(getTransactionLevel(config)); inv.invoke(); return ; } catch (SQLException e) { throw new ActiveRecordException(e); } } Boolean autoCommit = null; try { // 1. 建立数据库连接 conn = config.getConnection(); autoCommit = conn.getAutoCommit(); config.setThreadLocalConnection(conn); // 2. 设置事务隔离级别 conn.setTransactionIsolation(getTransactionLevel(config)); // conn.setTransactionIsolation(transactionLevel); // 3. 设置事务手动提交 conn.setAutoCommit(false); // 4. 反射机制调用 savePost() inv.invoke(); // 5. 事务提交 conn.commit(); } catch (NestedTransactionHelpException e) { if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);} LogKit.logNothing(e); } catch (Throwable t) { // 6. 若有异常就回滚 if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);} 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) { LogKit.error(t.getMessage(), t); // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown } finally { config.removeThreadLocalConnection(); // prevent memory leak } } }
事务隔离级别
Tx.java 使用的是 JFinal 默认配置的事务隔离级别,是在 DbKit.java 中配置的
public static final int DEFAULT_TRANSACTION_LEVEL = Connection.TRANSACTION_REPEATABLE_READ;
JFinal 还有几个拦截器,可以根据事务隔离级别的需求选用。
它们都继承与 Tx.java,唯一不同的就是事务隔离级别。
以 TxReadCommitted 为例。
继承 Tx.java,覆盖了 getTransactionLevel 方法,返回常量值,这个常量就代表了事务隔离级别。
public class TxReadCommitted extends Tx { /** * A constant indicating that * dirty reads are prevented; non-repeatable reads and phantom * reads can occur. This level only prohibits a transaction * from reading a row with uncommitted changes in it. */ private int TRANSACTION_READ_COMMITTED = 2; @Override protected int getTransactionLevel(com.jfinal.plugin.activerecord.Config config) { return TRANSACTION_READ_COMMITTED; } }
另一种实现事务的方式
这种实现方式并没有使用拦截器。
跟踪代码最终追到 DbPro.java 如下代码中:
boolean tx(Config config, int transactionLevel, IAtom atom) { Connection conn = config.getThreadLocalConnection(); if (conn != null) { // Nested transaction support try { if (conn.getTransactionIsolation() < transactionLevel) conn.setTransactionIsolation(transactionLevel); boolean result = atom.run(); if (result) return true; throw new NestedTransactionHelpException("Notice the outer transaction that the nested transaction return false"); // important:can not return false } catch (SQLException e) { throw new ActiveRecordException(e); } } Boolean autoCommit = null; try { // 1. 建立数据库连接 conn = config.getConnection(); autoCommit = conn.getAutoCommit(); config.setThreadLocalConnection(conn); // 2. 设置事务隔离级别 conn.setTransactionIsolation(transactionLevel); // 3. 设置事务手动提交 conn.setAutoCommit(false); // 4. 所有 DML 操作是否都执行成功? boolean result = atom.run(); // 5. 都成功:提交;不是都成功:回滚 if (result) conn.commit(); else conn.rollback(); return result; } catch (NestedTransactionHelpException e) { if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);} LogKit.logNothing(e); return false; } catch (Throwable t) { if (conn != null) try {conn.rollback();} catch (Exception e1) {LogKit.error(e1.getMessage(), e1);} 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) { LogKit.error(t.getMessage(), t); // can not throw exception here, otherwise the more important exception in previous catch block can not be thrown } finally { config.removeThreadLocalConnection(); // prevent memory leak } } }
主要事务流程:
- 建立数据库连接;
- 设置事务隔离级别;
- 设置事务手动提交;
- 调用 Atom 的 run 方法,所有 DML 操作是否都执行成功? 若都成功则事务提交,反之事务回滚。
转载于:https://www.cnblogs.com/xmsx/p/5844513.html
最后
以上就是仁爱中心为你收集整理的JFinal - 事务实现的原理的全部内容,希望文章能够帮你解决JFinal - 事务实现的原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复