Mybatis事务管理

Mybatis事务管理

事务管理方式

Transaction接口

public interface Transaction {
    Connection getConnection() throws SQLException;

    void commit() throws SQLException;

    void rollback() throws SQLException;

    void close() throws SQLException;

    Integer getTimeout() throws SQLException;
}

接口实现类有三个分别是JDBCTransaction.class、ManagedTransaction和SpringManagedTransaction(这里主要说前两者)

JDBC事务管理机制(JdbcTransaction)

即JDBC使用的到的Connection对象,下面我们看一下Connection的部分源码怎么写的

PreparedStatement prepareStatement(String sql) throws SQLException;
void setAutoCommit(boolean autoCommit) throws SQLException;
boolean getAutoCommit() throws SQLException;
PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException;
void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException;
String getClientInfo(String name) throws SQLException;
int getHoldability() throws SQLException;
void rollback(Savepoint savepoint) throws SQLException;
void commit() throws SQLException;
void rollback() throws SQLException;
void close() throws SQLException;

通过这些commit(),rollback(),close()可以实现事物的提交、回滚、关闭等操作

下面来看看JdbcTransaction的一些方法

protected Connection connection;
protected DataSource dataSource;
protected TransactionIsolationLevel level;
//ManagerTransaction没有这个属性
protected boolean autoCommit;

//构造方法
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
  dataSource = ds;
  level = desiredLevel;
  autoCommit = desiredAutoCommit;
}

protected void openConnection() throws SQLException {
    //打印日志
    if (log.isDebugEnabled()) {
        log.debug("Opening JDBC Connection");
    }
	//获取连接
    this.connection = this.dataSource.getConnection();
    //设置事物等级
    if (this.level != null) {
        this.connection.setTransactionIsolation(this.level.getLevel());
    }
	//设置自动提交
    this.setDesiredAutoCommit(this.autoCommit);
}
protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
   try {
	 if (this.connection.getAutoCommit() != desiredAutoCommit) {
      if (log.isDebugEnabled()) {
    	   log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + this.connection + "]");
       }
         //设置自动提交
         this.connection.setAutoCommit(desiredAutoCommit);
       }
      } catch (SQLException var3) {
            throw new TransactionException("Error configuring AutoCommit.  Your driver may not support getAutoCommit() or setAutoCommit(). Requested setting: " + desiredAutoCommit + ".  Cause: " + var3, var3);
      }
  }
public void close() throws SQLException {
  if (connection != null) {
    resetAutoCommit();
    if (log.isDebugEnabled()) {
      log.debug("Closing JDBC Connection [" + connection + "]");
    }
    connection.close();
  }
}

MANAGER管理事物(ManagedTransaction)

这种MANAGER机制主要是为了保证mybatis对事务管理的拓展性和灵活性,使用这种机制就可以和其他框架联合使用,将具体事物的管理都交由第三方框架来进行管理,主要和mybatis整合的框架基本就是Springframework

private DataSource dataSource;
private TransactionIsolationLevel level;
private Connection connection;
//JdbcTransaction类没有这个属性
private final boolean closeConnection;

//构造方法
public ManagedTransaction(Connection connection, boolean closeConnection) {
  this.connection = connection;
  this.closeConnection = closeConnection;
}
public ManagedTransaction(DataSource ds, TransactionIsolationLevel level, boolean closeConnection) {
  this.dataSource = ds;
  this.level = level;
  this.closeConnection = closeConnection;
}

protected void openConnection() throws SQLException {
  if (log.isDebugEnabled()) {
    log.debug("Opening JDBC Connection");
  }
  this.connection = this.dataSource.getConnection();
  if (this.level != null) {
    this.connection.setTransactionIsolation(this.level.getLevel());
  }
}

public void close() throws SQLException {
  if (this.closeConnection && this.connection != null) {
    if (log.isDebugEnabled()) {
      log.debug("Closing JDBC Connection [" + this.connection + "]");
    }
    this.connection.close();
  }
}

public void commit() throws SQLException {
  // Does nothing
}

public void rollback() throws SQLException {
  // Does nothing
}

与JDBCTransaction不同的是,它没有尝试设置自动提交。且在关闭是我们可以看出在JdbcTransaction这个类中关闭方法只是判断连接是否为空,而ManagerTransaction还必须判断属性closeConnection是否是true才进行关闭。而且提交和回滚方法都没有进行具体的实现,而是提供给spring去实现具体的业务

