事务的并发问题:脏读、不可重复读、幻读。
脏读:一个事务读取另外一个事务未提交的数据。
不可重复读:在一个事务中,读取到另外一个事务已经提交update数据,形成两次读取不同。
幻读:在一个事务中,读取到另外一个事务已经提交insert数据,形成读取记录条数不同。
丢失更新:两个事务同时修改目标数据,后提交的事务,会覆盖以前提交的数据。 java
鉴于并发访问出现的以上问题,数据库提供了事务隔离级别:
1. READ_UNCOMMITED:会发生以上全部问题
2. READ_COMMITTED:阻止脏读的发生,会发生不可重复读和幻读(Oracle 默认级别)
3. REPEATABLE_READ:阻止脏读和不可重复读发生,会发生幻读(MySQL 默认级别)
4. SERIALIZABLE:不会发生并发问题,串行初始化(性能很是差,也不会使用)
mysql
1)start transaction:开始事务
2)commit:提交事务
sql
<hibernate-configuration> <session-factory> <!-- 修改事务隔离级别 --> <property name="hibernate.connection.isolation">2</property>
隔离级别对应数值:
read uncommitted isolation --- 1
read committed isolation ------ 2
repeatable read isolation ------ 4
serializable isolation ----------- 8 数据库
丢失更新问题解决:
悲观锁和乐观锁。 session
假设丢失更新发生几率很大,底层原理使用数据库内部锁的机制。 并发
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);
oracle
//类型,OID,锁 PojoUser user = (PojoUser) session.get(PojoUser.class, 1, LockMode.UPGRADE); //更新操做 user.setName("XXxxx");mysql 对应 LockMode UPGRADE ;
假设丢失更新发生几率不高,底层原理为数据添加版本号,由程序来维护版本。 app
提交的版本号和数据库中版本不一样则报错: dom
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [cn.cvu.hibernate.domain.PojoUser#3]
- end
性能