Mysql事务回滚的问题探究

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: Mysql事务回滚的问题探究

前提

XXX平台导出的mysql建表语句没有指定存储引擎,而mysql默认使用MyISAM。

但是MyISAM是不支持事务的。在mysql中,唯有InnoDb是支持事务的。

目的

验证Spring提供的标签@Transactional,以及XXX提供的TransactionComponent组件在不同的存储引擎下的工作实况。

建表语句

借用XXX-BATCH工程中的“batch_cli_user”表部分字段进行实验。

CREATE TABLE `BATCH_CLI_USER` (
  `protocol_no`  VARCHAR(64) NOT NULL COMMENT '协议号',
  `user_id`  VARCHAR(32) COMMENT '用户标识,录入人ID',
  `user_name`  VARCHAR(80) COMMENT '用户名称',
  `contact`  VARCHAR(32) COMMENT '联系人',
  `telephone`  VARCHAR(16) COMMENT '电话号码',
  `mobile_no`  VARCHAR(16) COMMENT '电话号码',
  CONSTRAINT `pk_BATCH_CLI_USER` PRIMARY KEY (`protocol_no`)
) ENGINE = MYISAM;

以及使用Innodb存储引擎的建表语句

CREATE TABLE `BATCH_CLI_USER` (
  `protocol_no`  VARCHAR(64) NOT NULL COMMENT '协议号',
  `user_id`  VARCHAR(32) COMMENT '用户标识,录入人ID',
  `user_name`  VARCHAR(80) COMMENT '用户名称',
  `contact`  VARCHAR(32) COMMENT '联系人',
  `telephone`  VARCHAR(16) COMMENT '电话号码',
  `mobile_no`  VARCHAR(16) COMMENT '电话号码',
  CONSTRAINT `pk_BATCH_CLI_USER` PRIMARY KEY (`protocol_no`)
) ENGINE = INNODB;

实验思路

通过两次对相同主键的插入,若事务生效,则在第二次插入报主键冲突的时候,应当发生回滚,使第一条的插入语句也被回滚,若事务不生效,则查询后可以观察到该记录。

实验过程

测试代码

如果发送事务回滚,则预期为null正确。

@Test
public void testRollbackForMysql() throws Exception {    batchCliUserMapper.deleteByPrimaryKey("testProtocolNo004");    
 BatchCliUser batchCliUser = new BatchCliUser();    
 batchCliUser.setUserId("testUser004");    
 batchCliUser.setProtocolNo("testProtocolNo004");    batchCustomerInfoService.testRollbackForMysql(batchCliUser);    
 BatchCliUser result1 = batchCliUserMapper.selectByPrimaryKey("testProtocolNo004");    Assert.assertTrue(null == result1);
}

1. MyISAM与@Transactional

代码

@Override@Transactional(rollbackFor = Exception.class)
public void testRollbackForMysql(BatchCliUser batchCliUser) throws Exception {    
    // 开启事务,连续插入两次,看事务是否会回滚掉第一次的插入    
    LOGGER.info("开始第一次插入");    
    batchCliUserMapper.insertSelective(batchCliUser);
    LOGGER.info("开始第二次插入");    
    batchCliUserMapper.insertSelective(batchCliUser);}

结果

代码在第二次插入时抛出org.springframework.dao.DuplicateKeyException。但是在数据库中仍然可以查询到该记录,回滚并未生效。

2. MyISAM与TransactionComponent组件

代码

@Override
public void testRollbackForMysql(BatchCliUser batchCliUser) throws Exception {    
    // 显式开启事务,连续插入两次,看事务是否会回滚掉第一次的插入    
    try {        
        transactionComponent.begin();        
        LOGGER.info("开始第一次插入");        
        batchCliUserMapper.insertSelective(batchCliUser);        
        LOGGER.info("开始第二次插入");        
        batchCliUserMapper.insertSelective(batchCliUser);        
        transactionComponent.commit();    
    } catch (Exception e) {        
        transactionComponent.rollback();        
        throw e;    
    }
}

结果

与实验1相同,回滚并未生效。

3. INNODB与@Transactional

代码

与实验1相同

结果

成功回滚,数据库中查无记录。

4. INNODB与TransactionComponent组件

代码

与实验2相同

结果

与实验3相同,成功回滚,数据库中查无记录。

后续探究

TransactionTemplate

Spring提供的事务管理模板,验证可以事务回滚。【且相对XXX提供的组件,更方便设置隔离级别,事务传播特性等】

@Autowired
    public TransactionTemplate transactionTemplate;  
  @Override
  public void testRollbackForMysql(BatchCliUser batchCliUser) throws Exception {        
        // 显式开启事务,连续插入两次,看事务是否会回滚掉第一次的插入        
        transactionTemplate.execute(new TransactionCallbackWithoutResult(){           
            @Override protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                LOGGER.info("开始第一次插入");
                batchCliUserMapper.insertSelective(batchCliUser);
                LOGGER.info("开始第二次插入");
                batchCliUserMapper.insertSelective(batchCliUser);
            }        
        });
    }

xml中的Bean配置

<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">   
    <property name="transactionManager" ref="testTransactionManager"></property>