配置文件中配置事物执行流程

现在我们来看看在mybatis配置文件中写过配置(具体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>
	<properties resource="db/mysqlconn.properties"></properties>
	 <!-- 开启懒加载 -->
    <settings>
    	<setting name="lazyLoadingEnabled" value="true"/>
    	<setting name="aggressiveLazyLoading" value="false"/>
    <!-- 将other转为null值 -->	
    	<setting name="jdbcTypeForNull" value="NULL"/><!-- 不设置这个参数的话有一些数据库不能识别null,如oracle数据库 -->
    <!-- 指定日志为log4j -->
    	<setting name="logImpl" value="LOG4J"/>
    <!-- 开启二级缓存 -->
    	<setting name="cacheEnabled" value="true"/>
    </settings>
	<typeAliases>
		<package name="pojo" />
	</typeAliases>
	<environments default="development">
		<environment id="development">
            <!-- 在这里我们选择事务机制,选择了JDBC -->
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${driver}" />
				<property name="url" value="${url}" />
				<property name="username" value="${username}" />
				<property name="password" value="${password}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<package name="mapper" />
	</mappers>
</configuration> 

此时我们设置了事务为JDBC,那么在之后在调用XMLConfigBuilder.environmentsElement()方法时,就会生成一个JDBCTransactionFactory来产生JDBCTransaction对象,代码如下:

private void environmentsElement(XNode context) throws Exception {
  if (context != null) {
    if (environment == null) {
      environment = context.getStringAttribute("default");
    }
    for (XNode child : context.getChildren()) {
      String id = child.getStringAttribute("id");
      if (isSpecifiedEnvironment(id)) {
        //就这一步,将你传过来的JDBC解析成一个JDBCTransactionFactory
        TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
        DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
        DataSource dataSource = dsFactory.getDataSource();
        Environment.Builder environmentBuilder = new Environment.Builder(id)
            .transactionFactory(txFactory)
            .dataSource(dataSource);
        configuration.setEnvironment(environmentBuilder.build());
      }
    }
  }
}

下面我们来看事务工厂TransactionFactory接口的源码

public interface TransactionFactory {
  //设置一些必要的属性
  default void setProperties(Properties props) {
    // NOP
  }
  //和之前的JDBCTransaction和ManagerTransaction的构造方法像吧
  Transaction newTransaction(Connection conn);
  Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

}

具体实现类也是和Transaction接口类似,有三个,分别是JDBCTransactionFactory.class、ManagedTransactionFactory和SpringManagedTransactionFactory(主要看前两者)

JdbcTransactionFactory

@Override
public Transaction newTransaction(Connection conn) {
  return new JdbcTransaction(conn);
}
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
  return new JdbcTransaction(ds, level, autoCommit);
}

ManagedTransactionFactory

public void setProperties(Properties props) {
  if (props != null) {
    String closeConnectionProperty = props.getProperty("closeConnection");
    if (closeConnectionProperty != null) {
      closeConnection = Boolean.valueOf(closeConnectionProperty);
    }
  }
}
@Override
public Transaction newTransaction(Connection conn) {
  return new ManagedTransaction(conn, closeConnection);
}
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
  return new ManagedTransaction(ds, level, closeConnection);
}

可以看出JDBCTransactionFactory没有实现TransactionFactory的setProperties()方法,而ManagerTransactionFactory是实现的

JdbcTemplate

内部为用户封装了JDBC的步骤

public JdbcTemplate() {
}
//看得出必须依赖一个数据源
public JdbcTemplate(DataSource dataSource) {
   setDataSource(dataSource);
   afterPropertiesSet();
}

public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
   setDataSource(dataSource);
   setLazyInit(lazyInit);
   afterPropertiesSet();
}
//代理模式(线程安全)
protected Connection createConnectionProxy(Connection con) {
	return (Connection) Proxy.newProxyInstance(
			ConnectionProxy.class.getClassLoader(),
			new Class<?>[] {ConnectionProxy.class},
			new CloseSuppressingInvocationHandler(con));
}

在获取连接对象Connection的时,使用了JDK动态代理,所以这个类是线程安全的,每一次拿的连接对象(Connection)都是代理对象

原文地址:https://www.cnblogs.com/five-five/p/14102864.html