一、数据库四大特性
简称 | 特性 | 说明 |
A | 原子性 | 整个事务中的所有操作要么全部成功执行,要么全部失败后回滚到开始处 |
C | 一致性 | 数据库总是应该从一个一致性状态转为另一个一致性状态 |
I | 隔离性 | 一个事务所做出的操作在提交之前,是否能为其它事务可见;隔离有有四个级别,隔离性最低,安全性最低,并发性最高,隔离性最高,安全性最高,但是并发性就最低。 |
D | 持久性 | 事务一旦提交,其所做出的修改会永久保存 |
二、数据库四种隔离
1、未提交读(Read uncommitted)--->脏读
原理:(读时不加锁;改时加行共享锁)事务在读数据的时候并未对数据加锁。事务在修改数据的时候只对数据增加行级共享锁。
问题:下表事务一共查询了两次,在两次查询的过程中,事务二对数据进行了修改,并未提交(commit)。但是事务一的第二次查询查到了事务二的修改结果。在数据库的读现象浅析中我们介绍过,这种现象我们称之为脏读。
事务1 | 事务2 |
select age from users where id=1;//20 | |
update users set age=21 where id=1; | |
select age from users where id=1;//21 | |
rollback; |
2、提交读(Read committed)--->不可重复读
读已提交,即在一个事务修改数据过程中,如果事务还没提交,其他事务不能读该数据。
原理:(读时加行共享锁,读后释放;改时加行排他锁,事务结束释放)事务对当前被读取的数据加行级共享锁(当读到时才加锁),一旦读完该行,立即释放该行级共享锁;事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁,直到事务结束才释放。
问题:如下表,保证了读到的任何数据都是提交的数据,避免了脏读(dirty reads)。但是不保证事务重新读的时候能读到相同的数据,因为在每次数据读完之后其他事务可以修改刚才读到的数据。即不可重复读。
事务1 | 事务2 |
select * from users where id=1;//20 | |
update users set age=21 where id=1; commit; | |
select * from users where id=1;//21 commit; |
3、可重复读(Repeatable reads)--->幻读
原理:(读时加行共享锁,事务结束释放;改时加行排他锁,事务结束释放)事务在读取某数据的瞬间(就是开始读取的瞬间),必须先对其加行级共享锁,直到事务结束才释放;事务在更新某数据的瞬间(就是发生更新的瞬间),必须先对其加行级排他锁,直到事务结束才释放。
问题:如下表,事务一的第一次查询条件是age between 10 and 30;如果这是有10条记录符合条件。这时给这10条记录增加行级共享锁,任何其他事务无法更改这10条记录。事务二向表中插入一条数据,新增的记录并没有能力加锁,所以该操作可以顺利执行。事务一再次执行查询,这时有11条,比刚才多1条,造成的幻读。
事务1 | 事务2 |
select * from users where age between 10 and 30;//10个 | |
insert into users(name,age) values ('herry',29); commit; | |
select * from users where age between 10 and 30;//11个 |
4、串行读/可序列化(Serializable)
原理:(读时加表共享锁,事务结束释放;写时表排他锁,事务结束释放)事务在读取数据时,必须先对其加表级共享锁,直到事务结束才释放;事务在更新数据时,必须先对其加表级排他锁,直到事务结束才释放。
事务1读取A表时,事务2只能读A表,不可增删改;事务1在改A表时,事务2对A表的增删改查都不可以。
问题:(1)无法读取其它事务已修改但未提交的记录。(2)在当前事务完成之前,其它事务不能修改目前事务已读取的记录。(3)在当前事务完成之前,其它事务所插入的新记录,其索引键值不能在当前事务的任何语句所读取的索引键范围中。
总结:级别由低而高,最高级别是串行化。隔离性越来越好,但是并发性也就越来越低。mysql数据库默认是第三隔离级别REPEATABLE-READ,其他数据库一般默认第二级别READ-COMMITTED,所以mysql建议也修改为第二级别的READ-COMMITTED。
三、事务ACID+4种隔离的详细操作
启动事务:start transaction;
提交事务:commit;
回滚事务:rollback;
查看自动提交功能参数:select @@autocommit;
关闭自动提交功能:set @@session.autocommit=0;
查看当前会话级定义的事务隔离级别:select @@session.tx_isolation;//四种:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE
设置隔离级别为READ-UNCOMMITTED:set @@session.tx_isolation="READ-UNCOMMITTED";
更详细的操作相见:数据库之事务控制和隔离级别