mybatis事物如何避免脏读_Mybatis事务管理

1、Mybatis事务

1.1、事务管理方式

Mybatis中的事务管理方式有两种:

1、JDBC的事务管理机制,即使用JDBC事务管理机制进行事务管理

2、MANAGED的事务管理机制,Mybatis没有实现对事务的管理,而是通过容器来实现对事务的管理

其中,Mybatis提供了事务的接口:Transaction,其代码如下:public interface Transaction {  /**

* Retrieve inner database connection

* @return DataBase connection

* @throws SQLException

*/

//获得数据库连接

Connection getConnection() throws SQLException;  /**

* Commit inner database connection.

* @throws SQLException

*/

//提交

void commit() throws SQLException;  /**

* Rollback inner database connection.

* @throws SQLException

*/

//回滚

void rollback() throws SQLException;  /**

* Close inner database connection.

* @throws SQLException

*/

//连接关闭

void close() throws SQLException;  /**

* Get transaction timeout if set

* @throws SQLException

*/

//获取事务timeout

Integer getTimeout() throws SQLException;

}

Transaction有两个实现类:JdbcTransaction和ManagedTransaction,分别对应两种事务管理方式。

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;

}  @Override

public Connection getConnection() throws SQLException {    if (connection == null) {

openConnection();

}    return connection;

}  @Override

public void commit() throws SQLException {    if (connection != null && !connection.getAutoCommit()) {      if (log.isDebugEnabled()) {

log.debug("Committing JDBC Connection [" + connection + "]");

}

connection.commit();

}

}  @Override

public void rollback() throws SQLException {    if (connection != null && !connection.getAutoCommit()) {      if (log.isDebugEnabled()) {

log.debug("Rolling back JDBC Connection [" + connection + "]");

}

connection.rollback();

}

}  @Override

public void close() throws SQLException {    if (connection != null) {

resetAutoCommit();      if (log.isDebugEnabled()) {

log.debug("Closing JDBC Connection [" + connection + "]");

}

connection.close();

}

}  protected void setDesiredAutoCommit(boolean desiredAutoCommit) {    try {      //事务提交状态不一致时修改

if (connection.getAutoCommit() != desiredAutoCommit) {        if (log.isDebugEnabled()) {

log.debug("Setting autocommit to " + desiredAutoCommit + " on JDBC Connection [" + connection + "]");

}

connection.setAutoCommit(desiredAutoCommit);

}

} catch (SQLException e) {      // Only a very poorly implemented driver would fail here,

// and there's not much we can do about that.

throw new TransactionException("Error configuring AutoCommit.  "

+ "Your driver may not support getAutoCommit() or setAutoCommit(). "

+ "Requested setting: " + desiredAutoCommit + ".  Cause: " + e, e);

}

}  protected void resetAutoCommit() {    try {      if (!connection.getAutoCommit()) {        if (log.isDebugEnabled()) {

log.debug("Resetting autocommit to true on JDBC Connection [" + connection + "]");

}

connection.setAutoCommit(true);

}

} catch (SQLException e) {      if (log.isDebugEnabled()) {

log.debug("Error resetting autocommit to true "

+ "before closing the connection.  Cause: " + e);

}

}

}  protected void openConnection() throws SQLException {    if (log.isDebugEnabled()) {

log.debug("Opening JDBC Connection");

}    //从数据源中获得连接

connection = dataSource.getConnection();    if (level != null) {

connection.setTransactionIsolation(level.getLevel());

}

setDesiredAutoCommit(autoCommmit);

}  @Override

public Integer getTimeout() throws SQLException {    return null;

}

}

JdbcTransaction通过使用jdbc提供的方式来管理事务,通过Connection提供的事务管理方法来进行事务管理,只是将JDBC的事务管理进行了封装。

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

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

}

}  @Override

public Integer getTimeout() throws SQLException {    return null;

}

}

此外,当Mybatis与Spring一起使用时,Spring会提供一个Transaction的实现类SpringManagedTransaction进行事务管理,这会在后面的Spring源码中说到。

可参考:https://blog.csdn.net/qq924862077/article/details/525997851.2

1.2、事务配置方式

Mybatis的事务管理方式的配置是在核心配置文件中进行的,它是在configuration标签下的environments中与数据源一起配置的,可以配置多个,如下所示:

//配置事务管理方式      

2、事务隔离级别

在上面的源码中,我们看到TransactionIsolationLevel—事务隔离级别,Mybaais中定义了五种隔离级别,代码如下所示:public enum TransactionIsolationLevel {

NONE(Connection.TRANSACTION_NONE),

READ_COMMITTED(Connection.TRANSACTION_READ_COMMITTED),

READ_UNCOMMITTED(Connection.TRANSACTION_READ_UNCOMMITTED),

REPEATABLE_READ(Connection.TRANSACTION_REPEATABLE_READ),

SERIALIZABLE(Connection.TRANSACTION_SERIALIZABLE);  private final int level;  private TransactionIsolationLevel(int level) {    this.level = level;

}  public int getLevel() {    return level;

}

}

其中四种是一般数据库的事务隔离级别,从高到底以此为:Read uncommitted(读未提交)、Read committed(读已提交)、Repeatable read(可重复读)、Serializable(可串行化),这几个级别主要用于解决脏读、不可重复读、幻读等问题,其总结如下表:级别脏读不可重复读幻读说明Read uncommittedtruetruetrue一个更新语句没有提交,但是别的事务可以读到这个改变.这是很不安全的。允许任务读取数据库中未提交的数据更改,也称为脏读。

Read committedfalsetruetrue语句提交以后即执行了COMMIT以后别的事务就能读到这个改变. 只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别,可防止脏读。

Repeatable readfalsefalsetrue同一个事务里面先后执行同一个查询语句的时候,得到的结果是一样的.在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。

Serializablefalsefalsefalse事务执行的时候不允许别的事务并发执行. 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

注:true表示出现,false表示不出现

参考自:https://blog.csdn.net/qq924862077/article/details/52599961

Mybatis添加的隔离级别NONE,可在DefaultSqlSessionFactory中创建SqlSession时,设置数据库的事务隔离级别,以及通过设置autoCommit来设置事务的提交方式。代码参见DefaultSqlSessionFactory,示例代码如下:private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)

3、事务工厂

此外,在Mybatis中还提供了事务工厂:TransactionFactory,代码如下所示:public interface TransactionFactory {  //配置工厂属性

void setProperties(Properties props);  //通过Connection获取事务

Transaction newTransaction(Connection conn);

//通过数据库,事务等级,是否自动提交创建事务

Transaction newTransaction(DataSource dataSource, TransactionIsolationLevel level, boolean autoCommit);

}

类似的,TransactionFactory也有两个实现类:JdbcTransactionFactory和ManagedTransactionFactory

JdbcTransactionFactory代码如下:public class JdbcTransactionFactory implements TransactionFactory {  @Override

public void setProperties(Properties props) {

}  @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 class ManagedTransactionFactory implements TransactionFactory {  private boolean closeConnection = true;  @Override

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

}

}

作者:紫焱

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值