mybatis事务管理机制详解

时间:2023-03-09 13:39:09
mybatis事务管理机制详解

1.mybatis事务的配置和使用

mybatis事务有两种使用方式:

(a):使用JDBC的事务管理机制:即使用java.Sql.Connection对象完成对事务的提交,回滚和关闭操作。

(b):使用MANAGED的事务管理机制:mybatis本身不会去实现事务管理的相关操作,而是交个外部容器来管理事务。当与spring整合使用后,一般使用spring来管理事务。

在配置文件中的配置:

    <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>

在这段配置信息中,有三个节点:<transactionManager />,<dataSource>,<environment>。其中,<dataSource>节点封装了数据源的信息,<environment>封装了数据库的连接,包括数据源和事务,然后把该节点信息封装到了Configuration对象中,方便后面使用,现在看下mybatis在初始化加载配置文件时,对<environment/>节点的解析:

  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)) {
// 解析 <transactionManager>节点,获取事务工厂对象 进入该方法
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
// 解析<DataSource>节点,获取数据源对象
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());
}
}
}
}

进入解析<transactionManager/>节点的方法:

  private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
// 获取type的属性值,JDBC或者MANAGED
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
//生成一个TransactionFactory实例
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}

2.事务工厂TransactionFactory

TransactionFactory定义了创建Transaction的两种方法,如下:

public interface TransactionFactory {

  /**
* Sets transaction factory custom properties.
* @param props
*/
void setProperties(Properties props); /**
* Creates a {@link Transaction} out of an existing connection.
* @param conn Existing database connection
* @return Transaction
* @since 3.1.0
* 方法一:通过指定的Connection对象来创建事务
*/
Transaction newTransaction(Connection conn); /**
* Creates a {@link Transaction} out of a datasource.
* @param dataSource DataSource to take the connection from
* @param level Desired isolation level
* @param autoCommit Desired autocommit
* @return Transaction
* @since 3.1.0
* 方法二:通过DataSource,隔离级别,是否自动提交 来创建事务
*/
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit); }

TransactionFactory有两个子类:JdbcTransactionFactory和ManagedTransactionFactory

2.1 JdbcTransactionFactory,会创建JDBC类型的事务,就是JdbcTransaction,看下源码:

public class JdbcTransactionFactory implements TransactionFactory {

  public void setProperties(Properties props) {
}
// JDBCTransaction的创建有两种方法
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
} public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
}

2.2 ManagedTransactionFactory,会创建MANAGED类型的事务,ManagedTransaction,同样有两种方法:

public class ManagedTransactionFactory implements TransactionFactory {

  private boolean closeConnection = true;

  public void setProperties(Properties props) {
if (props != null) {
String closeConnectionProperty = props.getProperty("closeConnection");
if (closeConnectionProperty != null) {
closeConnection = Boolean.valueOf(closeConnectionProperty);
}
}
} public Transaction newTransaction(Connection conn) {
return new ManagedTransaction(conn, closeConnection);
} public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
// Silently ignores autocommit and isolation level, as managed transactions are entirely
// controlled by an external manager. It's silently ignored so that
// code remains portable between managed and unmanaged configurations.
return new ManagedTransaction(ds, level, closeConnection);
}
}

3.JdbcTransaction和ManagedTransaction

 3.1 JdbcTransaction

从源码可知:jdbcTransaction从DataSource获取连接对象Connection,然后利用Connection对象管理事务的commit和rollback,实际在事务处理上,jdbcTransaction是对java.sql.Connection的一个包装,它是使用Connection对象来管理事务的。

public class JdbcTransaction implements Transaction {

  private static final Log log = LogFactory.getLog(JdbcTransaction.class);

  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;
}
// 使用Connection对象提交
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
connection.commit();
}
} public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
} public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
connection.close();
}
} protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
try {
if (connection.getAutoCommit() != desiredAutoCommit) {
if (log.isDebugEnabled()) {
log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");
}
connection.setAutoCommit(desiredAutoCommit);
}
} catch (SQLException e) {
// Only a very poorly implemented driver would fail here,
// and there's not much we can do about that.
throw new TransactionException("Error configuring AutoCommit. "
+ "Your driver may not support getAutoCommit() or setAutoCommit(). "
+ "Requested setting: " + desiredAutoCommit + ". Cause: " + e, e);
}
} protected void resetAutoCommit() {
try {
if (!connection.getAutoCommit()) {
// MyBatis does not call commit/rollback on a connection if just selects were performed.
// Some databases start transactions with select statements
// and they mandate a commit/rollback before closing the connection.
// A workaround is setting the autocommit to true before closing the connection.
// Sybase throws an exception here.
if (log.isDebugEnabled()) {
log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");
}
connection.setAutoCommit(true);
}
} catch (SQLException e) {
log.debug("Error resetting autocommit to true "
+ "before closing the connection. Cause: " + e);
}
} protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
// 从数据源获取连接对象
connection = dataSource.getConnection();
if (level != null) {
connection.setTransactionIsolation(level.getLevel());
}
setDesiredAutoCommit(autoCommmit);
} }

3.2 ManagedTransaction 

ManagedTransaction对事务的commit和rollback交给了容器去管理,自己本身并没有做任何处理,看源码:

public class ManagedTransaction implements Transaction {

  private static final Log log = LogFactory.getLog(ManagedTransaction.class);

  private DataSource dataSource;
private TransactionIsolationLevel level;
private Connection connection;
private boolean closeConnection;
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}

// 没有做任何处理,因为交给了外部容器去做这件事了
public void commit() throws SQLException {
// Does nothing
} public void rollback() throws SQLException {
// Does nothing
} public void close() throws SQLException {
if (this.closeConnection && this.connection != null) {
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + this.connection + "]");
}
this.connection.close();
}
} 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());
}
} }