1.Session概述
- Session接口是Hibernate向应用程序提供的操纵数据库最主要的接口,它提供了基本的保存,更新,删除和加载java对象的方法
- Session具有一个缓存,位于缓存中的对象成为持久化对象,它和数据库中的相关记录对应,Session能够在某些时间点,按照缓存中对象的变化来执行相关的SQL语句,来同步更新数据库,这一过程被成为刷新缓存(flush)
- 站在持久化的角度,Hibernate把对象分为4种状态:持久化状态,临时状态,游离状态,删除状态。Session的特定方法能使对象从一个状态转换到另一个状态
2.Session缓存
@Test
public void testGet() {
Session session = getSession();
NewsEntity newsEntity = (NewsEntity) session.get(NewsEntity.class, 2);
NewsEntity newsEntity1 = (NewsEntity) session.get(NewsEntity.class, 2);
System.out.println(newsEntity);
System.out.println(newsEntity1);
session.close();
}
该方法只会向数据库发送1条SQL语句。当进行第二次获取时,会从Session缓存中获取数据,而不是去向数据库查询
3.操作Session缓存
(1)flush缓存
- Session按照缓存中对象的属性变化来同步更新数据库
- 默认情况下Session在以下时间点刷新缓存:
- 显示调用flush()方法
- 调用Transaction的commit()方法(该方法先flush,再提交事务)
- 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会flush缓存
- 特殊情况:如果使用native生成器生成OID,那么当调用Session的save()方法保存对象,会立即执行插入操作
(2)设定刷新缓存的时间点
- 若希望改变flush的默认时间点,可以通过Session的setFlushMode()方法显式设定flush的时间点
/*
调用Session的查询方法时,清理缓存,注意:这条规则必须保证显式开启的事务中
调用Session.commit()时,清理缓存
调用Session.flush()时,清理缓存
*/
session.setFlushMode(FlushMode.AUTO); //默认模式
/*
调用Session的查询方法时,不清理缓存
调用Session.commit()时,不清理缓存
调用Session.flush()时,清理缓存
*/
session.setFlushMode(FlushMode.MANUAL);
/*
调用Session的查询方法时,不清理缓存
调用Session.commit()时,清理缓存
调用Session.flush()时,清理缓存
*/
session.setFlushMode(FlushMode.COMMIT);
/*
调用Session的查询方法时,清理缓存,注意:这条规则必须保证显式开启的事务中
调用Session.commit()时,清理缓存
调用Session.flush()时,清理缓存
*/
session.setFlushMode(FlushMode.ALWAYS);
4.持久化对象的状态
Hibernate把对象分为4种状态:
持久化状态,临时状态,游离状态,删除状态
- 临时对象(Transient)
- 在使用代理主键的情况下,OID通常为null
- 不处于Session的缓存中
- 在数据库中没有对应的记录
- 持久化对象(Persist)
- OID不为null
- 位于Session缓存中
- 若在数据库中已经有和其对应的记录,持久化对象和数据库中的相关记录对应
- Session在flush缓存时,会根据持久化对象的属性变化,来同步更新数据库
- 在同一个Session实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象
- 删除对象(Removed)
- 在数据库中没有和其OID对应的记录
- 不再处于Session缓存中
- 一般情况下,应用程序不该再使用被删除的对象
- 游离对象(Detached)
- OID不为null
- 不再处于Session缓存中
- 一般情况下,游离对象是由持久化对象转变过来的,因此在数据库中可能还存在与它对应的记录
5.对象的状态转换图
6.save()方法
- Session的save()方法使一个临时对象转变为持久化对象
- 当对象为持久化状态时,不允许程序随意修改它的ID
@Test
public void testAdd() {
Session session = getSession();
//3. 开启事务
Transaction transaction = session.beginTransaction();
//4. 执行保存操作
NewsEntity newsEntity = new NewsEntity();
newsEntity.setTitle("java语句很强吗");
newsEntity.setAuthor("hello123");
newsEntity.setData(new Date());
session.save(newsEntity);
newsEntity.setId(5);
//5. 提交事务
transaction.commit();
//6. 关闭 Session
session.close();
}
- save()之后,又修改了NewsEntity,程序会抛出异常
- persist()和save()的区别:
/**
* persist(): 也会执行 INSERT 操作
*
* 和 save() 的区别 :
* 在调用 persist 方法之前, 若对象已经有 id 了, 则不会执行 INSERT, 而抛出异常
*/
@Test
public void testPersist(){
Session session = getSession();
//3. 开启事务
Transaction transaction = session.beginTransaction();
//4. 执行保存操作
NewsEntity newsEntity = new NewsEntity();
newsEntity.setTitle("测试");
newsEntity.setAuthor("java555");
newsEntity.setData(new Date());
newsEntity.setId(333);
session.persist(newsEntity);
//5. 提交事务
transaction.commit();
//6. 关闭 Session
session.close();
}
/**
* 1. save() 方法
* 1). 使一个临时对象变为持久化对象
* 2). 为对象分配 ID.
* 3). 在 flush 缓存时会发送一条 INSERT 语句.
* 4). 在 save 方法之前的 id 是无效的
* 5). 持久化对象的 ID 是不能被修改的!
*/
@Test
public void testSave(){
Session session = getSession();
//3. 开启事务
Transaction transaction = session.beginTransaction();
//4. 执行保存操作
NewsEntity newsEntity = new NewsEntity();
newsEntity.setTitle("测试");
newsEntity.setAuthor("java555");
newsEntity.setData(new Date());
newsEntity.setId(333);
session.save(newsEntity);
//5. 提交事务
transaction.commit();
//6. 关闭 Session
session.close();
// news.setId(101);
}
7.get()和load()方法
/**
* get VS load:
*
* 1. 执行 get 方法: 会立即加载对象.
* 执行 load 方法, 若不适用该对象, 则不会立即执行查询操作, 而返回一个代理对象
*
* get 是 立即检索, load 是延迟检索.
*
* 2. load 方法可能会抛出 LazyInitializationException 异常: 在需要初始化
* 代理对象之前已经关闭了 Session
*
* 3. 若数据表中没有对应的记录, Session 也没有被关闭.
* get 返回 null
* load 若不使用该对象的任何属性, 没问题; 若需要初始化了, 抛出异常.
*/
@Test
public void testLoad(){
Session session = getSession();
NewsEntity news = (NewsEntity) session.load(NewsEntity.class, 1);
System.out.println(news.getClass().getName());
// session.close();
// System.out.println(news);
}
@Test
public void testGet1(){
Session session = getSession();
NewsEntity news = (NewsEntity) session.get(NewsEntity.class, 1);
// session.close();
System.out.println(news);
}
8.update()方法
- Session 的 update() 方法使一个游离对象转变为持久化对象, 并且计划执行一条 update 语句.
- 若希望 Session 仅当修改了 News 对象的属性时, 才执行 update() 语句, 可以把映射文件中 <class> 元素的 select-before-update 设为 true. 该属性的默认值为 false
- 当 update() 方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常
- 当 update() 方法关联一个游离对象时, 如果在数据库中不存在相应的记录, 也会抛出异常
9.saveOrUpdate()方法
/**
* 注意:
* 1. 若 OID 不为 null, 但数据表中还没有和其对应的记录. 会抛出一个异常.
* 2. 了解: OID 值等于 id 的 unsaved-value 属性值的对象, 也被认为是一个游离对象
*/
@Test
public void testSaveOrUpdate(){
Session session = getSession();
//3. 开启事务
Transaction transaction = session.beginTransaction();
NewsEntity news = new NewsEntity("FFF", "fff", new Date());
news.setId(11);
session.saveOrUpdate(news);
//5. 提交事务
transaction.commit();
//6. 关闭 Session
session.close();
}
10.delete()方法
/**
* delete: 执行删除操作. 只要 OID 和数据表中一条记录对应, 就会准备执行 delete 操作
* 若 OID 在数据表中没有对应的记录, 则抛出异常
*
* 可以通过设置 hibernate 配置文件 hibernate.use_identifier_rollback 为 true,
* 使删除对象后, 把其 OID 置为 null
*/
@Test
public void testDelete(){
Session session = getSession();
NewsEntity news = (NewsEntity) session.get(NewsEntity.class, 23);
session.delete(news);
System.out.println(news);
}