1.mybatis事务的配置和使用
mybatis事务有两种使用方式:
(a):使用JDBC的事务管理机制:即使用java.Sql.Connection对象完成对事务的提交,回滚和关闭操作。
(b):使用MANAGED的事务管理机制:mybatis本身不会去实现事务管理的相关操作,而是交个外部容器来管理事务。当与spring整合使用后,一般使用spring来管理事务。
在配置文件中的配置:
//JDBC的事务方式
在这段配置信息中,有三个节点:,,。其中,节点封装了数据源的信息,封装了数据库的连接,包括数据源和事务,然后把该节点信息封装到了Configuration对象中,方便后面使用,现在看下mybatis在初始化加载配置文件时,对节点的解析:
private void environmentsElement(XNode context) throwsException {if (context != null) {if (environment == null) {
environment= context.getStringAttribute("default");
}for(XNode child : context.getChildren()) {
String id= child.getStringAttribute("id");if(isSpecifiedEnvironment(id)) {
// 解析 节点,获取事务工厂对象 进入该方法
TransactionFactory txFactory= transactionManagerElement(child.evalNode("transactionManager"));
// 解析节点,获取数据源对象
DataSourceFactory dsFactory= dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource=dsFactory.getDataSource();
Environment.Builder environmentBuilder= newEnvironment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
进入解析节点的方法:
private TransactionFactory transactionManagerElement(XNode context) throwsException {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);returnfactory;
}throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
2.事务工厂TransactionFactory
TransactionFactory定义了创建Transaction的两种方法,如下:
public interfaceTransactionFactory {/*** Sets transaction factory custom properties.
*@paramprops*/
voidsetProperties(Properties props);/*** Creates a {@linkTransaction} out of an existing connection.
*@paramconn Existing database connection
*@returnTransaction
*@since3.1.0
* 方法一:通过指定的Connection对象来创建事务*/Transaction newTransaction(Connection conn);/*** Creates a {@linkTransaction} out of a datasource.
*@paramdataSource DataSource to take the connection from
*@paramlevel Desired isolation level
*@paramautoCommit Desired autocommit
*@returnTransaction
*@since3.1.0
* 方法二:通过DataSource,隔离级别,是否自动提交 来创建事务*/Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level,booleanautoCommit);
}
TransactionFactory有两个子类:JdbcTransactionFactory和ManagedTransactionFactory
2.1JdbcTransactionFactory,会创建JDBC类型的事务,就是JdbcTransaction,看下源码:
public class JdbcTransactionFactory implementsTransactionFactory {public voidsetProperties(Properties props) {
}
// JDBCTransaction的创建有两种方法publicTransaction newTransaction(Connection conn) {return newJdbcTransaction(conn);
}public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, booleanautoCommit) {return newJdbcTransaction(ds, level, autoCommit);
}
}
2.2 ManagedTransactionFactory,会创建MANAGED类型的事务,ManagedTransaction,同样有两种方法:
public class ManagedTransactionFactory implementsTransactionFactory {private boolean closeConnection = true;public voidsetProperties(Properties props) {if (props != null) {
String closeConnectionProperty= props.getProperty("closeConnection");if (closeConnectionProperty != null) {
closeConnection=Boolean.valueOf(closeConnectionProperty);
}
}
}publicTransaction newTransaction(Connection conn) {return newManagedTransaction(conn, closeConnection);
}public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, booleanautoCommit) {//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 newManagedTransaction(ds, level, closeConnection);
}
}
3.JdbcTransaction和ManagedTransaction
3.1 JdbcTransaction
从源码可知:jdbcTransaction从DataSource获取连接对象Connection,然后利用Connection对象管理事务的commit和rollback,实际在事务处理上,jdbcTransaction是对java.sql.Connection的一个包装,它是使用Connection对象来管理事务的。
public class JdbcTransaction implementsTransaction {private static final Log log = LogFactory.getLog(JdbcTransaction.class);protectedConnection connection;// 连接对象protectedDataSource dataSource; //数据源protectedTransactionIsolationLevel level; // 隔离级别protected booleanautoCommmit;//是否自动提交public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, booleandesiredAutoCommit) {
dataSource=ds;
level=desiredLevel;
autoCommmit=desiredAutoCommit;
}publicJdbcTransaction(Connection connection) {this.connection =connection;
}
// 获取连接对象public Connection getConnection() throwsSQLException {if (connection == null) {
openConnection();
}returnconnection;
}
// 使用Connection对象提交public void commit() throwsSQLException {if (connection != null && !connection.getAutoCommit()) {if(log.isDebugEnabled()) {
log.debug("Committing JDBC Connection [" + connection + "]");
}
connection.commit();
}
}public void rollback() throwsSQLException {if (connection != null && !connection.getAutoCommit()) {if(log.isDebugEnabled()) {
log.debug("Rolling back JDBC Connection [" + connection + "]");
}
connection.rollback();
}
}public void close() throwsSQLException {if (connection != null) {
resetAutoCommit();if(log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + connection + "]");
}
connection.close();
}
}protected void setDesiredAutoCommit(booleandesiredAutoCommit) {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 voidresetAutoCommit() {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() throwsSQLException {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 implementsTransaction {private static final Log log = LogFactory.getLog(ManagedTransaction.class);privateDataSource dataSource;privateTransactionIsolationLevel level;privateConnection connection;private booleancloseConnection;public Connection getConnection() throwsSQLException {if (this.connection == null) {
openConnection();
}return this.connection;
}
// 没有做任何处理,因为交给了外部容器去做这件事了public void commit() throwsSQLException {//Does nothing
}public void rollback() throwsSQLException {//Does nothing
}public void close() throwsSQLException {if (this.closeConnection && this.connection != null) {if(log.isDebugEnabled()) {
log.debug("Closing JDBC Connection [" + this.connection + "]");
}this.connection.close();
}
}protected void openConnection() throwsSQLException {if(log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}this.connection = this.dataSource.getConnection();if (this.level != null) {this.connection.setTransactionIsolation(this.level.getLevel());
}
}
}