三个重要存储位置:
*session ActionQueue insert/update/delete
主要存放session操作(save、update、delete)之后,但尚未发出sql语句的对象的相关信息,简称 临时队列,调用session.flush()操作,会清空队列里的信息,发出sql语句,并改变缓存对象的 existsInDatabase属性值
*session PersistentContext
hibernate的session级缓存,其中对象的existsInDatebase属性标志着该缓存对象在数据库中是否存在
*数据库
session flush方法主要做了两件事:
* 清理临时队列
* 发出sql,并修改PersistentContext中对象的existsInDateBase值为true
session在什么情况下执行flush
* 默认在事务提交时
* 显示的调用flush
* 在执行查询前,如:iterate
调用flush操作后,hibernate按照save(insert),update、delete顺序发出sql语句,而会按照程序中操作的先后顺序,见后面的测试用例
1.定义User1类(UUID)
package com.bjsxt.hibernate;
import java.util.Date;
public class User1 {
private String id;
private String name;
private String password;
private Date createTime;
private Date expireTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getExpireTime() {
return expireTime;
}
public void setExpireTime(Date expireTime) {
this.expireTime = expireTime;
}
}
2.定义User1.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">
<class name="User1" table="t_user1">
<id name="id" column="user_id" length="32">
<generator class="uuid"/>
</id>
<property name="name" unique="true" not-null="true" length="20"/>
<property name="password" not-null="true" length="10"/>
<property name="createTime" column="create_time"/>
<property name="expireTime" column="expire_time"/>
</class>
</hibernate-mapping>
3.定义User2类(native)
package com.bjsxt.hibernate;
import java.util.Date;
public class User2 {
private int id;
private String name;
private String password;
private Date createTime;
private Date expireTime;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getExpireTime() {
return expireTime;
}
public void setExpireTime(Date expireTime) {
this.expireTime = expireTime;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
4.定义User2.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">
<class name="User2" table="t_user2">
<id name="id" column="user_id">
<generator class="native"/>
</id>
<property name="name" unique="true" not-null="true" length="20"/>
<property name="password" not-null="true" length="10"/>
<property name="createTime" column="createtime"/>
<property name="expireTime" column="expiretime"/>
</class>
</hibernate-mapping>
5.定义User3类(assigned)
package com.bjsxt.hibernate;
import java.util.Date;
public class User3 {
private String id;
private String name;
private String password;
private Date createTime;
private Date expireTime;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getExpireTime() {
return expireTime;
}
public void setExpireTime(Date expireTime) {
this.expireTime = expireTime;
}
}
6.定义User3.hbm.xml文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">
<class name="User3" table="t_user3">
<id name="id" column="user_id" length="32">
<generator class="assigned"/>
</id>
<property name="name"/>
<property name="password"/>
<property name="createTime" column="create_time"/>
<property name="expireTime" column="expire_time"/>
</class>
</hibernate-mapping>
6. 定义ExportDB类和HibernateUtils工具类(略)
7. 编写测试用例
package com.bjsxt.hibernate;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import junit.framework.TestCase;
public class SessionFlushTest extends TestCase {
/**
* 测试uuid主键生成策略
*/
public void testSave1() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
User1 user = new User1();
user.setName("李四");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
// user的主键生成策略采用的是uuid,由hibernate框架提供id值
//调用完成save后,会执行如下操作:
//在临时队列(ActionQueue)的insert集合中存储user信息
//将user纳入到了session(persistenContext)的管理,并将user的existsInDatebase状态为false
//不会发出insert语句,数据库中无user的相关信息
session.save(user);
//调用flush,hibernate会清理临时队列,发出sql,并且将session中persistentContext中的user对象的existsInDatebase状态为true
//如果数据库的隔离级别设置为未提交读,那么我们可以看到flush过的数据
session.flush();
//默认情况下commit操作会先执行flush清理缓存,所以不用显示的调用flush
//commit后数据是无法回滚的
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
/**
* 测试native主键生成策略
*/
public void testSave2() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
User2 user = new User2();
user.setName("张三1");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
// user的主键生成策略为native,id值由数据库提供
//调用session.save后,会执行如下操作
//不会在临时队列的insert集合中添加信息
//直接发出insert语句,返回有数据库生成的id
//纳入了session的管理,并将session中(persistentContext的user对象)existsInDatebase状态置为true
//如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据
session.save(user);
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
/**
* 测试uuid主键生成策略
*/
public void testSave3() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
User1 user = new User1();
user.setName("王五");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
//因为user的主键生成策略采用的是uuid(hibernate提供id值)
//所以调用完成save后,只是将user纳入到了session的管理,并在临时队列中存储待插入信息
//不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false
session.save(user);
//将user对象从session缓存中逐出,即session的persistentContext中不保存user对象
session.evict(user);
//无法成功提交,因为hibernate在清理临时队列时,从session的insertions集合中取出user对象进行insert操作后,然后会更新persistentContext中user的existsInDatabase属性的值为true,但是由于evict已经将user从session缓存(persistentContext)中清除,所以无法找到相应对象,此时抛出异常
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
/**
* 测试uuid主键生成策略
*/
public void testSave4() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
User1 user = new User1();
user.setName("王五");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
// user的主键生成策略采用的是uuid
//调用save后,发生如下操作
//在临时队列中保存待插入信息
//将user纳入到了session缓存(persistentContext)的管理,existsInDatebase状态为false
//而不会发出insert语句
session.save(user);
//flush后,会执行如下操作
//hibernate会清理临时队列(将session activeQueue中的insertions中的user对象清除)
//发出sql语句并将user对象保存到数据库中
//设置session persistentContext中该对象的existsInDatebase的状态为true
session.flush();
//将user对象从session缓存中逐出
session.evict(user);
//可以成功提交,因为hibernate在清理临时队列时,在session的insertions集合中无法找到user对象
//所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
/**
* 测试native主键生成策略
*/
public void testSave5() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
User2 user = new User2();
user.setName("张三11");
user.setPassword("123");
user.setCreateTime(new Date());
user.setExpireTime(new Date());
//因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回由数据库生成的id
//不会在临时队列中存储该对象的待插入信息
//纳入了session缓存的管理,修改了session中existsInDatebase状态为true
//如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据
session.save(user);
//将user对象从session缓存中逐出,即session的persistentContext中逐出
session.evict(user);
//可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象
//所以就不会发出insert语句,也不会更新session缓存中该对象的existsInDatabase的状态
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
/**
* 测试assigned主键生成策略
*
*/
public void testSave6() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
User3 user = new User3();
user.setId("001");
user.setName("张三");
session.save(user);
user.setName("王五");
session.update(user);
User3 user3 = new User3();
user3.setId("002");
user3.setName("李四");
session.save(user3);
//Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
//Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
//Hibernate: update t_user3 set name=?, password=?, create_time=?, expire_time=? where user_id=?
//hibernate按照save(insert),update、delete顺序提交相关操作
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
/**
* 测试assigned主键生成策略
*
*/
public void testSave7() {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtils.getSession();
tx = session.beginTransaction();
User3 user = new User3();
user.setId("003");
user.setName("张三");
session.save(user);
user.setName("王五");
session.update(user);
session.flush();
User3 user3 = new User3();
user3.setId("004");
user3.setName("李四");
session.save(user3);
//Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
//Hibernate: update t_user3 set name=?, password=?, create_time=?, expire_time=? where user_id=?
//Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
//因为我们在session.udpate(user)后执行了flush,所以在清理缓存时执行flush前的sql不会生成
//sql会按照我们的意愿执行
tx.commit();
}catch(Exception e) {
e.printStackTrace();
tx.rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
}