MySql事务无法回滚的原因

本文深入探讨了MySQL中事务无法回滚的问题,指出可能的原因在于表类型的选择不当。通过对比InnoDB与MyISAM这两种最常见的表类型,文章详细阐述了它们的区别,包括性能、功能支持及特定场景下的优劣。此外,文章提供了关于如何选择合适表类型以优化数据库性能的指导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用MySQL时,如果发现事务无法回滚,但Hibernate、Spring、JDBC等配置又没有明显问题时,不要苦恼,先看看MySQL创建的表有没有问题,即表的类型。

InnoDB和MyISAM是在使用MySQL最常用的两个表类型,各有优缺点,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。

MyIASM是IASM表的新版本,有如下扩展:

     二进制层次的可移植性。

     NULL列索引。

     对变长行比ISAM表有更少的碎片。

     支持大文件。

     更好的索引压缩。

     更好的键吗统计分布。

     更好和更快的auto_increment处理。


以下是一些细节和具体实现的差别:

1. InnoDB不支持FULLTEXT类型的索引。

2. InnoDB中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count(*)语句包含where条件时,两种表的操作是一样的。

3. 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引。

4. DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。

5. LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用。

另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”

任何一种表都不是万能的,只用恰当的针对业务类型来选择合适的表类型,才能最大的发挥MySQL的性能优势。


在MySQL 5.0里面,MyISAM和InnoDB存储引擎性能差别并不是很大,针对InnoDB来说,影响性能的主要是 innodb_flush_log_at_trx_commit 这个选项,如果设置为1的话,那么每次插入数据的时候都会自动提交,导致性能急剧下降,应该是跟刷新日志有关系,设置为0效率能够看到明显提升,当然,同样你可以SQL中提交“SET AUTOCOMMIT = 0”来设置达到好的性能。另外,还听说通过设置innodb_buffer_pool_size能够提升InnoDB的性能,但是我测试发现没有特别明显的提升。

基本上我们可以考虑使用InnoDB来替代我们的MyISAM引擎了,因为InnoDB自身很多良好的特点,比如事务支持、存储过程、视图、行级锁定等等,在并发很多的情况下,相信InnoDB的表现肯定要比MyISAM强很多,当然,相应的在my.cnf中的配置也是比较关键的,良好的配置,能够有效的加速你的应用。

### 如何在 MySQL 中实现事务回滚MySQL 数据库中,可以通过 `ROLLBACK` 命令来撤销当前事务中的所有更改。这使得可以恢复到事务开始之前的状态[^1]。 #### 设置隔离级别并启动事务 为了确保数据的一致性和准确性,在执行任何可能影响多行记录的操作前,建议设置合适的事务隔离级别: ```sql SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; START TRANSACTION; ``` 上述命令设置了最严格的串行化隔离级别,并开启了新事务[^2]。 #### 执行查询语句 在此之后可安全地运行各种 DML (Data Manipulation Language) 操作,比如 SELECT ... FOR UPDATE 来锁定特定行防止其他会话修改它们: ```sql SELECT * FROM t1 FOR UPDATE; ``` #### 处理异常情况下的自动回滚 如果希望在遇到 SQL 错误或警告时自动触发回滚,则可以在存储过程内声明退出处理器: ```sql DECLARE EXIT HANDLER FOR SQLEXCEPTION ROLLBACK; DECLARE EXIT HANDLER FOR SQLWARNING ROLLBACK; ``` 这些指令会在发生错误或警告的情况下立即终止程序流并将控制权返回给调用者的同时完成回滚操作[^4]。 #### 显式发出回滚命令 如果不满足条件或者决定不提交所做的变更,那么应该显式地调用 `ROLLBACK` : ```sql -- 当不想保存所做的改变时使用此命令 ROLLBACK; ``` 值得注意的是,一旦发出了 `COMMIT` 或者 `ROLLBACK` ,就意味着结束了当前的事务;因此每次都需要重新开启一个新的事务才能继续进行后续的数据操纵活动[^3]。 #### Python 示例:通过 PyMySQL 库管理事务 下面是一个简单的例子展示了如何利用 Python 的PyMySQL库来进行数据库连接以及处理事务: ```python import pymysql.cursors connection = pymysql.connect( host='localhost', user='user', password='passwd', database='db', cursorclass=pymysql.cursors.DictCursor) try: with connection.cursor() as cursor: sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)" cursor.execute(sql, ('webmaster@python.org', 'very-secret')) # 提交更改 connection.commit() finally: connection.close() # 如果需要回滚则替换 commit() 方法为 rollback(): # connection.rollback() ``` 在这个脚本里,每当创建了新的游标对象时就会隐含地开始了新的一次事务。而无论是调用了 `commit()` 还是 `rollback()` 都意味着结束该事务并且释放资源以便下一次循环能够正常工作。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值