Hibernate4-2 通过Session操纵对象

  Session接口是Hibernate向应用程序提供的操纵数据库的最主要接口,其提供有基本的保存、更新、删除和加载Java对象的方法。
  Session具有一个缓存,位于缓存中的对象称为持久化对象,其与数据表中相关记录相对应;其中,Session对象能够在某些时间点,按照缓存中对象的变化来执行对应SQL语句,以同步更新数据库,该过程被称为刷新缓存(flush)。
  站在持久化的角度来看,Hibernate将对象分为四种状态:持久化状态、临时状态、游离状态和删除状态,Session的特定方法能使对象从一个状态转换到另一个状态。


1. Session缓存

  概念:在Session接口的实现中包含一系列的Java集合,这些集合构成Session缓存。
  **作用:**Session缓存可减少Hibernate应用程序访问数据库的频率,因为只要Session实例没有结束生命周期且没有清理缓存,则存放在其缓存中的对象也不会消失。
  其中,Session缓存的基本原理测试代码如下所示:

// 注意:只会向数据库发送一条SQL语句
News news1 = (News) session.get(News.class, 1);
System.out.println(news1);

News news2 = (News) session.get(News.class, 1);
System.out.println(news2);

System.out.println(news1 == news2); // true
1.1 flush缓存

  作用: Session按照缓存中对象的属性变化来同步更新数据库中的表记录。
  实现:刷新缓存的时间点为session.flush();transaction.commit()
  比较: Session对象的flush()方法可能会执行SQL语句,但不提交事务;而Transaction对象的commit()方法先调用flush()方法,再提交事务(将对数据库的操作永久保存)。
  设定刷新缓存的时间点:可以调用Session对象的setFlushMode()方法显式设定刷新缓存的时间点,具体模式如下图所示:
这里写图片描述
  注意:在未提交事务或显式调用Session对象flush()方法,也可能会进行缓存刷新操作,具体如下:

  • 执行HQL或QBC查询时:若缓存中持久化对象的属性发生变化,则会先刷新缓存,以保证查询结果能够反映持久化对象的最新状态;
  • 执行save()方法保存对象时:若对象使用native生成器生成OID,则执行保存操作时,会立即执行刷新操作以保证对象的ID是存在的。
1.2 refresh缓存

  作用:强制发送SELECT语句,以使Session缓存中对象的状态和数据表中对应的记录保持一致。
  注意:MySQL数据库的默认事务隔离级别为“REPEATABLE READ”,需要手动修改为“READ COMMITED”。

1.3 clear缓存

  作用:Session对象的clear()方法可以清除Session缓存中的所有缓存对象。


2. 数据库的隔离级别

  数据库的隔离性是指隔离并发运行各个事务的能力,而隔离级别是指一个事务与其他事务的隔离程度;隔离级别越高,数据一致性就越好,但并发性越弱。

2.1 并发问题概述

  对于同时运行的多个事务,当这些事务访问数据库中相同数据时,如果没有采取必要的隔离机制,会导致各种并发问题,如下:

  • 脏读:对于两个事务T1和T2,T1读取了已经被T2更新但还没有被提交的字段后,若T2回滚,T1读取的内容就是临时且无效的;
  • 不可重复读:对于两个事务T1和T2,T1读取一个字段后,T2更新了该字段;之后T1再次读取同一个字段时值发生变化;
  • 幻读:对于两个事务T1和T2,T1从一个表中读取了一个字段后,T2在该表中插入一些新的行;之后,如果T1再次读取同一个表,就会多出几行。
2.2 事务隔离级别

  数据库提供的四种事务隔离级别,分别是:
这里写图片描述
  其中,Oracle 支持“READ COMMITED”(默认)和“SERIALIZABLE”两种事务隔离级别,而MySQL支持四种事务隔离级别,默认为“READ COMMITED”。
  

2.2 在MySQL中设置隔离级别

  在MySQL数据库中,每启动一个程序就会获得一个单独的数据库连接,每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。

  • 查看当前的隔离级别:SELECT @@tx_isolation
  • 设置当前MySQL连接的隔离级别:set transaction isolation level read committed
  • 设置当前MySQL数据库的隔离级别:set global transaction isolation level read committed
2.3 在Hibernate中设置隔离级别

  JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate中可通过配置其hibernate.connection.isolation属性的方式来设置事务的隔离级别,具体说明如下:

