发表于: 2019-11-11 23:58:45

1 989


今天完成的事情:(一定要写非常细致的内容,比如说学会了盒子模型,了解了Margin)

今天又没有做什么事,刷了牛客网的一套题。自己的基础还是很差。

Mybatis管理事务是分为两种方式:

(1)使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交
(2)使用MANAGED的事务管理机制,这种机制mybatis自身不会去实现事务管理,而是让程序的容器(JBOSS,WebLogic)来实现对事务的管理
在Mybatis的配置文件中可以配置事务管理方式如下:
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2.  <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">  
  3.  <configuration>  
  4.      <environments default="development">  
  5.           <environment id="development">  
  6.               <!--配置事务的管理方式-->  
  7.               <transactionManager type="JDBC" />  
  8.               <!-- 配置数据库连接信息 -->  
  9.               <dataSource type="POOLED">  
  10.                   <property name="driver" value="com.mysql.jdbc.Driver" />  
  11.                  <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />  
  12.                  <property name="username" value="root" />  
  13.                  <property name="password" value="XDP" />  
  14.              </dataSource>  
  15.          </environment>  
  16.      </environments>      
  17.  </configuration>  

Mybatis提供了一个事务接口Transaction,以及两个实现类jdbcTransaction和ManagedTransaction,当spring与Mybatis一起使用时,spring提供了一个实现类SpringManagedTransaction
Transaction接口:提供的抽象方法有获取数据库连接getConnection,提交事务commit,回滚事务rollback和关闭连接close,源码如下:

  1. //事务接口  
  2. ublic interface Transaction {  
  3.  /** 
  4.   * Retrieve inner database connection 
  5.   * @return DataBase connection 
  6.   * @throws SQLException 
  7.   */  
  8.   //获得数据库连接  
  9.  Connection getConnection() throws SQLException;  
  10.  /** 
  11.   * 提交 
  12.   * Commit inner database connection. 
  13.   * @throws SQLException 
  14.   */  
  15.  void commit() throws SQLException;  
  16.  /** 
  17.   * 回滚 
  18.   * Rollback inner database connection. 
  19.   * @throws SQLException 
  20.   */  
  21.  void rollback() throws SQLException;  
  22.  /** 
  23.   * 关闭连接 
  24.   * Close inner database connection. 
  25.   * @throws SQLException 
  26.   */  
  27.  void close() throws SQLException;  


JdbcTransaction实现类:Transaction的实现类,通过使用jdbc提供的方式来管理事务,通过Connection提供的事务管理方法来进行事务管理,源码如下:

  1. public class JdbcTransaction implements Transaction {  
  2.   
  3.   private static final Log log = LogFactory.getLog(JdbcTransaction.class);  
  4.   
  5.   /* 连接**/  
  6.   protected Connection connection;  
  7.     
  8.   /* 数据源**/  
  9.   protected DataSource dataSource;  
  10.     
  11.   /* 事务等级**/  
  12.   protected TransactionIsolationLevel level;  
  13.     
  14.   /* 事务提交**/  
  15.   protected boolean autoCommmit;  
  16.   
  17.   public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {  
  18.     dataSource = ds;  
  19.     level = desiredLevel;  
  20.     autoCommmit = desiredAutoCommit;  
  21.   }  
  22.   
  23.   public JdbcTransaction(Connection connection) {  
  24.     this.connection = connection;  
  25.   }  
  26.   
  27.   @Override  
  28.   public Connection getConnection() throws SQLException {  
  29.     if (connection == null) {  
  30.       openConnection();  
  31.     }  
  32.     //返回连接  
  33.     return connection;  
  34.   }  
  35.   
  36.   @Override  
  37.   public void commit() throws SQLException {  
  38.     if (connection != null && !connection.getAutoCommit()) {  
  39.       if (log.isDebugEnabled()) {  
  40.         log.debug("Committing JDBC Connection [" + connection + "]");  
  41.       }  
  42.       //连接提交  
  43.       connection.commit();  
  44.     }  
  45.   }  
  46.   
  47.   @Override  
  48.   public void rollback() throws SQLException {  
  49.     if (connection != null && !connection.getAutoCommit()) {  
  50.       if (log.isDebugEnabled()) {  
  51.         log.debug("Rolling back JDBC Connection [" + connection + "]");  
  52.       }  
  53.       //连接回滚  
  54.       connection.rollback();  
  55.     }  
  56.   }  
  57.   
  58.   @Override  
  59.   public void close() throws SQLException {  
  60.     if (connection != null) {  
  61.       resetAutoCommit();  
  62.       if (log.isDebugEnabled()) {  
  63.         log.debug("Closing JDBC Connection [" + connection + "]");  
  64.       }  
  65.       //关闭连接  
  66.       connection.close();  
  67.     }  
  68.   }  
  69.   
  70.   protected void setDesiredAutoCommit(boolean desiredAutoCommit) {  
  71.     try {  
  72.       //事务提交状态不一致时修改  
  73.       if (connection.getAutoCommit() != desiredAutoCommit) {  
  74.         if (log.isDebugEnabled()) {  
  75.           log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");  
  76.         }  
  77.         connection.setAutoCommit(desiredAutoCommit);  
  78.       }  
  79.     } catch (SQLException e) {  
  80.       // Only a very poorly implemented driver would fail here,  
  81.       // and there's not much we can do about that.  
  82.       throw new TransactionException("Error configuring AutoCommit.  "  
  83.           + "Your driver may not support getAutoCommit() or setAutoCommit(). "  
  84.           + "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);  
  85.     }  
  86.   }  
  87.   
  88.   protected void resetAutoCommit() {  
  89.     try {  
  90.       if (!connection.getAutoCommit()) {  
  91.         // MyBatis does not call commit/rollback on a connection if just selects were performed. select操作没有commit和rollback事务  
  92.         // Some databases start transactions with select statements 一些数据库在select操作是会开启事务  
  93.         // and they mandate a commit/rollback before closing the connection.  
  94.         // A workaround is setting the autocommit to true before closing the connection.  
  95.         // Sybase throws an exception here.  
  96.         if (log.isDebugEnabled()) {  
  97.           log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");  
  98.         }  
  99.         connection.setAutoCommit(true);  
  100.       }  
  101.     } catch (SQLException e) {  
  102.       if (log.isDebugEnabled()) {  
  103.         log.debug("Error resetting autocommit to true "  
  104.           + "before closing the connection.  Cause: " + e);  
  105.       }  
  106.     }  
  107.   }  
  108.   //打开连接  
  109.   protected void openConnection() throws SQLException {  
  110.     if (log.isDebugEnabled()) {  
  111.       log.debug("Opening JDBC Connection");  
  112.     }  
  113.     //从数据源中获得连接  
  114.     connection = dataSource.getConnection();  
  115.     if (level != null) {  
  116.       connection.setTransactionIsolation(level.getLevel());  
  117.     }  
  118.     setDesiredAutoCommit(autoCommmit);  
  119.   }  
  120.   
  121. }  

ManagedTransaction实现类:通过容器来进行事务管理,所有它对事务提交和回滚并不会做任何操作,源码如下:

  • 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;  
  •   }  
  •   
  •   @Override  
  •   public Connection getConnection() throws SQLException {  
  •     if (this.connection == null) {  
  •       openConnection();  
  •     }  
  •     return this.connection;  
  •   }  
  •   //提交操作无效  
  •   @Override  
  •   public void commit() throws SQLException {  
  •     // Does nothing  
  •   }  
  •   //回滚操作无效  
  •   @Override  
  •   public void rollback() throws SQLException {  
  •     // Does nothing  
  •   }  
  •   
  •   @Override  
  •   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());  
  •     }  
  •   }  
  •   
  • }  

