实体对象生命周期
事务管理
锁
数据缓存
实体对象生命周期
实体对象的3种状态
自由状态
即实体对象在内存中的自由存在,它与数据库中的记录无关。
持久状态
即实体对象处于由Hibernate框架所管理的状态。
游离状态
处于持久状态的对象,其对应的Session实例关闭之后,那么,此对象就处于游离状态。
事务管理
事务是一个逻辑工作单元,它包括一系列的操作。事务包含4个基本特性,也就是我们常说的ACID,其中包括:
Atomic(原子性):事务中包含的操作被看作一个逻辑单元,这个逻辑单元中的操作要么全部成功,要么全部失败。
Consistency(一致性):一致性意味着,只有合法的数据可以被写入数据库,如果数据有任何违例(比如数据与字段类型不符),则事务应该将其回滚到最初状态。
Isolation(隔离性):事务允许多个用户对同一个数据的并发访问,而不破坏数据的正确性和完整性。同时,并行事务的修改必须与其他并行事务的修改相互独立。
Durability(持久性):事务结束后,事务处理的结果必须能够得到固化(保存在可掉电存储器上)。
Hibernate的事务管理
User7 u1 = new User7();
User7 u2 = new User7();
u1.setName("zs");
u1.setAccount(1000);
u2.setName("abcdefg");
u2.setAccount(2000);
Session s = HibernateSessionFactory.getSession();
Transaction t = s.beginTransaction();
try {
s.save(u1);
s.save(u2);
t.commit();
} catch (Exception ex) {
ex.printStackTrace();
t.rollback();
}
HibernateSessionFactory.closeSession();
事务管理的隔离等级
事务隔离指的是,数据库(或其他事务系统)通过某种机制,在并行的多个事务之间进行分隔,使每个事务在其执行过程中保持独立(如同当前只有此事务单独运行)。
Hibernate中的事务隔依赖于底层数据库提供的事务隔机制,因此,对数据库事务隔离机制的理解在基于Hibernate实现的持久层中同样适用。
首先我们来看数据操作过程中可能出现的3种不确定情况:
脏读取:一个事务读取了另一个并行事务未提交的数据。
不可重复读取:一个事务再次读取之前曾读取过的数据时,发现该数据已经被另一个已提交的事务修改。
虚读:一个事务重新执行一个查询,返回一套符合查询条件的记录,但这些记录中包含了因为其他最近提交的事务而产生的新记录。
事务管理的隔离等级
为了避免上面3种情况的出现,标准SQL规范中,定义了如下4个事务隔离等级:
隔离等级 脏读取 不可重复读取 虚读
Read Uncommitted 可能 可能 可能
Read Committed 不可能 可能 可能
Repeatable Read 不可能 不可能 可能
Serializable 不可能 不可能 不可能
这4种事务隔离等级的严密程度由前往后依次递增,同时,其性能也依次下降。因此,无论实际情况如何,都使用最高级事务隔离的做法并不可取。我们必须根据应用的具体情况进行取舍,以获得数据合法性与系统性能上的最佳平衡。
在Hibernate中设置事务管理隔离等级:
<property name="connection.isolation">2</property>
锁
业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金融系统的日终结算处理中,我们希望针对某个截止点的数据进行处理,而不希望在结算进行过程中(可能是几秒种,也可能是几个小时),数据再发生变化。
此时,我们就需要一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的“锁”,即给我们选定的目标数据上锁,使其无法被其他程序修改。
Hibernate支持两种锁机制:
悲观锁
乐观锁
悲观锁
悲观锁,正如其名,它指的是对数据被外界修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制。
一个典型的,依赖数据库实现的悲观锁调用:
select * from user7 where name='zs' for update
通过for update子句,这条SQL锁定了user7表中所有符合检索条件的记录(name='zs')。本次事务提交之前,外界无法修改这些记录。
Hibernate的悲观锁,也是基于数据库的锁机制实现。
Hibernate的加锁方法:
Criteria.setLockMode()
Query.setLockMode()
Session.lock()
Session.load()
Session.get()
Hibernate悲观锁示例
CREATE TABLE `sample`.`user7` (
`id` int(10) unsigned auto_increment,
`name` varchar(6),
`account` int(11),
PRIMARY KEY (`id`)
)
class Lock extends Thread {
public void run() {
Session s = HibernateSessionFactory.getSession();
Transaction t = s.beginTransaction();
User7 user = (User7) s.get(User7.class, 1, LockMode.UPGRADE);
// User7 user = (User7) s.get(User7.class, 1);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(user.getAccount());
user.setAccount(user.getAccount() - 100);
s.update(user);
System.out.println(user.getAccount());
t.commit();
HibernateSessionFactory.closeSession();
}
}
乐观锁
相对悲观锁而言,乐观锁机制采取了更加宽松的加载机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。
乐观锁,大多是基于数据版本(version)记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。
读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时,将提交数据的版本数据与数据表对应记录的当前版本信息进行比对,如果提交际的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
Hibernate在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数据的更新操作,利用Hibernate提供的透明化乐观锁实现,将大大提升我们的生产力。
Hibernate乐观锁示例
创建数据表
CREATE TABLE `sample`.`user8` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` varchar(45) NOT NULL default '',
`account` int(11) NOT NULL default '0',
`version` int(11) NOT NULL default '0',
PRIMARY KEY (`id`)
)
实体类
package fire;
public class User8 implements java.io.Serializable {
private Integer id;
private Integer version;
private String name;
private Integer account;
public User8() {
}
public User8(Integer id, String name, Integer account) {
this.id = id;
this.name = name;
this.account = account;
}
……
}
Hibernate映射文件
<hibernate-mapping>
<class name="fire.User8" table="user8" catalog="sample"
optimistic-lock="version">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="assigned" />
</id>
<version name="version" type="java.lang.Integer">
<column name="version" not-null="true" />
</version>
<property name="name" type="java.lang.String">
<column name="name" length="45" not-null="true" />
</property>
<property name="account" type="java.lang.Integer">
<column name="account" not-null="true" />
</property>
</class>
</hibernate-mapping>
Hibernate配置文件
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/sample
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="show_sql">true</property>
<mapping resource="fire/User8.hbm.xml" />
</session-factory>
</hibernate-configuration>
测试类
class Lock extends Thread{
public void run(){
Session s = HibernateSessionFactory.getSession();
Transaction t = s.beginTransaction();
User8 user = (User8) s.get(User8.class, 1);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(user.getAccount());
user.setAccount(user.getAccount() - 100);
s.update(user);
System.out.println(user.getAccount());
t.commit();
HibernateSessionFactory.closeSession();
}
}
数据缓存
Hibernate数据缓存分为两个层次,以Hibernate语义加以区分,可分为:
1.一级缓存(Session)
一级缓存正常情况下由Hibernate自动维护,如果需要手动干预,我们可以通过以下方法完成:
Session.evict() Session.clear()
2.二级缓存(SessionFactory)
二级缓存是全局缓存,使用时需要对其进行配置:
<property name="cache.provider_class">
org.hibernate.cache.HashtableCacheProvider
</property>
<property name="cache.use_query_cache">true</property>
<cache usage="read-write"/>
Query.setCacheable(true)
SessionFactory.evictQueries()
一级缓存示例
Session s=HibernateSessionFactory.getSession();
User7 u1=(User7) s.load(User7.class, Integer.valueOf(1));
System.out.println(u1.getName());
// s.evict(u1);
// s.clear();
User7 u2=(User7) s.load(User7.class, Integer.valueOf(1));
System.out.println(u2.getName());
HibernateSessionFactory.closeSession();
二级缓存示例
Session s1 = HibernateSessionFactory.getSession();
Query q1 = s1.createQuery("from User7");
q1.setCacheable(true);
Iterator it1 = q1.list().iterator();
while (it1.hasNext()) {
User7 user = (User7) it1.next();
System.out.println(user.getName());
}
HibernateSessionFactory.closeSession();
Session s2 = HibernateSessionFactory.getSession();
// s2.getSessionFactory().evictQueries();
Query q2 = s2.createQuery("from User7");
q2.setCacheable(true);
Iterator it2 = q2.list().iterator();
while (it2.hasNext()) {
User7 user = (User7) it2.next();
System.out.println(user.getName());
}
HibernateSessionFactory.closeSession();
Hibernate的高级特性
最新推荐文章于 2017-03-24 16:27:39 发布