<!-- 1). 配置数据库的事务隔离级别为:READ UNCOMMITED -->
<property name="hibernate.connection.isolation">1</property>

<!-- 2). 配置数据库的事务隔离级别为:READ COMMITED -->
<property name="hibernate.connection.isolation">2</property>

<!-- 3). 配置数据库的事务隔离级别为:REPEATABLE READ -->
<property name="hibernate.connection.isolation">4</property>

<!-- 4). 配置数据库的事务隔离级别为:SERIALIZEABLE -->
<property name="hibernate.connection.isolation">8</property>

3. 持久化对象的状态

  站在持久化的角度,Hibernate把对象分为四种状态:持久化状态、临时状态、游离状态、删除状态;Session的特定方法能使对象从一个状态转换到另一个状态。

3.1 临时对象(Transient)
  • 在使用代理主键的情况下,OID通常为null;
  • 不处于Session缓存中;
  • 在数据库中没有对应的记录。
3.2 持久化对象(Persist)
  • OID不为null;
  • 位于Session缓存中;
  • 若在数据库中已经有与其对应的记录,持久化对象和数据库中的相关记录对应;
  • Session 在flush缓存时,会根据持久化对象的属性变化,来同步更新数据库;
  • 在同一个Session实例的缓存中, 数据库表中每条记录只对应唯一的持久化对象。
3.3 删除对象(Removed)
  • 在数据库中没有和其OID对应的记录;
  • 不再处于Session缓存中;
  • 一般情况下,应用程序不该再使用被删除的对象。
3.4 游离对象(Detached)
  • OID不为null;
  • 不再处于Session缓存中;
  • 一般情况下,游离对象是由持久化对象转变而来,在数据库中可能还存在与其对应的记录。
3.5 对象状态转换图

这里写图片描述


4. Session核心方法

4.1 save()与persist()方法
/**
 * Session对象的save()方法:
 * 1). 将临时对象加入Session缓存中,使其转变为持久化对象;
 * 2). 选用映射文件指定的标识符生成器,为持久化对象分配唯一的OID;
 * 3). 在flush缓存时,会发送一条INSERT语句;
 * 4). 在使用代理主键的情况下,通过setId()方法为临时对象设置OID是无效的;
 * 5). 持久化对象的OID不能被随意修改,因其维持着持久化对象与数据库记录的对应关系。
 * 
 * Session对象的persist()方法:也会执行INSERT操作;
 * 与save()方法的不同之处:当临时对象的OID不为空时,该方法将抛出异常。
 */
@Test
public void testSaveAndPersist() {
    News news = new News(null, "qiaobc", "qiaobei", new Date());
    news.setId(1001);   // 为临时对象设置OID是无效的
    System.out.println(news);

    // session.persist(news); 

    session.save(news);
    System.out.println(news);
    // news.setId(1002); // 持久化对象的OID不能修改
}
4.2 get()与load()方法
/**
 * Session对象的get()与load()方法:均可根据OID从数据库中加载一个持久化对象
 * 1). 执行get()方法时,立即加载对象;
 *     而执行load()方法时,延迟加载对象,即若不使用该对象,则不会立即查询,而是返回一个代理对象;
 * 2). load()方法可能会抛出LazyInitializationException异常:在需要初始化代理对象前关闭Session对象;
 * 3). 若数据表中没有与OID对应的记录,则get()方法返回null;
 *     而load()方法,若不使用该对象的任何属性则没问题,若需要初始化则抛出ObjectNotFoundException异常。
 */
@Test
public void testGet() {
    News news1 = (News) session.get(News.class, 10);
    System.out.println(news1);  // 持久化状态

    session.close();    // 游离状态
    System.out.println(news1);
}

@Test
public void testLoad() {
    News news2 = (News) session.load(News.class, 1);
    // 若不使用,则返回代理对象com.qiaobc.hibernate.entities.News_$$_javassist_0
    System.out.println(news2.getClass().getName());

    session.close();    // 游离状态
    System.out.println(news2);  // 抛出LazyInitializationException异常
}
4.3 update()方法
/**
 * Session对象的update()方法:
 * 1). 更新持久化对象不需要显式调用update()方法,因为事务提交时会flush缓存;
 * 2). 更新游离对象需要显式调用update()方法,将其转变为持久化对象;
 * 
 * 注意:
 * 1). 无论要更新的游离对象和数据表的记录是否一致,均会发送UPDATE语句;
 *     当Hibernate与触发器协同工作时,可在*.hbm.xml文件的class节点
 *     设置select-before-update=true以确保不盲目发送UPDATE语句;
 * 2). 当 update()方法关联一个游离对象时,如果在数据库中不存在相应的记录,抛出异常;
 * 3). 当 update()方法关联一个游离对象时,如果在Session缓存中已经存在相同OID的持久化对象,抛出异常;
 */