SpringManagedTransaction实现类:它其实也是通过使用JDBC来进行事务管理的,当spring的事务管理有效时,不需要操作commit/rollback/close,spring事务管理会自动帮我们完成,源码如下:

  1. public class SpringManagedTransaction implements Transaction {  
  2.   
  3.   private static final Log LOGGER = LogFactory.getLog(SpringManagedTransaction.class);  
  4.   
  5.   private final DataSource dataSource;  
  6.   
  7.   private Connection connection;  
  8.   
  9.   private boolean isConnectionTransactional;  
  10.   
  11.   private boolean autoCommit;  
  12.     
  13.   //获得数据源  
  14.   public SpringManagedTransaction(DataSource dataSource) {  
  15.     notNull(dataSource, "No DataSource specified");  
  16.     this.dataSource = dataSource;  
  17.   }  
  18.   
  19.   /** 
  20.    * {@inheritDoc} 
  21.    * 返回数据库连接 
  22.    */  
  23.   @Override  
  24.   public Connection getConnection() throws SQLException {  
  25.     if (this.connection == null) {  
  26.       openConnection();  
  27.     }  
  28.     return this.connection;  
  29.   }  
  30.   
  31.   /** 
  32.    * Gets a connection from Spring transaction manager and discovers if this 
  33.    * {@code Transaction} should manage connection or let it to Spring. 
  34.    * <p> 
  35.    * It also reads autocommit setting because when using Spring Transaction MyBatis 
  36.    * thinks that autocommit is always false and will always call commit/rollback 
  37.    * so we need to no-op that calls. 
  38.    *从spring的事务管理中获得一个连接  
  39.    */  
  40.   private void openConnection() throws SQLException {  
  41.     this.connection = DataSourceUtils.getConnection(this.dataSource);  
  42.     this.autoCommit = this.connection.getAutoCommit();  
  43.     this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);  
  44.   
  45.     if (LOGGER.isDebugEnabled()) {  
  46.       LOGGER.debug(  
  47.           "JDBC Connection ["  
  48.               + this.connection  
  49.               + "] will"  
  50.               + (this.isConnectionTransactional ? " " : " not ")  
  51.               + "be managed by Spring");  
  52.     }  
  53.   }  
  54.   
  55.   /** 
  56.    * {@inheritDoc} 
  57.    */  
  58.   @Override  
  59.   public void commit() throws SQLException {  
  60.     if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {  
  61.       if (LOGGER.isDebugEnabled()) {  
  62.         LOGGER.debug("Committing JDBC Connection [" + this.connection + "]");  
  63.       }  
  64.       this.connection.commit();  
  65.     }  
  66.   }  
  67.   
  68.   /** 
  69.    * {@inheritDoc} 
  70.    */  
  71.   @Override  
  72.   public void rollback() throws SQLException {  
  73.     if (this.connection != null && !this.isConnectionTransactional && !this.autoCommit) {  
  74.       if (LOGGER.isDebugEnabled()) {  
  75.         LOGGER.debug("Rolling back JDBC Connection [" + this.connection + "]");  
  76.       }  
  77.       this.connection.rollback();  
  78.     }  
  79.   }  
  80.   
  81.   /** 
  82.    * {@inheritDoc} 
  83.    */  
  84.   @Override  
  85.   public void close() throws SQLException {  
  86.     DataSourceUtils.releaseConnection(this.connection, this.dataSource);  
  87.   }  
  88.   
  89. }  

