zoukankan      html  css  js  c++  java
  • 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)都是代理对象

  • 相关阅读:
    HDU 5912 Fraction (模拟)
    CodeForces 722C Destroying Array (并查集)
    CodeForces 722B Verse Pattern (水题)
    CodeForces 722A Broken Clock (水题)
    CodeForces 723D Lakes in Berland (dfs搜索)
    CodeForces 723C Polycarp at the Radio (题意题+暴力)
    CodeForces 723B Text Document Analysis (水题模拟)
    CodeForces 723A The New Year: Meeting Friends (水题)
    hdu 1258
    hdu 2266 dfs+1258
  • 原文地址:https://www.cnblogs.com/five-five/p/14102864.html
Copyright © 2011-2022 走看看