理解数据库事物
现在项目动不动都是高并发大容量项目,网站,互联网等等,Hibernate作为框架如何处理事物,并发和缓存。
事物,acid特性
数据库事物,要么提交,要么回滚
jdbc针对单个数据库,jta是对两个或多个数据存储分布式事物。
Hibernate应用代码在管理环境和非管理软件是一样的,Hibernate提供一个抽象层处理,规避了内部实现细节。
Hiberante的事物API
定义事物的边界
Session session = sessions.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction(); 开始
concludeAuction();
tx.commit();//提交,同步Session状态和数据库
} catch (Exception e) {
if (tx != null) {
try {
tx.rollback();//回滚
} catch (HibernateException he) {
//log he and rethrow e
}
}
throw e;
} finally {
try {
session.close();
} catch (HibernateException he) {
throw he;
}
}
上面代码同时适用于管理和非管理环境,JTA,或JDBC
Flushing the Session
hibernate透明化的实现写后操作,不是马上对session状体回写到数据库中,而是归并许多状态变化,到最少的数据库请求提交到数据库.
Flushing时间点:
事物提交,查询之前,手工Session.flush()
Flushing模式,FlushMode.AUTO,FlushMode.COMMIT,FlushMode.NEVER
理解事物隔离级别:
隔离问题:
Lost update,Dirty read,Unrepeatable read,Second lost updates problem,Phantom read
更新丢失,脏读,不重复读,第二次丢失更新,幻想读。
隔离级别:
Read uncommitted,允许脏读,但是不丢失更新,可能是排他写锁
Read committed,允许非重复读,不是脏读,临时共享读锁和排他写锁,读事物不影响其他事物访问数据,但是写事物阻止一切事物
Repeatable read,不允许非重复读,和脏读,共享读锁,和排他锁
Serializable 最严格,事物都要顺序执行。
选择隔离级别:
Read uncommitted会产生bug,影响数据一致性,排除
Serializable 性能受影响
Repeatable read,避免了一个事物更改的数据,被另一个并发事物所更改,但是这并不是唯一的方法,效率不高,而且不能避免幻想读。
Hibernate第一级缓存和版本数据提供了重复读特性。版本保证不能发生第二次丢失更新问题,
一级cache session保证了数据不被其他的并发事物所影响。
不鼓励使用Repeatable read,
那就是剩下了Read committed,呵呵
设置Setting an isolation level
1—Read uncommitted isolation
■ 2—Read committed isolation
■ 4—Repeatable read isolation
■ 8—Serializable isolation
悲观锁
select .... for update
几种锁模式:
■ LockMode.NONE—Don’t go to the database unless the object isn’t in either
cache. 如果有缓存,就不访问数据库
■ LockMode.READ—Bypass both levels of the cache, and perform a version
check to verify that the object in memory is the same version that currently
exists in the database. 绕过双层缓存,并且版本检查去确认内存对象和数据库中版本一致
■ LockMode.UPDGRADE—Bypass both levels of the cache, do a version check
(if applicable), and obtain a database-level pessimistic upgrade lock, if
that is supported.绕过双层缓存,并且版本检查去确认内存对象和数据库中版本一致,并得到悲观锁,
■ LockMode.UPDGRADE_NOWAIT—The same as UPGRADE, but use a SELECT...FOR
UPDATE NOWAIT on Oracle. This disables waiting for concurrent lock releases,
thus throwing a locking exception immediately if the lock can’t be obtained.
不等待当前锁释放,会抛出异常,如果得不到悲观锁
■ LockMode.WRITE—Is obtained automatically when Hibernate has written to
a row in the current transaction (this is an internal mode; you can’t specify
it explicitly).写模式
应用事物
所谓应用事物,从用户角度来看,被认为一个简单的工作单元的商业过程,必须要横跨多个用户客户端得请求。一个粗粒度的广域的应用事物,比如,通过多个界面,多个步骤收集数据,最后完成操作。
既然我们不能用数据库保证当前应用事物隔离和原子性,隔离成为应用事物的关注点。
举例说明:
如果有两个管理员同时打开查看评论界面,并修改,提交了。有三种方法来处理并发试图写数据操作。
1,最后提交胜出,两种写数据库操作都成功,第二次写操作覆盖第一次写操作,无错报出
2.第一次提交胜出,第一次修改持久化后,用户提交第二次操作报错,用户必须重新进行业务过程,来检索更新的评论,再修改,再提交。这就是我们经常说的乐观锁。
3.合并两个提交结果,第一次提交完成,第二次提交也被用户选择性应用。
1的实现方法,是有问题,不允许的,第二种和第三种很类似,可以接受的
Hibernate可以帮助我们实现第二种,和第三种策略,通过控制版本的乐观锁。
Hibernate 的管理版本:
通过时间戳,或者是版本属性,相对时间戳,版本属性更可靠。
Session的粒度:
Session定义了对象身份的范围,Hibernate的事物实例匹配数据库事物范围
session和事物有一对一的情况。通常称为每个请求一个session
一个长运行的应用事物,包括两个客户请求和响应生命圈,加载数据通过第一个session,修改完数据,把脱离数据再重新附到新的session,hibernate会自动的进行版本控制。这种称为带有游离数据的每个请求一个session
另外的一种,长session或者叫一个应用事物一个session,session可以序列化到http session中。一个长session可以有两次数据库连接事物。
其他乐观锁:把要修改的数据字段,以前的数据字段内容作为查找条件,只更新这个修改数据字段。
举例如下:
update COMMENTS set COMMENT_TEXT='New text'
where COMMENT_ID=123
and COMMENT_TEXT='Old Text'
and RATING=5
and ITEM_ID=3
and FROM_USER_ID=45
Caching theory and practice
缓存是位于数据库和应用之间,存在于应用服务器的机器内存和硬盘中,是当前数据库状态代表。
cache策略和范围:
事物范围,确切的数据事物或者应用事物范围。
过程范围,多个事物或工作单元共享数据
集群范围,多个事物或工作单位共享,或一个集群内多台计算机共享
cache和对象身份
事物范围内,对象身份是一致的,比如两次查找同一个id,返回的对象是相同。
过程范围内,对象身份是不一致的
集群范围内,对象身份相同更不能保证。
cache和并发
任何ORM实现都允许多个工作单元共享相同持久对象实例,这样,必须提供一些对象级别的锁,来确保并发存取的同步,这样一来,会导致死锁,hibernate为每一个工作单元维护着一组实例集合,第一级cache能保证事物级别范围内对象身份相同,是最好的策略为高并发多用户系统。
cache和事物隔离
hibernate二级缓存,存储的对象基本上很少改动的,或改动不频繁。
Hibernate缓存框架:
Hibernate二层缓存框架,第一层缓存是session,是不可选,不能关闭,第二层缓存是可插拔的,范围是过程,或是集群.这层缓存状态的cache,不是持久实例,是可选的,可配置到每个类和每个关联类里面。
使用第一层cache,能确保先后取得相同的持久对象的时候,返回的是同一个java实例
重要的事情,它确保了再互相引用对象图情况下,不能发生栈溢出。在数据库交易完后,不会存在一个冲突的相同数据行的对象代表。所有的变化都要写入数据库。在这个工作单元的变化,这个单元的其他部分是可以见的
如果要管理第一层缓存的话,很多数据放在内存,可以用evict(),清除数据和集合从session
管理session,hibernate不是一个理想工具,进行大量的增加,更新工作,会造成内存溢出。session.clear()可以清除所有的对象。
Hibernate二级缓存,确切是sessionfactory 范围。
Persistent instances are stored in the second-level cache in a disassembled form.
Think of disassembly as a process a bit like serialization (the algorithm is much,
much faster than Java serialization, however).类似于序列化
并发内置策略:
并发策略是个中间物件,负责存储和检索从cache中,
四种策略,严格程度依次递减,事物级别,读写,nonstrict-read-write非严格读写,read-only只读
选择合适的cache提供者:
■ EHCache is intended for a simple process scope cache in a single JVM. It can
cache in memory or on disk, and it supports the optional Hibernate query
result cache.
■ OpenSymphony OSCache is a library that supports caching to memory and disk
in a single JVM, with a rich set of expiration policies and query cache support.
■ SwarmCache is a cluster cache based on JGroups. It uses clustered invalidation
but doesn’t support the Hibernate query cache.
■ JBossCache is a fully transactional replicated clustered cache also based on
the JGroups multicast library. The Hibernate query cache is supported,
assuming that clocks are synchronized in the cluster
实践cache
EHCache,
JbossCache两种。