如何避免脏读,幻读?避免下单重复问题

TRANSACTION_REPEATABLE_READ  可以防止脏读和不可重复读,         TRANSACTION_SERIALIZABLE  可以防止脏读,不可重复读取和幻读,(事务串行化)会降低数据库的效率  以上的五个事务隔离级别都是在Connection接口中定义的静态常量

使用setTransactionIsolation(int level) 方法可以设置事务隔离级别。         如:con.setTransactionIsolation(Connection.REPEATABLE_READ);  注意:事务的隔离级别受到数据库的限制,不同的数据库支持的的隔离级别不一定相同

一、脏读:

一个事务读取到了另外一个事务没有提交的数据

 事务1:更新一条数据

------------->事务2:读取事务1更新的记录

事务1:调用commit进行提交

***此时事务2读取到的数据是保存在数据库内存中的数据,称为脏读。

***读到的数据为脏数据

详细解释:脏读就是指:当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

解决:

修改时加排他锁,直到事务提交后才释放

读取时加共享锁,读取完释放事务1读取数据时加上共享锁后(这 样在事务1读取数据的过程中其他事务就不会修改该数据),不允许任何事物操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更 无权参与进来读写,这样就防止了脏读问题。

       但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改 完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。


二、 不可重复读/ 幻读 :

不可重复读:在同一事务中,两次读取同一数据,得到内容不同

            事务1:查询一条记录

                            -------------->事务2:更新事务1查询的记录

                            -------------->事务2:调用commit进行提交

            事务1:再次查询上次的记录


            ***此时事务1对同一数据查询了两次,可得到的内容不同,称为不可重复读

幻读:同一事务中,用同样的操作读取两次,得到的记录数不相同

            事务1:查询表中所有记录

                              -------------->事务2:插入一条记录

                              -------------->事务2:调用commit进行提交

            事务1:再次查询表中所有记录

取数据时加共享锁数据时加排他锁,都是事务提交释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题

三、下单重复

为了避免在同一时间的2个请求生成2个订单,可以通过Redis缓存一个lockkey生成一个锁。基本思路为:

在开始创建订单前,在redis中缓存一个由客户号clientId+投资顾问adviserId+名下产品productId的 lockey值,创建订单完成后,删除该lockkey值。这样,每次创建订单先查询 该 “客户号clientId+投资顾问adviserId+名下产品productId” 对应的lockey值在缓存中是否存在,如果存在说明有正在创建中的订单,直接返回。

相应的lockService实现如下:

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容