10.4 MyBatis事务管理 10.4.3事务的配置创建和使用

10.4 MyBatis事务管理 10.4.3事务的配置创建和使用

1.事务的配置

我们在使用MyBatis时,一般会在MyBatis的根配置文件mybatis-config.xml中定义类似如下的信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<environment id="mysql">
<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>

environment标签定义了连接某个数据库的信息,其子标签transactionManagertype属性决定我们用什么类型的事务管理机制。

如何查看mybatis源码

mybatis的源码放在github上了,所以到github上即可查看mybatis的源码.地址为:
https://github.com/mybatis/mybatis-3/tree/master/src/main/java/org/apache/ibatis

2.事务工厂的创建

MyBatis事务的创建是交给org.apache.ibatis.transaction.TransactionFactory事务工厂来完成的。如果我们将transactionManager标签的type属性配置为JDBC,那么,在MyBatis初始化解析environment标签时,会根据type="JDBC“创建一个JdbcTransactionFactory工厂.

  • 如果type="JDBC",则MyBatis会创建一个JdbcTransactionFactory的实例;
  • 如果type="MANAGED",则MyBatis会创建一个MangedTransactionFactory的实例。

3.事务工厂TransactionFactory

通过事务工厂TransactionFactory很容易获取到Transaction对象实例。我们以JdbcTransaction为例,看一下JdbcTransactionFactory是怎样生成JdbcTransaction的。
JdbcTransaction源代码如下:
如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class JdbcTransactionFactory implements TransactionFactory {
@Override
public void setProperties(Properties props) {
}
//根据给定的数据库连接Connection创建Transaction
@Override
public Transaction newTransaction(Connection conn) {
return new JdbcTransaction(conn);
}
//根据DateSource,隔离级别,是否自动提交创建Transacion
@Override
public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
return new JdbcTransaction(ds, level, autoCommit);
}
}

如上代码所示,JdbcTransactionFactory会创建JDBC类型的Transaction,即JdbcTransaction。类似地,ManagedTransactionFactory也会创建ManagedTransaction。下面我们分别深入解析JdbcTransactionManagedTransaction,看它们到底是怎样实现事务管理的.

4.JdbcTransaction

JdbcTransaction可直接使用JDBC的提交和回滚事务管理机制。它依赖于从dataSource中取得的连接connection来管理transaction的作用域,connection对象的获取被延迟到调用getConnection()方法时。如果将autocomt设置为on,开启状态的话,则它会忽略commitrollback.
也就是说,JdbcTransaction是使用java.sql.Connection上的commitrollback功能来完成事务操作的,JdbcTransaction只是相当于对java.sql.Connection事务处理进行了再次封装,Transaction的事务管理都是通过java.sql.Connection实现的JdbcTransaction源代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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 autoCommit;
public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
dataSource = ds;
level = desiredLevel;
autoCommit = desiredAutoCommit;
}
public JdbcTransaction(Connection connection) {
this.connection = connection;
}
@Override
public Connection getConnection() throws SQLException {
if (connection == null) {
openConnection();
}
return connection;
}
//使用Connection的commit()
@Override
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
connection.commit();
}
}
//使用Connection的rollback();
@Override
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
}
//使用Connection的close()
@Override
public void close() throws SQLException {
if (connection != null) {
resetAutoCommit();
if (log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
connection.close();
}
}
// 省略部分代码.
}

JdbcTransaction类的源代码可以看出,JdbcTransaction就是使用java.sql.Connection上的commitrollback功能来完成事务操作的.

5.ManagedTransaction

ManagedTransaction让容器来管理事务Transaction的整个生命周期,意思就是说,使用ManagedTransactioncommitrollback功能不会对事务有任何的影响,它什么都不会做,它将事务管理的权力移交给了容器。ManagedTransaction源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class ManagedTransaction implements Transaction {
private static final Log log = LogFactory.getLog(ManagedTransaction.class);
private DataSource dataSource;
private TransactionIsolationLevel level;
private Connection connection;
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;
}
@Override
public Connection getConnection() throws SQLException {
if (this.connection == null) {
openConnection();
}
return this.connection;
}
@Override
public void commit() throws SQLException {
// Does nothing
}
@Override
public void rollback() throws SQLException {
// Does nothing
}
@Override
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());
}
}
@Override
public Integer getTimeout() throws SQLException {
return null;
}
}

ManagedTransaction类的源代码可以看出,提交回滚它什么都没有做,也就是说,当使用ManagedTransactionMyBatis的事务是交给容器来操作管理的.