MySql中无法回滚的原因及解决办法

今天在编写程序的时候进行了回滚操作,程序运行正常,但是数据库并没有进行回滚操作。百度后发现自己创建的表类型是MyISAM,不支持事务操作,后改为InnoDB即能进行回滚操作。下面简单介绍两种数据表类型以及更改数据库类型为InnoDB的操作。

一 MySql支持的数据引擎

  • MyISAM:默认的MySQL插件式存储引擎,它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。
  • InnoDB:用于事务处理应用程序,具有众多特性,包括ACID事务支持。
  • BDB:可替代InnoDB的事务引擎,支持COMMIT、ROLLBACK和其他事务特性。
  • Memory:将所有数据保存在RAM中,在需要快速查找引用和其他类似数据的环境下,可提供极快的访问。
  • Merge:允许MySQL DBA或开发人员将一系列等同的MyISAM表以逻辑方式组合在一起,并作为1个对象引用它们。对于诸如数据仓储等VLDB环境十分适合。
  • Archive:为大量很少引用的历史、归档、或安全审计信息的存储和检索提供了完美的解决方案。
  • Federated:能够将多个分离的MySQL服务器链接起来,从多个物理服务器创建一个逻辑数据库。十分适合于分布式环境或数据集市环境。
  • Cluster/NDB:MySQL的簇式数据库引擎,尤其适合于具有高性能查找要求的应用程序,这类查找需求还要求具有最高的正常工作时间和可用性。
  • Other:其他存储引擎包括CSV(引用由逗号隔开的用作数据库表的文件),Blackhole(用于临时禁止对数据库的应用程序输入),以及Example引擎(可为快速创建定制的插件式存储引擎提供帮助)。

二 MyISAM引擎和InnoDB引擎的基本差别

  • MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。
  • MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
  • MyIASM是IASM表的新版本,有如下扩展:二进制层次的可移植性、NULL列索引、对变长行比ISAM表有更少的碎片、支持大文件、更好的索引压缩等
  • InnoDB不支持FULLTEXT类型的索引
  • InnoDB 中不保存表的具体行数
  • 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中,可以和其他字段一起建立联合索引
  • DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除
  • MyISAM:这个是默认类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的 顺序访问方法) 的缩写,它是存储记录和文件的标准方法.与其他存储引擎比较,MyISAM具有检查和修复表格的大多数工具. MyISAM表格可以被压缩,而且它们支持全文搜索.它们不是事务安全的,而且也不支持外键。如果事物回滚将造成不完全回滚,不具有原子性。如果执行大量 的SELECT,MyISAM是更好的选择。 
  • InnoDB:这种类型是事务安全的.它与BDB类型具有相同的特性,它们还支持外键.InnoDB表格速度很快.具有比BDB还丰富的特性,因此如果需要一个事务安全的存储引擎,建议使用它.如果你的数据执行大量的INSERT或UPDATE,出于性能方面的考虑,应该使用InnoDB表

三 更改数据库类型为InnoDB的操作

1 首先看数据库是否支持InnoDB,不支持的话,具体操作可看我上篇关于Sqlyongl安装出现问题的解决办法的博客。

数据库中查看是否支持InnoDB引擎的sql语句SHOW ENGINES; 


2  查看数据表的类型:

 sql语句:

 SHOW TABLE STATUS LIKE 'tbl_name';
 SHOW CREATE TABLE tbl_name;

3 更改数据表类型

sql语句: alter table tablename type=innodb;

在SqlYong中可直接修改:点击一个表名,右键,Alter table-Advanced Properties-Type-InnoDB-OK即可。(如果没有找到InnoDB,说明数据库不支持InnoDB引擎,则回到第一步重新操作)。


完成上面以后此数据库就能支持事务操作了。

感谢这两篇博客参考:【http://blog.sina.com.cn/s/blog_6ac4c6cb01018pb1.html】

               【http://blog.csdn.net/do_bset_yourself/article/details/51103373】



