MyBatis的事务管理和缓存机制

一、MyBatis的事务管理

1.事务的概念:事务是一个或几个操作组成的一个整体执行单元,它们要么全部执行,要么全不执行,不能只执行其中的某几个操作;可以理解为一个事务是一个程序中执行的最小单元。

2.事务的特性:事务包含四个特性:原子性、一致性、隔离性、持久性,简称ACID性,具体详解如下

        ·原子性:事务是应用中最小的执行单位,就像自然界中原子是最小的颗粒一样,具有不可分隔的特性,事务是应用程序中不可分隔的最小逻辑执行单元。

        ·一致性:事务执行的结果,必须使数据库从一种一致状态,变成另为一种一致状态。例如事务中包含两条需要执行的sql语句,要么两条语句都执行成功,要么都不成功,这就是一致性。

        ·隔离性:各个事务的执行互不干扰,任意一个事务的内部操作对其他并发的事务,都是隔离的。即,并发执行的事务之间是不会互相干扰的。

        ·持续性:指事务一旦提交,对数据的修改就是永久的,不可逆的。

3.事务的执行动作:数据库的事务执行动作可分为:创建(create)、提交(commit)、回滚(rollback)、关闭(close),其对应的动作都抽象到了Transaction接口中,其源代码如下:


public interface Transaction {

    //获取数据库连接
    java.sql.Connection getConnection() throws java.sql.SQLException;

    //提交
    void commit() throws java.sql.SQLException;

    //回滚
    void rollback() throws java.sql.SQLException;

    //关闭数据库连接
    void close() throws java.sql.SQLException;
}

4.MyBatis的事务管理分类:

        ·使用JDBC的事务管理机制 —— 利用java.sql.Connnection对象完成对事务的提交、回滚和关闭等操作。

        ·使用MANAGED的事务管理机制 —— 对于这种机制,MyBatis自身不会去实现事务管理,而是让容器如JBOSS等来实现对事务的管理。

5.事务的使用流程。

        5.1事务的配置,首先在MyBatis的根配置文件mybatis-config.xml中定义如下信息:

<environment id="mysql">
            <!--指定事务管理类型,type="JDBC"指直接使用JDBC的提交和回滚设置,type=“MANAGED”指让容器实现对事务的管理-->
            <transactionManager type="JDBC" />
           <!-- <transactionManager type="MANAGED">
                <property name="closeConnection" value="false" />
            </transactionManager>-->
            <!-- dataSource数据源配置,POOLED是JDBC连接对象的数据源连接池的实现。-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis" />
                <property name="username" value="root"/>
                <property name="password" value="123456" />
            </dataSource>
           
        </environment>

        5.2事务工厂的创建:MyBatis的事务创建是由org.apache.ibatis.transaction.TransactionFactory事务工厂来完成的,会根据<transactionManager>的type类型来创建是JdbcTransactionFactory工厂还是ManagedTransactionFactory工厂,其源码如下:

public interface TransactionFactory {
    void setProperties(java.util.Properties properties);

    org.apache.ibatis.transaction.Transaction newTransaction(java.sql.Connection connection);

    org.apache.ibatis.transaction.Transaction newTransaction(javax.sql.DataSource dataSource, org.apache.ibatis.session.TransactionIsolationLevel transactionIsolationLevel, boolean b);
}

         5.3 事务工厂TransactionFactory:通过TransactionFactory可以获得到Transaction对象的实例,以JdbcTransaction为例,其源码如下:

public class JdbcTransactionFactory implements TransactionFactory {

  public void setProperties(Properties props) {
  }

  //根据给定的数据库连接Connection创建Transaction  
  public Transaction newTransaction(Connection conn) {
    return new JdbcTransaction(conn);
  }

