MyBatis+SpringMVC+SpringBootJava服务器端编程程序员

Mybatis原理--事务管理

2017-09-24  本文已影响123人  ChinaXieShuai

本文将会介绍Mybatis的事务管理机制的原理,首先介绍下事务管理的特质、在Mybatis中是如何创建事务、事务有哪几种类型、不同事务的源码实现、并比较其中的不同、并总结事务的原理。最后分享学习事务常见的小知识。

事务的概述
对于数据库事务,具有如下几种特质:
Transaction源码
可以看出,这个接口中包含最基本 的getConnection、commit、rollback、close 方法,任何实现对事物管理都需要实现这几个方法。

Mybatis中实现事务的管理分为如下两种:

事务的创建

Mybatis在初始化的时候,会加载解析Mybatis的xml配置文件,在xml文件中若配置了事务管理的类型,<transactionManager>type配置为"JDBC",那么,在MyBatis初始化解析<environment>节点时,会根据

源码截图如下:

Mybatis事务的创建

下面我们来看看他们的实现细节:

JdbcTransaction的创建

JdbcTransactionFactory类会根据 DataSource、隔离级别、是否自动提交 这三个参数创建Transacion,也可以根据给定的数据库连接Connection创建Transaction
JdbcTransactionFactory 的源码如下:

public class JdbcTransactionFactory implements TransactionFactory {  
  
  public void setProperties(Properties props) {  
  }  
  
    /** 
     * 根据给定的数据库连接Connection创建Transaction 
     * @param conn Existing database connection 
     * @return 
     */  
  public Transaction newTransaction(Connection conn) {  
    return new JdbcTransaction(conn);  
  }  
  
    /** 
     * 根据DataSource、隔离级别和是否自动提交创建Transacion 
     * 
     * @param ds 
     * @param level Desired isolation level 
     * @param autoCommit Desired autocommit 
     * @return 
     */  
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {  
    return new JdbcTransaction(ds, level, autoCommit);  
  }  
}
JdbcTransaction的实现

JdbcTransaction直接使用JDBC的提交和回滚事务管理机制 。它依赖与从dataSource中取得的连接connection 来管理transaction 的作用域,connection对象的获取被延迟到调用getConnection()方法。如果autocommit设置为on,开启状态的话,它会忽略commitrollback
直观地讲,就是JdbcTransaction是使用的java.sql.Connection 上的commitrollback功能,JdbcTransaction只是相当于对java.sql.Connection事务处理进行了一次包装(wrapper),Transaction的事务管理都是通过java.sql.Connection实现的。
JdbcTransaction的源码如下,快速阅读的读者只需要看本人加注释的部分即可:

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;
    //根据  DataSource、隔离级别、是否自动提交 三个参数创建Transacion
    public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
        this.dataSource = ds;
        this.level = desiredLevel;
        this.autoCommmit = desiredAutoCommit;
    }

    //根据给定的数据库连接Connection创建Transaction
    public JdbcTransaction(Connection connection) {
        this.connection = connection;
    }

    public Connection getConnection() throws SQLException {
        if(this.connection == null) {
            this.openConnection();
        }

        return this.connection;
    }

    //使用 java.sql.Connection 的 commit
    public void commit() throws SQLException {
        if(this.connection != null && !this.connection.getAutoCommit()) {
            if(log.isDebugEnabled()) {
                log.debug("Committing JDBC Connection [" + this.connection + "]");
            }

            this.connection.commit();
        }

    }

    //使用 java.sql.Connection 的 rollback
    public void rollback() throws SQLException {
        if(this.connection != null && !this.connection.getAutoCommit()) {
            if(log.isDebugEnabled()) {
                log.debug("Rolling back JDBC Connection [" + this.connection + "]");
            }

            this.connection.rollback();
        }

    }
    //使用 java.sql.Connection 的 close
    public void close() throws SQLException {
        if(this.connection != null) {
            this.resetAutoCommit();
            if(log.isDebugEnabled()) {
                log.debug("Closing JDBC Connection [" + this.connection + "]");
            }

            this.connection.close();
        }

    }

    protected void setDesiredAutoCommit(boolean desiredAutoCommit) {
        try {
            if(this.connection.getAutoCommit() != desiredAutoCommit) {
                if(log.isDebugEnabled()) {
                    log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + this.connection + "]");
                }

                this.connection.setAutoCommit(desiredAutoCommit);
            }

        } catch (SQLException var3) {
            throw new TransactionException("Error configuring AutoCommit.  Your driver may not support getAutoCommit() or setAutoCommit(). Requested setting: " + desiredAutoCommit + ".  Cause: " + var3, var3);
        }
    }

    protected void resetAutoCommit() {
        try {
            if(!this.connection.getAutoCommit()) {
                if(log.isDebugEnabled()) {
                    log.debug("Resetting autocommit to true on JDBC Connection [" + this.connection + "]");
                }

                this.connection.setAutoCommit(true);
            }
        } catch (SQLException var2) {
            if(log.isDebugEnabled()) {
                log.debug("Error resetting autocommit to true before closing the connection.  Cause: " + var2);
            }
        }

    }

    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());
        }

        this.setDesiredAutoCommit(this.autoCommmit);
    }

    public Integer getTimeout() throws SQLException {
        return null;
    }
}
总结:
  • 当使用DataSource创建数据库连接时,数据库的事务隔离级别使用DataSource默认的事务隔离级别
  • 当使用 DataSource、隔离级别、是否自动提交 三个参数创建JdbcTransaction时,会使用传入的参数来设定隔离级别和是否自动提交
  • 对select不进行事务控制
  • JdbcTransaction的事务,原理上就是封装了一层JDBC的方法

ManagedTransaction的实现

ManagedTransaction让容器来管理事务Transaction的整个生命周期,使用ManagedTransactioncommitrollback功能不会对事务有任何的影响,它什么都不会做,它将事务管理的权利移交给了容器来实现

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

    public Connection getConnection() throws SQLException {
        if(this.connection == null) {
            this.openConnection();
        }

        return this.connection;
    }
    //不做任何处理
    public void commit() throws SQLException {
    }
    //不做任何处理
    public void rollback() throws SQLException {
    }

    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());
        }

    }

    public Integer getTimeout() throws SQLException {
        return null;
    }
}
关于事务的隔离级别
先对不同隔离级别涉及到的名词解释:

脏读: 对于两个事物 T1、T2,T1 读取了已经被 T2 更新但还没有被提交的字段。之后, 若 T2 回滚,T1读取的内容就是临时且无效的。
不可重复读: 对于两个事物 T1、T2, T1 读取了一个字段, 然后 T2 更新了该字段。 之后, T1再次读取同一个字段, 值就不同了。
幻读: 对于两个事物 T1、T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插入了一些新的行。 如果 T1 再次读取同一个表, 就会多出数据

具体的隔离级别定义:

Oracle 默认的事务隔离级别为: READ COMMITED(读已提交数据)
Mysql 默认的事务隔离级别为: REPEATABLE READ(可重复读)

以上就是《Mybatis原理--事务管理》的全部内容,如有不正确的地方,请读者指正,互相学习,共同进步,谢谢。

上一篇下一篇

猜你喜欢

热点阅读