MyBatis transactionManager 事务管理
1、MyBatis事务配置
在MyBatis的配置文件中可以配置事务管理方式如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
<environment id="development">
<!--配置事务的管理方式-->
<transactionManager type="JDBC" />
<!-- 配置数据库连接信息 -->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
<property name="username" value="root" />
<property name="password" value="root" />
</dataSource>
</environment>
</environments>
</configuration>
说明:
(1)type为"JDBC"时,使用JdbcTransaction管理事务。
(2)type为"managed"时,使用ManagedTransaction管理事务(也就是交由外部容器管理)
2、MyBatis事务工厂
mybatis的事务是由TransactionFactory创建的,利用典型的简单工厂模式来创建Transaction,如下图:
说明:
- Transaction:封装事务管理方法的接口
- TransactionFactory:抽象事务工厂生产方法
- JdbcTransactionFactory:实现TransactionFactory接口,用于生产JdbcTransaction的工厂类
- ManagedTransactionFactory:实现TransactionFactory接口,用于生产ManagedTransaction的工厂类
- JdbcTransaction:实现Transaction接口,只是对事务进行了一层包装、实际调用数据库连接Connection的事务管理方法
- ManagedTransaction:实现Transaction没有对数据库连接做任何事务处理、交由外部容器管理
3、MyBatis事务源码分析
第一步:解析配置文件的transactionManager节点。
private void environmentsElement(XNode context) throws Exception {
//只关注事务部分...
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
...
}
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
注意:两种事务工厂已经在mybatis初始化的时候完成了注册:
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
第二步:利用反射机制生成具体的的factory,此处以JdbcTransactionFactory为例,查看一下JdbcTransactionFactory的源码:
public class JdbcTransactionFactory implements TransactionFactory {
public void setProperties(Properties props) {
}
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
}
说明:在反射过程中,JdbcTransactionFactory默认无参构造方法被调用
第三步:获取具体类型的事务,以JdbcTransaction为例。
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
说明:JdbcTransaction是通过Connection来创建具体的实例
第四步:事务的底层实现。以JdbcTransaction为例来说明。
public class JdbcTransaction implements Transaction
{
/* 连接**/
protected Connection connection;
/* 数据源**/
protected DataSource dataSource;
/* 事务等级**/
protected TransactionIsolationLevel level;
/* 事务提交**/
protected boolean autoCommmit;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit)
{
dataSource = ds;
level = desiredLevel;
autoCommmit = desiredAutoCommit;
}
public JdbcTransaction(Connection connection)
{
this.connection = connection;
}
public Connection getConnection() throws SQLException
{
if (connection == null)
{
openConnection();
}
//返回连接
return connection;
}
public void commit() throws SQLException
{
if (connection != null && !connection.getAutoCommit())
{
//连接提交
connection.commit();
}
}
public void rollback() throws SQLException
{
if (connection != null && !connection.getAutoCommit())
{
//操作回滚
connection.rollback();
}
}
public void close() throws SQLException
{
if (connection != null)
{
resetAutoCommit();
//关闭连接
connection.close();
}
}
protected void setDesiredAutoCommit(boolean desiredAutoCommit)
{
try
{
//事务提交状态不一致时修改
if (connection.getAutoCommit() != desiredAutoCommit)
{
connection.setAutoCommit(desiredAutoCommit);
}
}
catch (SQLException e)
{
throw new TransactionException("Error configuring AutoCommit.", e);
}
}
protected void resetAutoCommit()
{
try
{
if (!connection.getAutoCommit())
{
connection.setAutoCommit(true);
}
}
catch (SQLException e)
{
}
}
protected void openConnection() throws SQLException
{
connection = dataSource.getConnection();
if (level != null)
{
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommmit);
}
}
从源码中可知,JdbcTransaction如何管理事务的,是通过封装调用DataSource获取connection来实现的。