数据库的四大特性以及不同隔离级别

2022年9月2日12:17:32

数据库的四大特性
原子性(要么全部成功,要么全部失败);
一致性(数据执行前后,保持一致);
隔离性(互不影响,就是所谓的隔离级别);
持久性(已经提交的事务,对于数据库中数据的改变是永久性的,即使数据库发生故障也不能丢失已提交事务所完成的改变;)

数据库的隔离级别由低到高的顺序:
未提交读 (Read Uncommitted) ;
提交读 (Read Committed) ;
可重复读 (Repeated Read) ;
串行化(Serializab);

四种隔离级别介绍:
未提交读:
一个事务可以读取另一个未提交事务的数据;(因为事务未提交,所以数据不准确 出现“脏读”)

提交读:
一个事务要等另一个事务提交后才能读取数据。(并发情况下 两个事务同时操作同一条数据,导致数据被覆盖;造成“不可重复读”)

可重复读:
一个事务中,查询的行被加上 共享锁,加了共享锁的行 可以被多个事务查询 但是不能修改;修改的行加上排他锁,其他事务不能查看也不能修改;(解决了“不可重复读“,但是会造成”幻读“)

串行化:
事物a 执行读写操作时,会锁定检索的数据行范围(范围锁),这种锁会阻止其他事物在本范围内的一切操作,
只有事物a执行完毕,提交事物后,才会释放范围锁,这样就避免了幻读。(统计时,发生增、删的情况 )

MYSQL 默认隔离级别 可重复读 (Repeated Read) ;
SQLSERVICE\ORACLE 默认隔离级别 提交读 (Read Committed) ;

--------------并发问题
user1 更新的数据丢失了,这也是更新覆盖,比如用户转账的操作。a 账户总共1000,事务1和事务2查询账户都是1000,然后事务1账户扣减100,提交。事务2扣减800提交。这时候账户余额为200,事务1扣减的100 会不翼而飞,这会导致严重的问题。

MYSQL 不会出现这种情况,SQLSERVICE\ORACLE 会出现这种情况;
解决办法1:使用悲观锁

1)读取锁定 --> select balance from account where user= ‘a’ for update

2)更新 --> update account set balance = balance -100 where user= ‘a’

解决办法2: 使用乐观锁

1)表增加字段 jpa_version int 版本号 --> select balance,version from account where user= ‘a’

2) 使用版本号更新 --> update account set balance = balance -100 where user= ‘a’ and jpa_version = ${version}

总结:

对于账户交易建议直接使用悲观,数据库的性能很高,并发度不是很高的场景两者性能没有太大差别。如果是交易减库存的操作可以考虑乐观锁,保证并发度。

作者:h_f7e8
链接:https://www.jianshu.com/p/3fcba1c04ddf
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 作者:我为offer而来
  • 原文链接:https://blog.csdn.net/weixin_43854111/article/details/122347545
    更新时间:2022年9月2日12:17:32 ,共 1227 字。