hibernate 事务和隔离级别

本文主要是学习hibernate的数据库事务和隔离级别的设置

1、什么是数据库事务?

事务是数据库并发控制的基本单元,作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行,它具有原子性,一致性,隔离性,持久性。

2、事务并发有哪些问题?

1)第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖。

在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了。
例如:
张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5000,汇入100,并提交数据库,工资变为5100,随后事务A发生异常,回滚了,恢复张三的工资为5000,这样就导致事务B的更新丢失了。

2)脏读:一个事务读到另一事务未提交的更新数据。

是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
例如:
  张三的工资为5000,事务A中把他的工资改为8000,但事务A尚未提交。
  与此同时,
  事务B正在读取张三的工资,读取到张三的工资为8000。
  随后,
  事务A发生异常,而回滚了事务。张三的工资又回滚为5000。
  最后,
  事务B读取到的张三工资为8000的数据即为脏数据,事务B做了一次脏读。

3)虚读:一个事务读到另一事务已提交的新插入的数据。 

是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
例如:
  目前工资为5000的员工有10人,事务A读取所有工资为5000的人数为10人。
  此时,
  事务B插入一条工资也为5000的记录。
  这是,事务A再次读取工资为5000的员工,记录为11人。此时产生了幻读。

4)不可重复读:一个事务读到另一事务已提交的更新数据。

是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
例如:
  在事务A中,读取到张三的工资为5000,操作没有完成,事务还没提交。
  与此同时,
  事务B把张三的工资改为8000,并提交了事务。
  随后,
  在事务A中,再次读取张三的工资,此时工资变为8000。在一个事务中前后两次读取的结果并不致,导致了不可重复读。

5)第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一事务已提交的更新数据。

不可重复读的特例,有两个并发事务同时读取同一行数据,然后其中一个对它进行修改提交,而另一个也进行了修改提交。这就会造成第一次写操作失效。 

例如:

在事务A中,读取到张三的存款为5000,操作没有完成,事务还没提交。
  与此同时,
  事务B
,存储1000,把张三的存款改为6000,并提交了事务。
  随后,
  在事务A中,
存储500,把张三的存款改为5500,并提交了事务,这样事务A的更新覆盖了事务B的更新。

3、事务隔离级别分别解决哪些并发问题?

下面的图说明了每种事务隔离级别分别解决了哪些并发问题,注意隔离级别越高,并发性越低,所以隔离级别的选择和并发性能的需要要进行折中考虑。

4、hibernate事务隔离级别配置

在没有配置的时候,hibernate默认使用数据库的隔离级别,mysql默认的隔离级别是repeatable read。Hibernate的配置文件中可以显式的设置隔离级别。每一种隔离级别都对应一个整数:
1:Read Uncommitted
2:Read Committed
4:Repeatable Read
8:Serializable
如下的配置将hibernate的隔离级别设置为read commited方式

hibernate.connection.isolation=2

5、hibernate锁机制,悲观锁和乐观锁

1)悲观锁

悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
一个典型的依赖数据库的悲观锁调用:select * from customer where name=”lpp” for update这条 sql 语句锁定了customer表中所有符合检索条件( name=”lpp” )的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。

悲观锁,是基于数据库的锁机制实现,在Hibernate使用悲观锁十分容易,但实际应用中悲观锁是很少被使用的,因为它大大限制了并发性。设置悲观锁的代码:session.lock(LockMode.update)或者query.setlockMode(LockMode.update);

Hibernate 的加锁模式有:
a)LockMode.NONE :无锁机制。

b)LockMode.WRITE :  A WRITE lock is obtained when an object is updated or inserted.This lock mode is for internal use only and is not a valid mode for load() or lock() (both of which throw exceptions if WRITE is specified).

Hibernate 在 Insert 和 Update 记录的时候会自动获取,应用程序不会直接使用。

c)LockMode.READ :A shared lock. Objects in this lock mode were read from the database in the current transaction, rather than being pulled from a cache (注:也就是从数据库中读数据,绕过了Hibernate的Cache) 

Hibernate 在使用createQuery查找记录的时候会自动获取。

d)LockMode.UPGRADE : An upgrade lock.(注:相当于SQL语句select xxx from xxxx for update,也就是把锁的处理交给了数据库),利用数据库的 for update 子句加锁。

2)乐观锁

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。
乐观锁的工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
Hibernate为乐观锁提供了3中实现:
1. 基于version

        <!-- version标签用于指定表示版本号的字段信息 -->
        <version name="version" column="version" type="integer"></version>

2. 基于timestamp

        <!-- timestamp标签用于指定表示版本号的字段信息 -->
        <timestamp name="updateDate" column="updateDate"></timestamp>

3. 为遗留项目添加乐观锁

    <class name="com.study.hbm.User" table="user" catalog="hibernate" optimistic-lock="all" >





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值