阳后的第三次奔跑,感觉下降不少.继续努力;2023年工作加油,继续保持输出文档.奔跑也不能断,需要保持.向阳而立.
事务
一组数据要么成功,要么失败.保证数据最终一致性.
事务特性
事务通常具有4个属性(简称ACID)
- 原子性(Atomicity): 事务操作要么成功,要么失败.主要是通过undo log日志来实现该特性.
- 一致性(Consistent): 事务的最终目标,通过AID以及业务代码逻辑实现该特性.
- 隔离性(Isolation): 事务并发过程中不相互干扰.由MySQL锁和MVCC机制来实现该特性.
- 持久性(Durable): 事务一旦提交,改变就是永久性.由redo log日志实现该特性.
事务处理的问题
更新丢失或脏写
多个事务修改相同数据及最后事务修改了其他事务的更新操作.
脏读
事务1读到事务2已经修改但未提交的数据.
不可重复读
事务1内部相同查询在不同时间段结果不一致.
幻读
事务1读到事务2提交的新数据.
脏读与幻读的区别: 脏读是修改数据,幻读是新增数据
事务隔离级别
脏读,不可重复读,幻读.由数据库的事务隔离机制来解决.
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交(Read uncommitted) | 可能 | 可能 | 可能 |
| 读已提交(Read committed) | 不可能 | 可能 | 可能 |
| 可重复读(Repeatableread) | 不可能 | 不可能 | 可能 |
| 读已提交(Read committed) | 不可能 | 不可能 | 不可能 |
数据库的隔离级别,从上到下越来越严格.同理越严格越限制数据库的并发要求,但同时许多应用可能更关系系统的并发访问能力,不可重复读或幻读并非很关注. 查看当前数据库的隔离级别: show variables like 'tx_ioslation';
MySQL 事务默认是可重复读.(spring开发如果定义了isolation,就已定义的为准,否则就是数据库默认的隔离级别)
隔离验证
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(500) NOT NULL,
`age` tinyint(1) NOT NULL,
PRIMARY KEY (`id`,`username`),
UNIQUE KEY `idx_name` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `users` (`id`, `username`, `password`, `age`) VALUES ('1', 'zhangsan', '123', '1');
INSERT INTO `users` (`id`, `username`, `password`, `age`) VALUES ('2', 'lisi', '1234', '4');
INSERT INTO `users` (`id`, `username`, `password`, `age`) VALUES ('3', 'wangwu', '12345', '5');
读未提交
两个编辑器操作都设置为read-uncommitted隔离级别 其中操作A修改年龄age=3,但未提交
-- 读未提交,修改年龄age=3
set tx_isolation='read-uncommitted';
BEGIN;
update users SET age = 3 WHERE id = 1;
COMMIT;
另一个操作B直接查询,就查询到了未提交的数据
-- 读未提交
set tx_isolation='read-uncommitted';
BEGIN;
SELECT * FROM users;
COMMIT;
但此时,如若操作A回滚,则所有操作都会撤销.操作B查询的数据就是脏数据.解决问题的方式就需要更新隔离级别为读已提交
读已提交
两操作同时设置读已提交 read-committed
操作A查询
-- 读已提交
set tx_isolation='read-committed';
BEGIN;
SELECT * FROM users;
COMMIT;
操作B修改
但数据未提交
再次执行操作A,数据未变化.由于B未提交数据,故未查询到数据.解决脏读问题
数据B提交 再进行操作A查询会产生两次一样的查询,可结果不一致.出现不可重复读问题
可重复读
可重复读同上操作. 语句设置如下:
-- 可重复读
set tx_isolation='repeatable-read';
begin;
select * from users;
commit;
结果: 两者操作互不影响.可重复读隔离级别使用MVCC(Multi-version concurrency control)多版本并发控制,select 查询的是读取快照数据;insert update delete 当前读.
查询是否需要事务?
1:单条SQL查询不需要。
2:如果需要执行多条sql查询来合成最终的统计结果,就可以利用事务隔离级别保证数据查询的一致性。(如若不需要已执行,同1)
结果:建议多条sql查询(针对可重复读RR),设置只读事务(readOnly=true)还是有必要的