读书人

Oracle培训(三十九)Hibernate第

发布时间: 2012-11-23 00:03:43 作者: rapoo

Oracle培训(三十九)——Hibernate第五章知识点总结——第五章--事务管理

Oracle培训(三十九)——Hibernate第五章知识点总结——第五章--事务管理

高级映射回顾

组件映射

继承映射

每张表一个类层次、每张表一个子类、每个类一张表

值类型集合映射

Set/Bag/idBag/List/Map

sort/order-by

目标

理解事务的概念及特性

理解并应用事务隔离级别

掌握Hibernate事务API

掌握乐观锁和悲观锁的应用

知识点预览

数据库事务

Hibernate事务

数据库事务

1. 了解数据库事务

a) 数据库事务组合了数据库访问操作。

b) 一个事务要被确保以两种方式终止:提交或回滚。

c) 为了在事务内执行所有的数据库操作,必须标记这个工作单的范围,必须启用事务,在某个时间提交变化。如果出现错识,必须回滚事务,保留数据的一致状态。

2. 事务管理概述

a) 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)一起称为ACID标准。

b) Atomicity:一个事务中包含的所有都是一个不可分割的工作单元。

c) Consistency:只有合法的数据可以被写入数据库,如果有任何违例(比如数据与字段类型不符),事务应该将其回滚到最初状态。

d) Isolation:事务允许多个用户对同一数据的并发访问,而不破坏数据的正确性和完整性,同时并行事务的修改和其他并行事务的修改相互独立。

e) Durability:一旦事务被提交之后,处理结果被固化(保存到可掉电存储器上)。

3. 事务隔离问题

a) 脏读(Dirty read)如果一个事务读取另一个事务没有提交的数据。

b) 不可重复读(Unrepeatable read)一个事务再次读取之前曾读取的数据,两次读取结果不一样。

c) 幻读(Phantom read)一个事务执行一个查询两次,并且第二个结果集包括第一个结果集中不存在的记录。

4. 事务隔离级别

a) 未提交读(Read uncommitted)允许脏读取,但不允许丢失更新

b) 提交读(Read committed)不会读到另一个并行事务已修改但未提交的数据,避免“脏读”,此隔离级别是大多数主流数据库默认隔离级别,同时也适用于大多数应用系统。

c) 可重复读(Repeatable read)一个事务不可能更新已经由另一个事务读取但未提交的数据,避免不可重复读取和脏读取

d) 串行读(Serializable)最严格的事务隔离,要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行

e) 隔离级别

Oracle培训(三十九)——Hibernate第五章知识点小结——第五章-事务管理

f) 4种隔离级别严密程度又前往后依次递增,同时其性能也依次下降,因此采取最高性能隔离级别并不可取,我们需根据实际情况进行取舍,以获得数据合法性和系统性能上最佳平衡。

5. 选择隔离级别

a) 首先排除”未提交读”隔离级别

b) 绝大部分应用都无须使用“序列化”隔离(一般来说,读取幻影数据并不是一个问题),此隔离级别也难以测量(scale poorly)

c) 可重复读隔离级别,消除一个事务在另外一个并发事务过程中覆盖数据的可能性

6. 设置隔离级别

a) 隔离级别值

1 读取未提交隔离

2 读取提交隔离

4 可重复读隔离

8 串行读隔离

b) Hibernate在配置文件中设置隔离级别

c) Hibernate不会改变从应用服务器获取的数据库连接的隔离级别

7. 设置隔离级别—配置文件

<!-- 设置隔离层次,控制事务的并发,缺省时Read Committed: 2 -->

<property name="connection.isolation">2</property>

Hibernate事务

1. Hibenrate是JDBC的轻量级封装,本身并不具备事务管理能力,因此在事务管理层Hibernate将其委托给底层的JDBC或者JTA,以实现事务的管理与调度;

2. 底层事务实现方式定义在Hibernate配置文件中,Hibernate默认事务处理机制基于JDBCTransaction。

3. 事务实现方式—配置文件

<!-- 配置事务 -->

<!-- 非管理环境:桌面应用,tomcat环境,可以不写 -->

<property name="transacton.factory_class">

org.hibernate.transaction.JDBCTransactionFactory

</property>

<!-- 管理环境,JTA事务 -->

<!-- property name="transacton.factory_class">

org.hibernate.transaction.JTATransactionFactory

</property-->

4. Hibernate事务—基于JDBC实现

a) Hibernate代码片段:

Session s=sessionFactory.openSession();

Transaction tx=s.beginTransaction();

……

tx.commit();

b) JDBC代码片段:

Connection conn=DiverManager.getConnection();

conn.setAutoCommit(false);

……

conn.commit();

5. Hibernate事务—基于JTA实现

Oracle培训(三十九)——Hibernate第五章知识点小结——第五章-事务管理

JTA事务是有JTA Container维护的,事务的生命周期由JTA Container维护,与具体Connection无关

6. Hiberante事务API