如果开启MyBatis事务管理,则需要手动进行事务提交,否则事务会回滚到原状态;

String resource = "mybatis/config.xml";

InputStream is = Main.class.getClassLoader().getResourceAsStream(resource);

SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

SqlSession session = sessionFactory.openSession();

User user = new User();

user.setName("liuliu");

user.setPassword("123123");

user.setScore("88");

String statement = "mybatis.mapping.UserMapper.insertUser";

session.insert(statement,user);

session.close();

如果在具体操作执行完后不通过sqlSession.commit()方法提交事务,事务在sqlSession关闭时会自动回滚到原状态;只有执行了commit()事务提交方法才会真正完成操作;

如果不执行sqlSession.commit()操作,直接执行sqlSession.close(),则会在close()中进行事务回滚;

如果不执行sqlSession.commit()操作也不手动关闭sqlSession,在程序结束时关闭数据库连接时会进行事务回滚;


String resource = "mybatis/config.xml";

InputStream is = Main.class.getClassLoader().getResourceAsStream(resource);

SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(is);

SqlSession session = sessionFactory.openSession();

User user = new User();

user.setName("liuliu");

user.setPassword("123123");

user.setScore("88");

String statement = "mybatis.mapping.UserMapper.insertUser";

session.insert(statement,user);

session.commit();

session.close();

在XML配置文件中定义事务工厂类型,JDBC或者MANAGED分别对应JdbcTransactionFactory.class和ManagedTransactionFactory.class;

如果type=”JDBC”则使用JdbcTransactionFactory事务工厂则MyBatis独立管理事务,直接使用JDK提供的JDBC来管理事务的各个环节:提交、回滚、关闭等操作;

如果type=”MANAGED”则使用ManagedTransactionFactory事务工厂则MyBatis不在ORM层管理事务而是将事务管理托付给其他框架,如Spring;

<environments default="development">

    <environment id="development">

        <transactionManager type="JDBC" />    //相当于<transactionManager type="JdbcTransactionFactory.class" />

        <dataSource type="POOLED">

            <property name="driver" value="com.mysql.jdbc.Driver" />

            <property name="url" value="jdbc:mysql://localhost:3306/test" />

            <property name="username" value="root" />

            <property name="password" value="BIUBIU" />

        </dataSource>

    </environment>

</environments>

在从SessionFactory中获取sqlSession时候会根据environment配置获取相应的事务工厂TransactionFactory,并从中获取事务实例当做参数传递给Executor,用来从中获取Connection数据库连接;

public SqlSession openSession() {  return openSessionFromDataSource(configuration.getDefaultExecutorType(), nullfalse); }


getTransactionFactoryFromEnvironment()方法根据XML配置获取JdbcTransactionFactory或者ManagedTransactionFactory;ManagedTransactionFactory类中的commit()方法和rollback()方法都为空,事务相关操作不发挥作用;

private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {

  Transaction tx = null;

  try {

    final Environment environment = configuration.getEnvironment();

    final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);

    tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);

    final Executor executor = configuration.newExecutor(tx, execType);

    return new DefaultSqlSession(configuration, executor, autoCommit);

  } catch (Exception e) {

    closeTransaction(tx); // may have fetched a connection so lets call close()

    throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);

  } finally {

    ErrorContext.instance().reset();

  }

}


MyBatis可以通过XML配置是否独立处理事务,可以选择不单独处理事务,将事务托管给其他上层框架如spring等;

如果MyBatis选择处理事务则事务会对数据库操作产生影响

对UPDATE操作的影响主要表现在UPDATE操作后如果没有进行事务提交则会子啊会话关闭时进行数据库回滚;

对SELECT操作的影响主要表现在二级缓存上,执行SELECT操作后如果未进行事务提交则缓存会被放在临时缓存中,后续的SELECT操作无法使用该缓存,直到进行commit()事务提交,临时缓存中的数据才会被转移到正式缓存中;


明天计划的事情:(一定要写非常细致的内容)
遇到的问题:(遇到什么困难,怎么解决的)
收获:(通过今天的学习,学到了什么知识)



返回列表 返回列表
评论

    分享到