事务的并发问题:脏读、不可重复读、幻读。
脏读:一个事务读取另一个事务未提交的数据。
不可重复读:在一个事务中,读取到另一个事务已经提交update数据,造成两次读取不一样。幻读:在一个事务中,读取到另一个事务已经提交insert数据,造成读取记录条数不一样。丢失更新:两个事务同时修改目标数据,后提交的事务,会覆盖之前提交的数据。
鉴于并发访问出现的以上问题,数据库提供了事务隔离级别:
1. READ_UNCOMMITED:会发生以上所有问题2. READ_COMMITTED:阻止脏读的发生,会发生不可重复读和幻读(Oracle默认级别)3. REPEATABLE_READ:阻止脏读和不可重复读发生,会发生幻读(MySQL默认级别)4. SERIALIZABLE:不会发生并发问题,串行初始化(性能非常差,也不会使用)
1.MySql事务操作:
1)start transaction:开始事务2)commit:提交事务
2.修改MySql事务隔离级别:
2
隔离级别对应数值:
read uncommitted isolation --- 1read committed isolation ------ 2repeatable read isolation ------ 4serializable isolation ----------- 8
丢失更新问题解决:
悲观锁和乐观锁。
2.悲观锁:
假设丢失更新发生概率很大,底层原理使用数据库内部锁的机制。
1)Mysql数据库内部提供读锁(共享锁)、写锁(排它锁 );2)一张数据表允许添加多个读锁;3)一张数据表只能添加一个写锁,其与其他锁互斥。添加了写锁则不能再添加读锁;4)默认情况下,在修改记录时,会自动添加写锁;5)在执行查询时,也可以为数据添加共享锁和排它锁select * from customer lock in share mode; 添加共享锁select * from customer for update;添加排它锁6)悲观锁使用的即是排它锁。第1个修改执行select * from customer for update,第个操作(包括查询)需要等待session提供.get(Class class, Serializable id, LockMode lockMode);
//类型,OID,锁
PojoUser user = (PojoUser) session.get(PojoUser.class, 1, LockMode.UPGRADE);
//更新操作
user.setName("XXxxx");
mysql
对应
LockMode UPGRADE
;
oracle
对应
LockMode UPGRADE_NOWAIT
。
3.乐观锁:
假设丢失更新发生概率不高,底层原理为数据添加版本号,由程序来维护版本。
1)在POJO中添加Integer version字段:
2)在POJO.hbm.xml中添加版本字段:
3)加断点在debug模式测试:
提交的版本号和数据库中版本不同则报错:
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [cn.cvu.hibernate.domain.PojoUser#3]
- end