</bean>

深入探究

  1. 三种方式均可完成回滚,那么其到底有什么共同点,在DataSourceTransactionManager类中有如下方法,在debug时发现:
protected void doRollback(DefaultTransactionStatus status) {    DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject)status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
           this.logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
       } try {
           con.rollback();
       } catch (SQLException var5) {
           throw new TransactionSystemException("Could not roll back JDBC transaction", var5);
       }
   }

其核心代码在con.rollback()这一行中,交由各个Connection接口的实现类自己实现。

PS: @Transactional注解还需要配置代理,配置如下后:

<!-- 事务管理器 -->
<bean id="testTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">   
    <property name="dataSource" ref="gapsDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="testTransactionManager" proxy-target-class="true"/>

配置好后@Transactional就可以正常回滚了。

  1. Mysql事务中到底怎么完成回滚?
    调试con.rollback()方法中,可以看到调用了以下方法:
private void rollbackNoChecks() throws SQLException {
    try {        
        synchronized(this.getConnectionMutex()) {
            if (!(Boolean)this.useLocalTransactionState.getValue() || this.session.getServerSession().inTransactionOnServer()) {
                this.session.execSQL((Query)null, "rollback", -1, (NativePacketPayload)null, false, this.nullStatementResultSetFactory, this.database, (ColumnDefinition)null, false);
            }
        }
    } catch (CJException var5) {
        throw SQLExceptionsMapping.translateException(var5, this.getExceptionInterceptor());
    }
}
  1. 方法中执行了execSQL((Query)null, “rollback”,***),去完成了回滚操作。

结论

  1. @Transactional、TransactionComponent、TransactionTemplate均可以完成在Mysql的INNODB存储引擎上的事务回滚,但不能在默认的MyISAM存储引擎完成回滚。
  2. TransactionComponent、TransactionTemplate使用方法类似,需要手动使用代码控制事务。@Transactional注解在开发上一般使用在实现类的方法上,使用方便,代码量少,粒度较显式使用会粗一点。
  3. 三种方法均需配置ResourceTransactionManager的Bean交于Spring管理事务。
  4. 开发时导出数据库建表语句建议直接显式声明其存储引擎,以防有些数据库并未设置默认引擎为INNODB。
    (修改数据库默认存储引擎:在配置文件my.cnf中的 [mysqld] 下面加入default-storage-engine=INNODB)
default-storage-engine=INNODB
  1. 可以在数据库执行sql show engines查看默认的存储引擎:

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
目录
相关文章
|
11月前
|
SQL 监控 关系型数据库
MySQL怎么全局把一张表的数据回滚
MySQL怎么全局把一张表的数据回滚
1021 2
|
25天前
|
SQL 关系型数据库 MySQL
MySQL锁机制:并发控制与事务隔离
本文深入解析了MySQL的锁机制与事务隔离级别,涵盖锁类型、兼容性、死锁处理及性能优化策略,助你掌握高并发场景下的数据库并发控制核心技巧。
|
1月前
|
存储 监控 Oracle
MySQL事务
MySQL事务具有ACID特性,包括原子性、一致性、隔离性和持久性。其默认隔离级别为可重复读,通过MVCC和间隙锁解决幻读问题,确保事务间数据的一致性和并发性。
MySQL事务
|
2月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
11天前
|
关系型数据库 MySQL 数据库
MySql事务以及事务的四大特性
事务是数据库操作的基本单元,具有ACID四大特性:原子性、一致性、隔离性、持久性。它确保数据的正确性与完整性。并发事务可能引发脏读、不可重复读、幻读等问题,数据库通过不同隔离级别(如读未提交、读已提交、可重复读、串行化)加以解决。MySQL默认使用可重复读级别。高隔离级别虽能更好处理并发问题,但会降低性能。
|
2月前
|
安全 关系型数据库 MySQL
mysql事务隔离级别
事务隔离级别用于解决脏读、不可重复读和幻读问题。不同级别在安全与性能间权衡,如SERIALIZABLE最安全但性能差,READ_UNCOMMITTED性能高但易导致数据不一致。了解各级别特性有助于合理选择以平衡并发性与数据一致性需求。
146 1
|
7月前
|
存储 SQL 关系型数据库
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log、原理、写入过程;binlog与redolog区别、update语句的执行流程、两阶段提交、主从复制、三种日志的使用场景;查询日志、慢查询日志、错误日志等其他几类日志
628 35
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
|
9月前
|
SQL 安全 关系型数据库
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
4225 56
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
|
8月前
|
SQL 关系型数据库 MySQL
MySQL事务日志-Undo Log工作原理分析
事务的持久性是交由Redo Log来保证,原子性则是交由Undo Log来保证。如果事务中的SQL执行到一半出现错误,需要把前面已经执行过的SQL撤销以达到原子性的目的,这个过程也叫做"回滚",所以Undo Log也叫回滚日志。
355 7
MySQL事务日志-Undo Log工作原理分析
|
11月前
|
存储 SQL 关系型数据库
MySQL的事务隔离级别
【10月更文挑战第17天】MySQL的事务隔离级别
264 43

推荐镜像

更多