事务的概念
事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败.
例如A给B转钱,A扣钱,B加钱,这两个过程就构成了事务
事务的特性
- 原子性:事务不可分割
- 隔离性:一个事务执行的过程中,不应该受到其他的事务的干扰
- 一致性:一个事务执行的过程中,不应该受到其他的事务的干扰
- 持久性:事务一旦提交,数据就永久保持到数据库中
Hibernate中的高并发
读的问题
如果不考虑事务的隔离性,会引发一些读的问题
脏读:一个事务读到另一个事务未提交的数据
不可重复读:一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致.
虚读:一个事务读到了另一个事务已经提交的insert数据,导致多次查询结果不一致.
隔离级别
通过设置数据库的隔离级别来解决上述读的问题
未提交读:不能解决任何读的问题
已提交读:避免脏读,但是不可重复读,虚度都可能发生
可重复读:避免脏读,不可重复读.但是虚读是有可能发生
串行化:以上读的情况都可以避免
在Hibernate中设置隔离级别
在hibernate.cfg.xml的配置文件中通过标签hibernate.connection.isolation来配置
<property name="hibernate.connection.isolation">4</property>
取值
* 1—Read uncommitted isolation(未提交读)
* 2—Read committed isolation(已提交读)
* 4—Repeatable read isolation(可重复读)
* 8—Serializable isolation(串行化)
写的问题
如果不考虑事务的隔离性,会引发更新丢失的问题
例如:A事务和B事务同时获取一条数据,同时再做修改,A事务修改完成后,提交了事务,B再做修改提交事务,就会造成A事务的更新丢失
为了解决这个问题,引入了两种解决方案悲观锁和乐观锁
悲观锁
当一个事务操作一条记录的时候,会把这条记录锁上,其他事务不能操作这条记录,只要当这个事务提交后,锁才会被打开,其它事务才能操作改记录
Hibernate中使用
session.get(Entity.class, 1,LockMode.UPGRADE)
如果采用做了这种机制,数据库提供的一种锁机制,在SQL语句的后面添加 for update 子句
乐观锁
采用版本号的机制来解决的,会给表结构添加一个字段version=0,默认值是0
当A事务在操作完该条记录,提交事务时,会先检查版本号,如果发生版本号的值相同时,才可以提交事务。同时会更新版本号version=1
当B事务操作完该条记录时,提交事务时,会先检查版本号,如果发现版本不同时,程序会出现错误
Hibernate 中使用乐观锁
- 在对应的JavaBean中添加一个属性,名称可以是任意的,一般叫version。提供get和set方法
private Integer version
//对应的get和set方法省略
- 在映射的配置文件中,提供version标签即可
<version name="version"/>