• Mybatis事务管理


    Mybatis事务管理

    事务管理方式

    Transaction接口

    public interface Transaction {
        Connection getConnection() throws SQLException;
    
        void commit() throws SQLException;
    
        void rollback() throws SQLException;
    
        void close() throws SQLException;
    
        Integer getTimeout() throws SQLException;
    }
    

    接口实现类有三个分别是JDBCTransaction.class、ManagedTransaction和SpringManagedTransaction(这里主要说前两者)

    JDBC事务管理机制(JdbcTransaction)

    即JDBC使用的到的Connection对象,下面我们看一下Connection的部分源码怎么写的

    PreparedStatement prepareStatement(String sql) throws SQLException;
    void setAutoCommit(boolean autoCommit) throws SQLException;
    boolean getAutoCommit() throws SQLException;
    PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException;
    void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException;
    String getClientInfo(String name) throws SQLException;
    int getHoldability() throws SQLException;
    void rollback(Savepoint savepoint) throws SQLException;
    void commit() throws SQLException;
    void rollback() throws SQLException;
    void close() throws SQLException;
    

    通过这些commit(),rollback(),close()可以实现事物的提交、回滚、关闭等操作

    下面来看看JdbcTransaction的一些方法

    protected Connection connection;
    protected DataSource dataSource;
    protected TransactionIsolationLevel level;
    //ManagerTransaction没有这个属性
    protected boolean autoCommit;
    
    //构造方法
    public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
      dataSource = ds;
      level = desiredLevel;
      autoCommit = desiredAutoCommit;
    }
    
    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.autoCommit);
    }
    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);
          }
      }
    public void close() throws SQLException {
      if (connection != null) {
        resetAutoCommit();
        if (log.isDebugEnabled()) {
          log.debug("Closing JDBC Connection [" + connection + "]");
        }
        connection.close();
      }
    }
    

    MANAGER管理事物(ManagedTransaction)

    这种MANAGER机制主要是为了保证mybatis对事务管理的拓展性和灵活性,使用这种机制就可以和其他框架联合使用,将具体事物的管理都交由第三方框架来进行管理,主要和mybatis整合的框架基本就是Springframework

    private DataSource dataSource;
    private TransactionIsolationLevel level;
    private Connection connection;
    //JdbcTransaction类没有这个属性
    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;
    }
    
    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 void close() throws SQLException {
      if (this.closeConnection && this.connection != null) {
        if (log.isDebugEnabled()) {
          log.debug("Closing JDBC Connection [" + this.connection + "]");
        }
        this.connection.close();
      }
    }
    
    public void commit() throws SQLException {
      // Does nothing
    }
    
    public void rollback() throws SQLException {
      // Does nothing
    }
    

    与JDBCTransaction不同的是,它没有尝试设置自动提交。且在关闭是我们可以看出在JdbcTransaction这个类中关闭方法只是判断连接是否为空,而ManagerTransaction还必须判断属性closeConnection是否是true才进行关闭。而且提交和回滚方法都没有进行具体的实现,而是提供给spring去实现具体的业务

    配置文件中配置事物执行流程

    现在我们来看看在mybatis配置文件中写过配置(具体mybatis配置文件解释||具体mybatis执行流程)

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
    	<properties resource="db/mysqlconn.properties"></properties>
    	 <!-- 开启懒加载 -->
        <settings>
        	<setting name="lazyLoadingEnabled" value="true"/>
        	<setting name="aggressiveLazyLoading" value="false"/>
        <!-- 将other转为null值 -->	
        	<setting name="jdbcTypeForNull" value="NULL"/><!-- 不设置这个参数的话有一些数据库不能识别null,如oracle数据库 -->
        <!-- 指定日志为log4j -->
        	<setting name="logImpl" value="LOG4J"/>
        <!-- 开启二级缓存 -->
        	<setting name="cacheEnabled" value="true"/>
        </settings>
    	<typeAliases>
    		<package name="pojo" />
    	</typeAliases>
    	<environments default="development">
    		<environment id="development">
                <!-- 在这里我们选择事务机制,选择了JDBC -->
    			<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>
    	</environments>
    	<mappers>
    		<package name="mapper" />
    	</mappers>
    </configuration> 
    

    此时我们设置了事务为JDBC,那么在之后在调用XMLConfigBuilder.environmentsElement()方法时,就会生成一个JDBCTransactionFactory来产生JDBCTransaction对象,代码如下:

    private void environmentsElement(XNode context) throws Exception {
      if (context != null) {
        if (environment == null) {
          environment = context.getStringAttribute("default");
        }
        for (XNode child : context.getChildren()) {
          String id = child.getStringAttribute("id");
          if (isSpecifiedEnvironment(id)) {
            //就这一步,将你传过来的JDBC解析成一个JDBCTransactionFactory
            TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
            DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
            DataSource dataSource = dsFactory.getDataSource();
            Environment.Builder environmentBuilder = new Environment.Builder(id)
                .transactionFactory(txFactory)
                .dataSource(dataSource);
            configuration.setEnvironment(environmentBuilder.build());
          }
        }
      }
    }
    

    下面我们来看事务工厂TransactionFactory接口的源码

    public interface TransactionFactory {
      //设置一些必要的属性
      default void setProperties(Properties props) {
        // NOP
      }
      //和之前的JDBCTransaction和ManagerTransaction的构造方法像吧
      Transaction newTransaction(Connection conn);
      Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);
    
    }
    

    具体实现类也是和Transaction接口类似,有三个,分别是JDBCTransactionFactory.class、ManagedTransactionFactory和SpringManagedTransactionFactory(主要看前两者)

    JdbcTransactionFactory

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

    ManagedTransactionFactory

    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) {
      return new ManagedTransaction(ds, level, closeConnection);
    }
    

    可以看出JDBCTransactionFactory没有实现TransactionFactory的setProperties()方法,而ManagerTransactionFactory是实现的

    JdbcTemplate

    内部为用户封装了JDBC的步骤

    public JdbcTemplate() {
    }
    //看得出必须依赖一个数据源
    public JdbcTemplate(DataSource dataSource) {
       setDataSource(dataSource);
       afterPropertiesSet();
    }
    
    public JdbcTemplate(DataSource dataSource, boolean lazyInit) {
       setDataSource(dataSource);
       setLazyInit(lazyInit);
       afterPropertiesSet();
    }
    //代理模式(线程安全)
    protected Connection createConnectionProxy(Connection con) {
    	return (Connection) Proxy.newProxyInstance(
    			ConnectionProxy.class.getClassLoader(),
    			new Class<?>[] {ConnectionProxy.class},
    			new CloseSuppressingInvocationHandler(con));
    }
    
    

    在获取连接对象Connection的时,使用了JDK动态代理,所以这个类是线程安全的,每一次拿的连接对象(Connection)都是代理对象

  • 相关阅读:
    【C++】虚函数
    ZF-net
    bzoj1061【NOI2008】志愿者招募
    highcharts 绘制图标的JAVASCRIPT 类库 收藏
    C语言中的const,free使用方法具体解释
    Java Transaction Management
    从有序数组中查找某个值 low_bound
    [华为机试练习题]35.找零钱
    1.9算法入门之进制转换
    uboot移植rtc
  • 原文地址:https://www.cnblogs.com/five-five/p/14102864.html
Copyright © 2020-2023  润新知