对mybatis中的Transaction进行简单的解析

pull/4/head
AmyliaY 5 years ago
parent 869125a0e6
commit 46bee89bc2

@ -1,4 +1,4 @@
在数据持久层数据源和事务是两个非常重要的组件对数据持久层的影响很大在实际开发中一般会使用mybatis集成第三方数据源组件c3p0、Druid另外mybatis也提供了自己的数据源实现。而事务方面一般使用spring进行事务的管理。下面我们看一下mybatis是如何对这两部分进行封装的。 在数据持久层数据源和事务是两个非常重要的组件对数据持久层的影响很大在实际开发中一般会使用mybatis集成第三方数据源组件c3p0、Druid另外mybatis也提供了自己的数据库连接池实现本文会通过mybatis的实现来了解数据库连接池的设计。而事务方面一般使用spring进行事务的管理,这里不做详细分析。下面我们看一下mybatis是如何对这两部分进行封装的。
## 1 DataSource ## 1 DataSource
常见的数据源都会实现javax.sql.DataSource接口mybatis中提供了两个该接口的实现类分别是PooledDataSource和UnpooledDataSource并使用不同的工厂类分别管理这两个类的对象。 常见的数据源都会实现javax.sql.DataSource接口mybatis中提供了两个该接口的实现类分别是PooledDataSource和UnpooledDataSource并使用不同的工厂类分别管理这两个类的对象。
### 1.1 DataSourceFactory ### 1.1 DataSourceFactory
@ -701,5 +701,285 @@ public class PooledDataSource implements DataSource {
} }
``` ```
## 2 Transaction ## 2 Transaction
遵循接口-实现类的设计原则mybatis也是先使用Transaction接口对数据库事务做了抽象而实现类则只提供了两个JdbcTransaction和ManagedTransaction。这两种对象的获取使用了两个对应的工厂类JdbcTransactionFactory和ManagedTransactionFactory。
不过一般我们并不会使用mybatis管理事务而是将mybatis集成到spring由spring进行事务的管理。细节部分会在后面的文章中详细讲解。
```java
public interface Transaction {
/**
* 获取连接对象
*/
Connection getConnection() throws SQLException;
/**
* 提交事务
*/
void commit() throws SQLException;
/**
* 回滚事务
*/
void rollback() throws SQLException;
/**
* 关闭数据库连接
*/
void close() throws SQLException;
/**
* 获取配置的事务超时时间
*/
Integer getTimeout() throws SQLException;
}
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;
}
// 提交、回滚、关闭等操作的代码都比较简单只对原生的JDBC操作做了简单封装
@Override
public void commit() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
connection.commit();
}
}
@Override
public void rollback() throws SQLException {
if (connection != null && !connection.getAutoCommit()) {
if (log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
}
@Override
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) {
if (log.isDebugEnabled()) {
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(autoCommit);
}
@Override
public Integer getTimeout() throws SQLException {
return null;
}
}
public class ManagedTransaction implements Transaction {
private static final Log log = LogFactory.getLog(ManagedTransaction.class);
// 数据源
private DataSource dataSource;
// 事务隔离级别
private TransactionIsolationLevel level;
// 对应的数据库连接
private Connection connection;
// 控制是否关闭持有的连接在close()方法中用其判断是否真的关闭连接
private final boolean closeConnection;
// 本类的实现也很简单commit、rollback方法都是空实现
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;
}
}
public interface TransactionFactory {
/**
* 配置TransactionFactory对象一般会在完成TransactionFactory对象
* 初始化之后 就进行自定义属性配置
*/
default void setProperties(Properties props) {
// NOP
}
/**
* 在指定的数据库连接上创建Transaction事务对象
*/
Transaction newTransaction(Connection conn);
/**
* 从指定数据源获取数据库连接并在此连接上创建Transaction对象
*/
Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
}
public class JdbcTransactionFactory implements TransactionFactory {
@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);
}
}
public class ManagedTransactionFactory implements TransactionFactory {
private boolean closeConnection = true;
@Override
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) {
// 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);
}
}
```
Loading…
Cancel
Save