github地址:https://github.com/dchack/Mybatis-source-code-learn (歡迎star)java
官方文檔:mysql
在 MyBatis 中有兩種類型的事務管理器(也就是 type=」[JDBC|MANAGED]」):
JDBC – 這個配置就是直接使用了 JDBC 的提交和回滾設置,它依賴於從數據源獲得的鏈接來管理事務做用域。
MANAGED – 這個配置幾乎沒作什麼。它歷來不提交或回滾一個鏈接,而是讓容器來管理事務的整個生命週期(好比 JEE 應用服務器的上下文)。 默認狀況下它會關閉鏈接,然而一些容器並不但願這樣,所以須要將 closeConnection 屬性設置爲 false 來阻止它默認的關閉行爲。例如:git<transactionManager type="MANAGED"> <property name="closeConnection" value="false"/> </transactionManager>提示若是你正在使用 Spring + MyBatis,則沒有必要配置事務管理器, 由於 Spring 模塊會使用自帶的管理器來覆蓋前面的配置。github
以上配置transactionManager屬性來配置使用哪種TransactionFactory
的代碼,確定在MybatisXMLConfigBuilder
中能夠找到:spring
private TransactionFactory transactionManagerElement(XNode context) throws Exception { if (context != null) { String type = context.getStringAttribute("type"); Properties props = context.getChildrenAsProperties(); TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance(); factory.setProperties(props); return factory; } throw new BuilderException("Environment declaration requires a TransactionFactory."); }
從TransactionFactory
入手:sql
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 */ 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 */ Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit); }
TransactionFactory
接口描述實現者須要從Connection
或DataSource
生產org.apache.ibatis.transaction.Transaction
出來。apache
接口實現類以下:
服務器
他們各自生產的Transaction
分別是:ide
Transaction接口:ui
/** * Wraps a database connection. * Handles the connection lifecycle that comprises: its creation, preparation, commit/rollback and close. * * @author Clinton Begin */ public interface Transaction { /** * Retrieve inner database connection * @return DataBase connection * @throws SQLException */ Connection getConnection() throws SQLException; /** * Commit inner database connection. * @throws SQLException */ void commit() throws SQLException; /** * Rollback inner database connection. * @throws SQLException */ void rollback() throws SQLException; /** * Close inner database connection. * @throws SQLException */ void close() throws SQLException; /** * Get transaction timeout if set * @throws SQLException */ Integer getTimeout() throws SQLException; }
抽象出了控制connection生命週期的核心接口:getConnection(create),commit,rollback,close。
三個操做方法:commit,rollback,close
,都是connection
的封裝而已,commit,rollback執行的條件須要已經生成好connection
而且AutoCommit
沒有設置true,close方法會調用resetAutoCommit
方法重置Connection
的autoCommit
屬性爲true
:
@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(); } }
重置autoCommit屬性方法:
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); } } }
在看下getConnection
方法的實現:
@Override public Connection getConnection() throws SQLException { if (connection == null) { openConnection(); } return connection; } 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); }
openConnection中設置了事務隔離級別(transaction isolation level)和autoCommmit。
事務隔離級別在TransactionIsolationLevel
枚舉中能夠看到:
public enum TransactionIsolationLevel { NONE(Connection.TRANSACTION_NONE), READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED), READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED), REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ), SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE); private final int level; private TransactionIsolationLevel(int level) { this.level = level; } public int getLevel() { return level; } }
在java.sql.Connection
中的定義和註釋以下:
/** * A constant indicating that transactions are not supported. */ int TRANSACTION_NONE = 0; /** * A constant indicating that * dirty reads, non-repeatable reads and phantom reads can occur. * This level allows a row changed by one transaction to be read * by another transaction before any changes in that row have been * committed (a "dirty read"). If any of the changes are rolled back, * the second transaction will have retrieved an invalid row. */ int TRANSACTION_READ_UNCOMMITTED = 1; /** * A constant indicating that * dirty reads are prevented; non-repeatable reads and phantom * reads can occur. This level only prohibits a transaction * from reading a row with uncommitted changes in it. */ int TRANSACTION_READ_COMMITTED = 2; /** * A constant indicating that * dirty reads and non-repeatable reads are prevented; phantom * reads can occur. This level prohibits a transaction from * reading a row with uncommitted changes in it, and it also * prohibits the situation where one transaction reads a row, * a second transaction alters the row, and the first transaction * rereads the row, getting different values the second time * (a "non-repeatable read"). */ int TRANSACTION_REPEATABLE_READ = 4; /** * A constant indicating that * dirty reads, non-repeatable reads and phantom reads are prevented. * This level includes the prohibitions in * <code>TRANSACTION_REPEATABLE_READ</code> and further prohibits the * situation where one transaction reads all rows that satisfy * a <code>WHERE</code> condition, a second transaction inserts a row that * satisfies that <code>WHERE</code> condition, and the first transaction * rereads for the same condition, retrieving the additional * "phantom" row in the second read. */ int TRANSACTION_SERIALIZABLE = 8;
幾個概念:
隔離級別:
mysql中查看隔離級別設置:
select @@global.tx_isolation;
另外咱們也看到JdbcTransaction
中是須要autoCommmit
設置true的,不然是不能完成事務功能的。
從類註釋上能夠看到:ManagedTransaction
是將事務的生命週期交給容器管理,能夠理解它都是空實現,好比commit,rollback
,close
能夠經過closeConnection
字段來關閉。
後續進入Mybatis擴展模塊時展開。