<think>嗯,用户问的是数据库锁表的解决办法原因。这个问题我之前学过一些,但可能需要仔细回忆一下相关知识。首先,我需要明确什么是锁表,为什么会发生,然后才能想到解决办法。 数据库锁表,应该是指某个事务长时间占用表资源,导致其他操作被阻塞的情况。锁通常分为行锁和表锁,行锁只锁定某一行,而表锁会锁定整个表。如果发生表锁,可能很多操作都无法进行,比如查询、更新等,影响系统性能。 那锁表的原因可能有哪些呢?比如,事务处理时间过长,比如一个事务中有大量数据操作,没有及时提交或回滚,导致锁一直存在。或者,有提交的事务,比如程序在执行业务逻辑时出现异常,没有正确关闭事务,导致锁被释放。还有可能是死锁,不同事务互相等待对方释放锁,导致都无法继续执行。另外,数据库的隔离级别设置过高,比如使用可重复读(Repeatable Read)或序列化(Serializable),可能会增加锁的范围和时间,从而更容易出现锁表的情况。 解决办法的话,首先要找到导致锁表的原因。可以通过数据库提供的工具查看当前的锁状态,比如MySQL的SHOW ENGINE INNODB STATUS命令,或者查询information_schema库中的INNODB_TRX、INNIB_LOCKS等表。如果是长时间运行的事务,可以考虑优化事务,减少事务执行时间,或者拆分成小事务。对于提交的事务,需要检查程序代码,确保事务及时提交或回滚,尤其是在异常处理中。如果是死锁,数据库通常会自动检测并回滚其中一个事务,但可能需要优化应用逻辑,调整事务的执行顺序,以减少死锁的可能性。调整隔离级别到较低的级别,比如读已提交(Read Committed),也可以减少锁的持有时间。另外,合理使用索引,避免全表扫描,因为全表扫描可能会导致锁升级为表锁。在必要时,可以手动杀死导致锁表的会话进程,但需要谨慎操作,避免影响其他正常操作。 可能需要提醒用户,不同的数据库系统(如MySQL、PostgreSQL、Oracle)在锁机制和解决方法上可能有所不同,具体操作需要参考对应数据库的文档。还有,预防锁表的发生比事后处理更重要,应该在设计和编码阶段就考虑事务的合理使用和优化。 不过,可能我有没有遗漏的地方?比如,是否还有其他原因,比如数据库设计不合理,比如缺少必要的索引,导致查询需要锁定整个表?或者某些特定的操作,比如ALTER TABLE会锁定表?这时候可能需要考虑在业务低峰期执行这类DDL操作。另外,使用行级锁的数据库(如InnoDB)通常比表级锁(如MyISAM)更少出现锁表问题,所以存储引擎的选择也可能影响锁表的频率。 总结下来,锁表的原因包括长事务、提交事务、死锁、高隔离级别、全表扫描等。解决办法需要根据具体原因进行处理,包括优化事务、及时提交、调整隔离级别、使用索引、手动终止会话等。同时,预防措施也很重要,比如合理设计事务,使用合适的存储引擎,避免在高峰时期执行DDL等。</think>以下是数据库锁表问题的原因及解决方法,按优先级分步说明: === 锁表原因 === 1. **长事务阻塞** - 提交的事务长时间占用锁(如忘记提交/回滚) - 例:`BEGIN; UPDATE table SET ... WHERE ...;` 执行COMMIT 2. **死锁循环** - 事务A持有锁1请求锁2,事务B持有锁2请求锁1 - 数据库自动检测后会回滚其中一个事务 3. **锁升级机制** - 行锁数量超过阈值时自动升级为表锁(如SQL Server) 4. **DDL操作冲突** - ALTER TABLE等结构变更操作会获取元数据锁 - 与长时间运行的查询冲突时形成阻塞 5. **全表扫描加锁** - 走索引的查询可能升级为表级锁(如MyISAM引擎) === 排查方法 === 1. **MySQL示例** ```sql -- 查看当前锁状态 SHOW ENGINE INNODB STATUS; -- 查询阻塞进程 SELECT * FROM information_schema.INNODB_TRX WHERE trx_state = 'LOCK WAIT'; ``` 2. **SQL Server示例** ```sql -- 查看阻塞链 SELECT session_id AS SPID, blocking_session_id AS BlkBy, command, wait_type, wait_time FROM sys.dm_exec_requests WHERE blocking_session_id > 0; ``` === 解决方案 === 1. **应急处理** ```sql -- 终止阻塞进程(谨慎操作) KILL [session_id]; ``` 2. **事务优化** - 将大事务拆分为小批量操作 ```sql -- 分页更新示例 WHILE EXISTS(SELECT 1 FROM table WHERE condition) BEGIN UPDATE TOP(1000) table SET column = value WHERE condition; COMMIT; END ``` 3. **索引优化** - 为WHERE条件列添加组合索引 - 避免`SELECT *`,减少锁覆盖范围 4. **隔离级别调整** ```sql -- 使用读已提交隔离级别 SET TRANSACTION ISOLATION LEVEL READ COMMITTED; ``` 5. **DDL操作规范** - 使用ONLINE DDL(MySQL 5.6+) ```sql ALTER TABLE table_name ADD COLUMN new_column INT, ALGORITHM=INPLACE, LOCK=NONE; ``` 6. **锁超时设置** ```sql -- 设置锁等待超时(单位:秒) SET innodb_lock_wait_timeout = 30; ``` === 预防措施 === 1. 事务代码模板强制包含异常处理: ```java try { conn.setAutoCommit(false); // 业务操作 conn.commit(); } catch (Exception e) { conn.rollback(); } finally { conn.close(); } ``` 2. 监控预警配置项: - 长事务阈值:执行时间 > 5s - 锁等待阈值:等待时间 > 3s 3. 架构层面: - 读写分离架构分流压力 - 热点数据采用Redis缓存 不同数据库处理差异对比: | 特性 | MySQL(InnoDB) | PostgreSQL | Oracle | |--------------|---------------------|--------------------|------------------| | 默认锁粒度 | 行级锁 | 行级锁 | 行级锁 | | 锁升级机制 | 无 | 无 | 有 | | 死锁检测 | 自动检测+回滚 | 自动检测+回滚 | 自动检测+回滚 | | 在线DDL | 支持(5.6+) | 部分支持 | 支持 | 建议开发规范: 1. UPDATE/DELETE语句必须带索引条件 2. 事务内操作行数不超过5000行 3. 批量操作使用LIMIT分批次提交 4. 避免业务高峰期执行统计查询
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值