@Test
public void update1() {
    News news = (News) session.get(News.class, 1);
    news.setAuthor("SUN");
    session.update(news); // 若更新持久化对象不需要显式调用update()方法
}

@Test
public void update2() {
    News news = (News) session.get(News.class, 1);
    transaction.commit();
    session.close();

    session = sessionFactory.openSession();
    transaction = session.beginTransaction();
    news.setAuthor("SUN");  // 此时news为游离对象

    session.update(news); 
}
4.4 saveOrUpdate()方法
/**
 * Session对象的saveOrUpdate()方法:临时对象执行保存操作,游离对象执行更新操作。
 * 1). 判定对象为临时对象的标准:Java对象的OID是否为null;
 * 2). 了解:若Java对象的OID取值等于映射文件中id节点unsaved-value属性值,则其也为临时对象。
 */
@Test
public void testSaveOrUpdate() {
    // OID不为空,执行更新操作;若OID对应的记录不存在,则抛出StaleStateException异常。
    News news1 = new News(10, "qiaobc1", "qiaobei1", new Date());
    session.saveOrUpdate(news1);

    // OID为空,执行保存操作
    News news2 = new News(null, "qiaobc", "qiaobei", new Date());
    session.saveOrUpdate(news2);
}
4.5 merge()方法

这里写图片描述

4.6 delete()方法
/**
 * Session对象的delete()方法:既可以删除一个游离对象,也可以删除一个持久化对象
 * 1). 只要OID与数据表中记录对应,即执行删除操作;无对应记录则抛出异常;
 * 2). 通过设置hibernate.use_identifier_rollback=true,使删除对象时置OID=null;
 */
@Test
public void testDelete() {
    News news = new News();
    news.setId(5);
    session.delete(news);   // 删除游离对象

    News news2 = (News) session.get(News.class, 6);
    session.delete(news2);  // 删除持久化对象

    // 配置前:News [id=6, title=qiaobc, author=qiaobei, date=2017-02-20 17:10:35.0]
    // 配置后:News [id=null, title=qiaobc, author=qiaobei, date=2017-02-20 17:10:35.0]
    System.out.println(news2);
}
4.7 evict()方法
/**
 * Session对象的evict()方法:从缓存中将持久化对象移除
 */
@Test
public void testEvict() {
    News news1 = (News) session.get(News.class, 1);
    News news2 = (News) session.get(News.class, 2);

    news1.setAuthor("No.1");
    news2.setAuthor("No.2");

    session.evict(news2);   // 移除news2对象,不再更新该对象
}

5. Hibernate调用存储过程

这里写图片描述


6. Hibernate与触发器协同工作

这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用AngularJs编写的简单 益智游戏(附源代码)  这是一个简单的 javascript 项目。这是一个拼图游戏,也包含一个填字游戏。这个游戏玩起来很棒。有两个不同的版本可以玩这个游戏。你也可以玩填字游戏。 关于游戏 这款游戏的玩法很简单。如上所述,它包含拼图和填字游戏。您可以通过移动图像来玩滑动拼图。您还可以选择要在滑动面板中拥有的列数和网格数。 另一个是填字游戏。在这里你只需要找到浏览器左侧提到的那些单词。 要运行此游戏,您需要在系统上安装浏览器。下载并在代码编辑器中打开此项目。然后有一个 index.html 文件可供您修改。在命令提示符中运行该文件,或者您可以直接运行索引文件。使用 Google Chrome 或 FireFox 可获得更好的用户体验。此外,这是一款多人游戏,双方玩家都是人类。 这个游戏包含很多 JavaScript 验证。这个游戏很有趣,如果你能用一点 CSS 修改它,那就更好了。 总的来说,这个项目使用了很多 javascript 和 javascript 库。如果你可以添加一些具有不同颜色选项的级别,那么你一定可以利用其库来提高你的 javascript 技能。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值