事务控制中悲观锁与乐观锁

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sundacheng1989/article/details/89673517

事务并发可能存在的问题 

1.  在撤销事务之后,不管有没有其他人或者其他事务进行了操作,直接回到最原始的状态 

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

3. 因为其他事务的介入,使得本事务前后读取的数据不一致 

4. 不可重复读的特殊情况(先后两次读取不一样,并做了操作) 

第一种,只要支持事务就不会有这个问题。第二种,脏读,读了其他人没有提交的事务。 第三种,不可重复读,本事务又读了一次数据库,前后两次不一致。 第四种,在更新的时候,覆盖了别人的操作。 

数据库的事务隔离机制 

这是java.SQL中的transaction的隔离级别 

事务隔离机制的设置,是设置本次操作。 

  1. 如果事务设置成Transaction_none, 那么就不会有任何的事务,数据库操作不支持事务,任何操作都是各自提交的,整个操作没有原子性。 

  2. read_uncommited. 这种级别不能限制脏读的出现。 

  3. read_comminted. 没有读取到脏数据,因为另外的都是已经提交了的。但是无法解决不可重复读问题。这里没有对同一个数据加锁。 

  4. repetable_read. 可重复读。实现方式就是一条数据读出来的时候加把锁,别人不能操作。这样本次事务前后操作读取的数据都一致了。(事务级别越复杂效率越低,因为需要检查,加锁等) 

  5. Serilaziable. 序列化。所有事务都挨个运行。只要有一个事务在操作某个数据,那么其他的事务都是等着,不操作。这个最安全,但是在多并发的情况下效率最低。 

一般都设置为read-commited, 避免了脏读,并发性也很好,接下来可以用其他方法去解决不可重复读的问题。如果不在代码中明确的设置,那么默认的就是使用的数据库的事务隔离级别。如何避免了脏读?因为本次事务在读取某个数据库字段的时候,发现这个字段被其他事务占用,而且检查到其他事务还没有提交,那么本事务就会等待。 

在银行系统中,假设事务隔离机制为read_comminted,那么如何解决不可重复读的问题出现?比如说A向账户取款,先读出来1000,在操作过程中,B对账户取走了200,这时候A再取1000,则不能取出1000,因为已经没有那么多了。 

在Hibernate中,可以通过悲观锁乐观锁机制来解决这个不可重复读的问题。 为了并发的效率,隔离机制设置为read-commit,然后用悲观锁乐观锁解决重复读取的问题。 

悲观锁是借助数据库的锁。在数据库中通过语句把我们要更新的记录上一把锁。在Hinernate中,session中加第三个参数,LockMode.UPGRADE, 这样通知数据库在本事务还没有结束的时候,锁住这条记录,其他人不能操作。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。例如:  

select * from table_name where id = ‘xxx’ for update;  

乐观锁是在程序中用代码解决的。而且需要在数据库表中增加一个新的字段,叫做版本字段。一旦有人update这行记录,那么这个字段就要加1. 一个事务前后对比这个字段,就知道有没有人动过这行记录。 

为什么叫悲观为什么就乐观?悲观是对别人更新的看法很悲观,本事务拿走数据的时候觉得别人肯定会更新,所以干脆锁上了。乐观是我拿的时候乐观的认为别人不会更新,但是到时候我发现别人更新了,那么我再做出相应的处理,这个处理逻辑需要代理自己设置。乐观锁不加锁,效率高。 

SMS4.0为什么会产生死锁的现象?在调用存储过程的时候,begin关键字默认开启了一个事务。而事务可能是read-commit隔离级别,所以就是说当一个事务在占用某条数据记录的时候,它没有提交,其他的事务就会等待这条记录。而恰巧其他的事务也占用这个事务的需要的某条记录,所以相互等待,就死锁了。如果transaction设置为none,使其不支持事务,那么就不会发生死锁。但是可能发生A更新了B刚刚更新的字段。 

对于写操作,如果一个事务中更改了某条记录,那么在这个事务提交前,其他任何事务都不能更改此记录。至于能不能读,就要看另外的事务的隔离机制设置了,如果能够读脏数据,则可以读。不过不能读脏数据,则不能读。事务隔离机制,最主要说的是对于读的操作。写的话,事务没有提交,那么别的事务肯定不能写。 

SQL Server 与 Oracle的默认事务隔离机制都是read-commited, Mysql的默认隔离机制为Repeatable-read. 

Oracle数据库可能会出现重复读的现象,所以在相关业务中要考虑到这点,使用version字段。 Oracle, 本事务修改了没提交,其他事务可以读,但是修改要等待。  本事务读了没提交,其他事务可读可改,所以容易造成重复读。 其他事务随时可以读(读到的是本事务更改前的基本数据),但是改要等待。 

Oracle中,对于别人正在执行的,没有提交的数据,如果其他的人去读的话,读的是更改之前的数据。 如果去改的话,就得排队等待。 

猜你喜欢

转载自blog.csdn.net/sundacheng1989/article/details/89673517
今日推荐