public void transientToPersist(){Session ses = sf.openSession();Transaction tx = ses.beginTransaction();//创建一个transient对象cCourse c = new Course("Core C++", "C++ fundamental");try{//将transient 对象c变成了persistent对象ccid = (Long)ses.save(c);tx.commit();}catch(HibernateException he){ tx.rollback();throw he;}finally{ses.close();}//persistent对象c变成了detached对象c}//garbage collection c


7. 提交回滚关闭

调用tx.commit()方法同步Session状态到数据库。

如果s.save(c)抛出一个异常,则必须强制调用tx.rollback()方法回滚事务。

非常重要的是,不管成功与否,都要在finally代码块关闭Session,以确保JDBC连接释放到数据库连接池。

1. 锁

a) 业务逻辑处理中,往往需要数据访问排他性,需要通过一些机制保证这个数据在操作过程中不会被外界修改,锁是预防在并发访问数据资源时,当一个事务对数据加锁后,没有并发事务能读或者修改该数据资源。

b) 悲观锁(Pessimistic Locking)

c) 乐观锁(Optimistic Locking)

2. 悲观锁

a) 悲观锁在读取数据资源进行加锁,直到事务完成该锁被释放掉。

b) 依赖数据库的悲观锁(for update)

select * from t_user where name=‘zz’ for update

3. 锁模式

a) Hibernate内部锁机制:

LockMode.NONE无锁机制

LockMode.WRITEHibernate在Insert和Update记录时会自动获取

LockMode.READ Hibernate读取记录时会自动获取

b) 数据库锁机制:

LockMode.UPDGRADE利用数据库的 for update子句加锁

LockMode.UPDGRADE_NOWAIT Oracle的特定实现,利用oracle的for update nowait子句实现加锁

c) Hibernate的LockMode类可以让你请求一个特定的悲观锁

public void update(){Session ses = sf.openSession();Transaction tx = ses.beginTransaction();try{ses.lock(c, LockMode.UPGRADE);c.setName("Core Java");c.setDescription("Java language");ses.update(c); //如果使用了lock()方法,没有必要调用update()tx.commit();}catch(HibernateException he){tx.rollback();throw he;}finally{ses.close();}}


d) 应用事务

i. 假设两个不同的柜员对同一账户进行修改并提交,这时,我们有三种方法可以处理写入数据库的并发

ii. 最晚提交生效(Last commit wins)两个变更都成功,第二个变更覆盖第一个变更

iii. 最先提交生效(First commit wins)第一个变更提交,第二个变更提交时会得到一个错误消息

iv. 合并冲突更新(Merge conflicting updates)第一个变更提交,第二个修改会返回错误信息,用户可以有选择的应用修改

4. 乐观锁

a) Hibernate使用乐观版本管理可以使第二和每三个策略生效

b) 实现方式:

version:版本机制(版本号或时间戳)

dirty:检查被改动的属性

all:检查被保存的所有属性

c) 版本机制

版本管理使用一个增长的版本号或一个当前时间的时间戳

操作员A此时读出数据(version=1),并从账户扣除余额

在A操作过程中,B也读入此用户信息(version=1),并扣除余额

A修改完成之后,增加版本号(version=2),并更新余额信息

B修改完成后,增加版本号(version=2),在数据提交过程中,发现当前版本号不大于数据记录版本号,被驳回。

使用Hibernate版本管理,我们必须在User类添加一个版本属性,并且使用<version>标志或使用@Version注解映射该属性为一个版本号。

d) 使用版本管理—POJO类代码片段

package com.oracle.entity;public class User {private Integer userId;private String userName;private String userAddress;private Integer userAge;private int version;public int getVersion() {return version;}public void setVersion(int version) {this.version = version;}}


e) 使用版本管理—映射文件

<?xml version="1.0" encoding="utf-8"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping><class name="com.oracle.entity.User" table="T_USER" optimistic-lock="version"><id name="userId" type="java.lang.Integer"><column name="userId" length="32" /><generator class="native" /></id><version name="version" column="version"></version><property name="userName" type="java.lang.String"><column name="userName" length="200" /></property><property name="userAddress" type="java.lang.String"><column name="userAddress" length="200" /></property><property name="userAge" type="java.lang.Integer"><column name="userAge" /></property></class></hibernate-mapping>


f) 使用版本管理—持久化代码片段

public class Test {public static void main(String[] args) {try {sf = cfg.buildSessionFactory();s1 = sf.openSession();s2=sf.openSession();User u1=(User) s1.get(User.class, 1);User u2=(User) s2.get(User.class, 1);tx1 = s1.beginTransaction();tx2=s2.beginTransaction();u1.setUserAge(27);tx1.commit();u2.setUserAge(36);tx2.commit();} catch (HibernateException e) {e.printStackTrace();tx1.rollback();tx2.rollback();}finally{if(s1!=null){s1.close();}if(s2!=null){s2.close();}if(sf!=null){sf.close();}}}}


Oracle培训(三十九)——Hibernate第五章知识点小结——第五章-事务管理

g) 使用版本管理

i. Hibernate每次更新时,会在SQL的子句中使用版本字段如下 :

ii. update orders set name=‘new name’,version=6 where id=1001 and version=5;

iii. 如果另一个事务读取并更新相同的信息, VERSION字段不是值5,则找不到匹配的行而更新不成功,此时Hibernate会抛出异常

总结

事务管理概述

ACID/三种问题/四种隔离级别

Hibernate事务API

JDBC实现/JTA实现

锁机制

悲观锁/乐观锁

问题

Hibernate的事务隔离级别

乐观锁和悲观锁

读书人网 >编程

热点推荐