我是靠谱客的博主 仁爱中心,最近开发中收集的这篇文章主要介绍JFinal - 事务实现的原理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

使用声明式事务

事务类本身就是一个拦截器,可以用注解的方式配置。方法内部的所有 DML 操作都将在本次事务之内。

配置代码如下:

@Before(Tx.class)
public void savePost(){
//...
}

事务配置就是这么简单任性。

 

声明式事务实现原理

上述配置中为 savePost() 配置了事务也就是拦截器 Tx,当调用到 savePost() 的时候,是会进入到 Tx 的 intercept 方法中的:

  1. 建立数据库连接;
  2. 设置事务隔离级别;
  3. 设置事务手动提交;
  4. 反射机制调用 savePost();
  5. 事务提交;
  6. 若事务失败,就回滚。

主要代码如下:

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

}
}
}

主要事务流程:

  1. 建立数据库连接;
  2. 设置事务隔离级别;
  3. 设置事务手动提交;
  4. 调用 Atom 的 run 方法,所有 DML 操作是否都执行成功? 若都成功则事务提交,反之事务回滚。

 

转载于:https://www.cnblogs.com/xmsx/p/5844513.html

最后

以上就是仁爱中心为你收集整理的JFinal - 事务实现的原理的全部内容,希望文章能够帮你解决JFinal - 事务实现的原理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(70)

评论列表共有 0 条评论

立即
投稿
返回
顶部