在mysql中,常见的存储引擎有innodb、myisam,memory等。其中innodb支持事务(transaction),而myisam,memory等不支持事务。
show engines;
事务是一个不可分割的最小工作单位,事务中的操作只有成功及失败两种情况。
事务的原子性是通过 undo log 来实现。
在事务开始之前和事务结束以后,数据库的完整性没有被破坏。
通过原子性,持久性,隔离性来实现
数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
事务的隔离性是通过 (读写锁+MVCC)来实现的。
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
事务的持久性性是通过 redo log 来实现。
1、内存中重做日志缓冲 (redo log buffer),易丢失,存在内存。 2、重做日志文件 (redo log file),是持久的,保存在磁盘中
1、先修改数据,后写日志。 2、redo日志比数据页先写回磁盘。 3、聚集索引、二级索引、undo页面的修改,均需要记录Redo日志。
事务分为隐式事务和显式事务。
DML语句(insert、update、delete)就是隐式事务。 该事务没有明显的开启和结束标记,它们都具有自动提交事务的功能。
该事务具有明显的开启和结束标记; 禁用自动提交功能就是设置autocommit变量值为0【禁用】
SELECT @@autocommit;
-- 关闭自动提交
SET autocommit = 0;
-- 开启自动提交
SET autocommit = 1;
-- 开始一个事务BEGIN;
或者start transaction;
-- 提交一个事务COMMIT;
-- 回滚一个事务ROLLBACK;
SELECT @@tx_isolation;
默认隔离级别为:REPEATABLE-READ【可重复读】
允许事务读取未被其他事务提交的变更。(脏读、不可重复读和幻读的问题都会出现)
1、脏读:读取到了还未提交的数据。解决:事务隔离级别调整为读已提交。
允许读取其他事务已提交的数据。
1、不可重复读:该隔离级别内,前后读取的数据,可能不一致。
在同一个事务内,前后读取的同一条数据,内容一致。
1、幻读:一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。【快照读主要无法解决新增数据的问题】
最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰。该级别可以防止脏读、不可重复读以及幻读。
数据库并发量低,性能差。
运行时间比较长,长时间未提交的事务就可以称为长事务。
注意:Spring的声明式事务是基于动态代理实现的,如果事务是static、final的,同样无法通过动态代理,事务也是不会生效的。
如果使用MySQL且存储引擎是MyISAM,则事务是不起作用的,原因是MyIASM不支持事务。
加上@Service注解或者使用其他能注册成Spring Bean的方式或注解,使用spring容器管理,事务才能生效。
手动捕捉异常,事务不会回滚。
Propagation.NOT_SUPPORTED:不在Transaction中运行,事务无效。
不在一个线程时,获取的数据库连接可能不是同一个,处于不同事务中,此时事务无效。 需要手动创建事务,控制事务提交及回滚。
分布式事务的实现。