  //根据DataSource、隔离级别和是否自动提交创建Transaction
  public Transaction newTransaction(DataSource ds, TransactionIsolationLevel level, boolean autoCommit) {
    return new JdbcTransaction(ds, level, autoCommit);
  }
}

        5.4 JdbcTransaction :JdbcTransaction可直接使用JDBC提交和回滚事务管理机制,JdbcTransaction是使用了java.sql.Connection上的commit和rollback功能来完成事务操作,其实JdbcTransaction只是把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;

  public JdbcTransaction(DataSource ds, TransactionIsolationLevel desiredLevel, boolean desiredAutoCommit) {
    dataSource = ds;
    level = desiredLevel;
    autoCommmit = desiredAutoCommit;
  }

  public JdbcTransaction(Connection connection) {
    this.connection = connection;
  }

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

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

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

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

}

          5.5 ManagedTransaction:ManagedTransaction让容器来管理事务Transaction的整个生命周期,也就是说,使用ManagedTransaction的commit和rollback功能不会对事务有任何的影响,它什么都不会做,它将事务管理的权利移交给了容器来实现,其源码如下:

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) {
      openConnection();
    }
    return this.connection;
  }

  public void commit() throws SQLException {
    // Does nothing
  }

  public void rollback() throws SQLException {
    // Does nothing
  }

  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("Openning JDBC Connection");
    }
    this.connection = this.dataSource.getConnection();
    if (this.level != null) {
      this.connection.setTransactionIsolation(this.level.getLevel());
    }
  }

}

二、MyBatis的缓存机制

1、一级缓存(SqlSession级别) ——

1.1 含义:在操作数据库时需要创建SqlSession对象,在对象中有一个HashMap用来存储缓存数据,并且不同的SqlSession之间的缓存数据区域是不会互相影响的。

1.2 作用域:一级缓存的作用域是SqlSession范围,就是当同一个SqlSession中执行两次相同的sql查询语句时,第一次回去数据库中查询数据并写到缓存中,第二次在查询的时候,不会再去数据库中去查询,而是直接在缓存中读取数据。在使用时需要注意:当SqlSession执行DML操作(insert、update、delete)时,MyBatis会清空SqlSession中的一级缓存,这样做的目的是保证缓存中的数据永远是最新的数据,防止出现脏读数据。

2.二级缓存(mapper级别) ——

1.1 含义:使用二级缓存时,多个SqlSession共享一个Mapper的sql语句去操作数据库,得到的数据,同样用HashMap来存储缓存数据,相比较于一级缓存,二级缓存的范围更大,多个SqlSession共享二级缓存,二级缓存时跨SqlSession的。

1.2作用域:二级缓存的作用域是mapper的同一个namespace,当不同的SqlSession执行相同的namespace下的sql语句,并向sql语句中传递的参数也相同时,第一次回去数据库中查询数据并写到缓存中,第二次在查询的时候,不会再去数据库中去查询,而是直接在缓存中读取数据。

1.3 二级缓存的使用配置:因为MyBatis默认没有开启二级缓存,需要在setting全局参数中开启二级缓存,其mybatis-config.xml配置文件如下:

<settings>
     <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>

在需要开启二级缓存的mapper文件中加入如下配置:

<cache eviction="LRU" flushInterval="10000" size="512" readOnly="true" />

其上述元素配置详解如下:

        ·eviction —— 收回策略,默认为LRU,一共有如下几种回收策略

                ·LRU —— 最近最少使用的策略,移除最长时间不被使用的对象。

                ·FIFO —— 先进先出策略,按对象进入缓存的顺序来移除它们。

                ·SOFT —— 软引用策略,移除基于垃圾回收器状态和软引用规则的对象。

                ·WEAK —— 弱引用策略,更积极地移除基于垃圾收集器状态和弱引用规则的对象。

        ·flushInterval —— 刷新间隔,可以被设置为任意的正整数,它的单位毫秒,默认情况下是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

        ·size —— 缓存数目,可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。

        ·readOnly —— 只读属性,可以被设置为 true或false,只读的缓存会给所有调用着返回缓存对象的相同实例,因此这些对象不能被修改,可读写的缓存会返回缓存对象的拷贝(通过序列化)。这样做会慢一些,但是安全,因此默认是false。

猜你喜欢

转载自blog.csdn.net/huxiaodong1994/article/details/82431162