数据库的四大特性
隔离性(Isolation)
持久性(Durability)
一致性(Consistency)
原子性(Atomicity)
独持一原(idca):一致性 是说事务结束后不能破坏数据库原有的约束。
事务四大特性? 独持一原(idca)
隔离性(Isolation): 如果2个事务 T1 和 T2 同时运行,事务 T1 和 T2 最终的结果是相同的,不管 T1和T2谁先结束。
持久性(Durability): 一旦事务提交,不管发生什么(崩溃或者出错),数据要保存在数据库中。
一致性(Consistency): 只有合法的数据(依照关系约束和函数约束)才能写入数据库。
原子性(Atomicity): 事务要么全部完成,要么全部取消。 如果事务崩溃,状态回到事务之前(事务回滚)。
事务四大隔离级别
1.Read Uncommitted(读取未提交‘内容’)
事务2中 第二次读count得到的值和第一次读count得到的值不一样(因为事务1新增了一条数据),这叫幻读,不隔离新增的数据。
事务2中 第一次读aa 和第二次读aa得到的值是不一样的(事务1未提交),对最新版本的值可见,不隔离已经存在的数据。 不可以重复读,读到的数据是不一样的。
如果此时事务1因为其他原因回滚了,事务2第二次读到的数据是无意义的,因为修改没有发生(回滚了),这叫脏读 。
3.Read Committed(读取已提交‘内容’)
这是大多数数据库系统的默认隔离级别Oracle、PostgreSQL、SQL Server默认模式。
事务2中 第二次读count得到的值和第一次读count得到的值不一样(因为事务1新增了一条数据),这叫幻读,不隔离新增的数据。
事务2中 第一次读aa 和第二次读aa得到的值是不一样的,对刚提交的值可见,不隔离已经存在的数据。 不可以重复读,读到的数据是不一样的(如果成功修改)。
2.Repeatable Read(可重读)
这是MySQL的默认事务隔离级别
事务2中 第二次读count得到的值和第一次读count得到的值不一样(因为事务1新增了一条数据),这叫幻读,不隔离新增的数据。
事务2中 第一次读aa 和第二次读aa得到的值是一样的,对刚更新的值不可见,隔离已经存在的数据。 可以重复读,读到的数据都是一样的。
4.Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
数据库事务存在的问题
1.脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。当危机提交的事务出现异常回滚,那么对于第一个事务中读到的数据就是脏数据。还没提交的操作被读到了
2.不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。再次读,值变了(update、del)
3,虚读(幻读)
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(insert)(比如数据的个数)。
四种隔离级别能解决的问题
美团事务隔离级别
https://tech.meituan.com/2014/08/20/innodb-lock.html
mysql的隔离级别是怎么实现的
mvcc(多版本并发控制) + lock
mysql可重复的能解决 幻读问题么?
使用 行锁 + 间隙锁 可以部分解决
如图所示,InnoDB使用的是聚集索引,teacher_id身为二级索引,就要维护一个索引字段和主键id的树状结构(这里用链表形式表现),并保持顺序排列。
Innodb将这段数据分成几个个区间
(negative infinity, 5],
(5,30],
(30,positive infinity);
update class_teacher set class_name=‘初三四班’ where teacher_id=30;不仅用行锁,锁住了相应的数据行;同时也在两边的区间,(5,30]和(30,positive infinity),都加入了gap锁。这样事务B就无法在这个两个区间insert进新数据。
update class_teacher set class_name=‘初一一班’ where teacher_id=20; 间隙锁的是(5,30]
insert into class_teacher values (null,‘初三五班’,40); 在间隙之外,索引就锁不住
如果使用的是没有索引的字段,比如update class_teacher set teacher_id=7 where class_name=‘初三八班(即使没有匹配到任何数据)’,那么会给全表加入gap锁。同时,不能经过MySQL Server过滤自动解除不满足条件的锁,因为没有索引,则这些字段也就没有排序,也就没有区间。除非该事务提交,否则其它事务无法插入任何数据。
select加锁么?
Serializable这个级别很简单,读加共享锁,写加排他锁,读写互斥。使用的悲观锁的理论,实现简单,数据更加安全,但是并发能力非常差。如果你的业务并发的特别少或者没有并发,同时又要求数据及时可靠的话,可以使用这种模式。
这里要吐槽一句,不要看到select就说不会加锁了,在Serializable这个级别,还是会加锁的!