hiernate-session
一、概述
Session 是 Hibernate 向应用程序提供操纵数据的主要接口,它提供了基本的保存、更新、删除和加载 Java 对象的方法。
二、Session 缓存
1.简介
(1)Session 有一个缓存,称为 Hibernate 一级缓存。位于缓存中的对象称为持久化对象,每一个持久化对象与数据库中的一条记录对应。
(2)站在持久化的角度,Hibernate 将对象分为 4 种状态:临时状态、持久化状态、游离状态、删除状态。
2.测试 Session 缓存
(1)准备
①hibernate.cfg.xml 文件请参看上一篇文章。
②SessionFactory、Session、Transaction
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction; @Before
public void init() {
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
session = sessionFactory.openSession();
transaction = session.beginTransaction();
} @After
public void destroy() {
transaction.commit();
session.close();
sessionFactory.close();
}
说明:使用单元测试类进行测试。因为是测试环境,不存在并发的情况,创建了一个 Session 对象。
(2)测试
@Test
public void testSession() {
News news = (News) session.get(News.class, 1);
System.out.println(news); News news2 = (News) session.get(News.class, 1);
System.out.println(news2); System.out.println(news.equals(news2));
}
测试结果:
Hibernate:
select
news0_.id as id1_0_0_,
news0_.title as title2_0_0_,
news0_.author as author3_0_0_,
news0_.date as date4_0_0_
from
hibernate.news news0_
where
news0_.id=?
News{id=1, title='Title', author='tom', date=2016-09-28}
News{id=1, title='Title', author='tom', date=2016-09-28}
true
说明:
第一次查询的时候,会将引用赋值给 news,同时向 Session 缓存中存入了一份。
第二次查询的时候,并没有发送 select 语句,而是从 Session 缓存中直接获取的。
3.操纵 Session 缓存
(1)flush() :使数据表中的记录和 Session 缓存中的对象的状态保持一致。
① 在 Transaction 的 commit() 方法中,先调用 session 的 flush 方法,再提交事务。
org.hibernate.engine.transaction.spi.AbstractTransactionImpl#commit
@Override
public void commit() throws HibernateException {
if ( localStatus != LocalStatus.ACTIVE ) {
throw new TransactionException( "Transaction not successfully started" );
} LOG.debug( "committing" ); beforeTransactionCommit(); try {
doCommit();
localStatus = LocalStatus.COMMITTED;
afterTransactionCompletion( Status.STATUS_COMMITTED );
}
catch ( Exception e ) {
localStatus = LocalStatus.FAILED_COMMIT;
afterTransactionCompletion( Status.STATUS_UNKNOWN );
throw new TransactionException( "commit failed", e );
}
finally {
invalidate();
afterAfterCompletion();
}
}
org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction#beforeTransactionCommit
protected void beforeTransactionCommit() {
this.transactionCoordinator().sendBeforeTransactionCompletionNotifications(this);
if(this.isDriver && !this.transactionCoordinator().getTransactionContext().isFlushModeNever()) {
this.transactionCoordinator().getTransactionContext().managedFlush();
} if(this.isDriver) {
this.transactionCoordinator().getTransactionContext().beforeTransactionCompletion(this);
} }
② 可能会打印 SQL 语句,但是不会提交事务。
③ 在未提交事务或显式的调用 flush() 方法前,也可能会进行 flush() 操作。
- 执行 HQL 或 QBC 查询,会先进行 flush() 操作,以得到数据表的最新记录。
- 若记录的 ID 是由数据库使用的自增的方式生成的,则在调用 save() 方法时,就会立即发送 INSERT 语句,因为 save 方法后,必须保证对象的 ID 存在。
(2)refresh():会强制发送 SELECT 语句,以使 Session 缓存中对象的状态和数据表中对应的记录保持一致。
1 @Test
2 public void testRefresh() {
3 News news = (News) session.get(News.class, 1);
4 System.out.println(news);
5 session.refresh(news);
6 System.out.println(news);
7 }
我在第5行断点,然后修改数据库中 News 的 `author` 字段,改为 jerry。执行。
两次打印结果相同。
Hibernate:
select
news0_.id as id1_0_0_,
news0_.title as title2_0_0_,
news0_.author as author3_0_0_,
news0_.date as date4_0_0_
from
hibernate.news news0_
where
news0_.id=?
News{id=1, title='Title', author='tom', date=2016-09-28}
Hibernate:
select
news0_.id as id1_0_0_,
news0_.title as title2_0_0_,
news0_.author as author3_0_0_,
news0_.date as date4_0_0_
from
hibernate.news news0_
where
news0_.id=?
News{id=1, title='Title', author='tom', date=2016-09-28}
原因:数据库的隔离级别,Mysql 默认隔离级别为 REPEATABLE READ。
在 Hibernate 的配置文件中可以显式的设置隔离级别. 每一个隔离级别都对应一个整数:
1. READ UNCOMMITED
2. READ COMMITED
4. REPEATABLE READ
8. SERIALIZEABLE
Hibernate 通过为 Hibernate 映射文件指定 hibernate.connection.isolation 属性来设置事务的隔离级别。
修改后的打印结果:
两次打印结果不同。
Hibernate:
select
news0_.id as id1_0_0_,
news0_.title as title2_0_0_,
news0_.author as author3_0_0_,
news0_.date as date4_0_0_
from
hibernate.news news0_
where
news0_.id=?
News{id=1, title='Title', author='jerry', date=2016-09-28}
Hibernate:
select
news0_.id as id1_0_0_,
news0_.title as title2_0_0_,
news0_.author as author3_0_0_,
news0_.date as date4_0_0_
from
hibernate.news news0_
where
news0_.id=?
News{id=1, title='Title', author='tom', date=2016-09-28}
(3)clear():清理缓存。
@Test
public void testClear() {
session.get(News.class, 1);
session.clear();
session.get(News.class, 1);
}
输出结果:
Hibernate:
select
news0_.id as id1_0_0_,
news0_.title as title2_0_0_,
news0_.author as author3_0_0_,
news0_.date as date4_0_0_
from
hibernate.news news0_
where
news0_.id=?
Hibernate:
select
news0_.id as id1_0_0_,
news0_.title as title2_0_0_,
news0_.author as author3_0_0_,
news0_.date as date4_0_0_
from
hibernate.news news0_
where
news0_.id=?
三、Session API
1.四种状态的转换图
(1)临时对象
- 在使用代理主键的情况下,OID 通常为 null
- 不处于 Session 的缓存中
- 在数据库中没有对应的记录
(2)持久化对象
- OID 不为空
- 位于 Session 缓存中
- 在同一个 Session 实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象
(3)游离对象
- OID 不为空
- 不处于 Session 缓存中
(4)删除对象
- 在数据库中没有和其 OID 对应的记录
- 不再处于 Session 缓存中
2.save()
(1)将一个临时对象转变为持久化对象
(2)为对象分配 ID
(3)在 flush 缓存的时候,计划执行一条 INSERT 语句
(4)在 save() 方法前的 id 是无效的
(5)持久化对象的 ID 是不能被更改的。因为 Hibernate 通过持久化对象的 OID 来维持它与数据库相关记录的对应关系。
* persist() 和 save() 区别
对一个 OID 不为 Null 的对象执行 save() 方法时,会把该对象以一个新的 OID 保存到数据库中,而 persist() 则会抛出一个异常。
3.get()/load()
(1)都可以根据 OID 从数据库中加载一个持久化对象。
(2)执行 get() 时会立即加载对象。执行 load() ,若不使用该对象,则不会立即执行查询操作,而是返回一个代理对象。
(3)get() 是立即检索,而 load() 是延迟检索。
(4)若数据表中没有对应记录,Session 也没有被关闭。get() 返回 null,load() 使用返回对象时抛出异常。
(5)load() 可能会抛出 LozyInitizationException 异常:在需要初始化代理对象之前已经关闭了 Session。
@Test
public void testLoad() {
News news = (News) session.load(News.class, 1);
session.close();
System.out.println(news);
}
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
4.update()
(1)将一个游离对象转变为持久化对象,并且计划执行一条 update 语句。
(2)若更新一个持久化对象,不需要显式的调用 update() 方法。因为在调用 Transaction 的 commit() 方法时,会先执行 session 的 flush() 方法。
(3)注意
- 无论要更新的游离对象和数据表的记录是否一致,都会发送 UPADATE 语句。如何让只在不一致的情况下发送 UPDATE 语句?在 entity.hbm.xml 文件的 class 节点设置 select-before-update=true(默认为 false)。通常不需要设置,与触发器协同工作时需要注意。
- 若数据表中没有对应的记录,但还是调用了 update() 方法,会抛出异常。
- 当 update() 方法关联一个游离对象时,如果在 Session 缓存中已经存在相同 OID 的持久化对象,会抛出异常。因为在 Session 缓存中不能有两个 OID 相同的对象。
5.saveOrUpdate()
(1)同时包含了 save() 和 update() 方法的功能。
(2)判断是否是游离对象还是临时对象是根据 对象的 OID 来判定的。若为 null ,则执行 save() ,若不为 null,则判定为游离对象,执行 update() 。
(3)若 OID 不为 null,但数据中还没有与之对应的记录,则会抛出一个异常。
(4)了解:OID 值等于 id 的 unsaved-value 属性值的对象,也被认为是一个游离对象。
6.delete()
(1)既可以删除一个游离对象,也可以删除一个持久化对象。
(2)只要 OID 和数据表中一条记录对应,就会准备执行 delete 操作,若 OID 在数据表中没有对应的记录,则抛出异常。
(3)在执行 delete() 后,还是可以获取到对象的 OID,防止对该对象的其他持久化操作,可以通过设置 hibernate 配置文件的 hibernate.use_identifier_rollback 为 true,
使删除对象后,把其 OID 值为 null。
7.evict()
把指定持久化对象从 session 缓存中移除。
8.调用存储过程
@Test
public void testWork() {
session.doWork(new Work() {
@Override
public void execute(Connection connection) throws SQLException {
System.out.println(connection);
// 调用存储过程
}
});
}
四、总结
介绍了 Hibernate 的一级缓存,包括如何操纵 Session 的缓存,以及四种状态之间的转换,以及建立在 Session 缓存和四种状态基础上的 Session API。
hiernate-session的更多相关文章
- session实现购物车
为实现简单的购物功能(购物车添加.账户查看.购物车商品删除.实时的购物商品数量及价格的计算显示.购物车商品数量可手动输入等),用session实现了一简单的以php语言为基础.连接MySQL数据库的购 ...
- Asp.net Core中使用Session
前言 2017年就这么悄无声息的开始了,2017年对我来说又是特别重要的一年. 元旦放假在家写了个Asp.net Core验证码登录, 做demo的过程中遇到两个小问题,第一是在Asp.net Cor ...
- 懒加载session 无法打开 no session or session was closed 解决办法(完美解决)
首先说明一下,hibernate的延迟加载特性(lazy).所谓的延迟加载就是当真正需要查询数据时才执行数据加载操作.因为hibernate当中支持实体对象,外键会与实体对象关联起来.如 ...
- 探索ASP.NET MVC5系列之~~~6.Session篇(进程外Session)
其实任何资料里面的任何知识点都无所谓,都是不重要的,重要的是学习方法,自行摸索的过程(不妥之处欢迎指正) 汇总:http://www.cnblogs.com/dunitian/p/4822808.ht ...
- Nhibernate的Session管理
参考:http://www.cnblogs.com/renrenqq/archive/2006/08/04/467688.html 但这个方法还不能解决Session缓存问题,由于创建Session需 ...
- nginx+iis+redis+Task.MainForm构建分布式架构 之 (redis存储分布式共享的session及共享session运作流程)
本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,上一篇分享文章制作是在windows上使用的nginx,一般正式发布的时候是在linux来配 ...
- zookeeper源码分析之六session机制
zookeeper中session意味着一个物理连接,客户端连接服务器成功之后,会发送一个连接型请求,此时就会有session 产生. session由sessionTracker产生的,sessio ...
- [转载]Cookie/Session的机制与安全
Cookie和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道.本文来详细讨论Cookie和Session的实现机制,以及其中涉及的安全问题. 因 ...
- 修改session垃圾回收几率
<?php //修改session垃圾回收几率 ini_set('session.gc_probability','1'); ini_set('session.gc_divisor','2'); ...
- Nginx反向代理,负载均衡,redis session共享,keepalived高可用
相关知识自行搜索,直接上干货... 使用的资源: nginx主服务器一台,nginx备服务器一台,使用keepalived进行宕机切换. tomcat服务器两台,由nginx进行反向代理和负载均衡,此 ...
随机推荐
- Hibernate.cfg.xml 主配置
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hiber ...
- 一道C语言安全编码题目
1.前言 最近在网上看到一道C语言题目,用C语言实现一个函数,给定一个int类型的整数,函数输出逆序的整数,例如输入123,则输出字符串"321",,输入-123,则输出字符串&q ...
- solr5.5索引mysql数据(新手总结)
一 solr5.5环境部署到Eclipse(luna版) solr部署参见:http://blog.csdn.net/csmnjk/article/details/64121765 二 Ik分词器设置 ...
- 【WPF】DispatcherFrame 是个啥玩意儿
对于 WPF 的线程模型,Dispatcher 对象相信各位大伙伴已经不陌生,尤其是跨线程更新UI的时候,都会用它来调度消息.与 Dispatcher 对象有关的,还有一个叫 DispatcherFr ...
- USACO hamming
考试周终于过去了一半,可以继续写USACO了. 先来看一下题目吧. Hamming CodesRob Kolstad Given N, B, and D: Find a set of N codewo ...
- java怎么连接mysql数据库
JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口 ...
- Mathematica 10 Mac 设置默认工作目录
用SetDirectory命令设置
- 屏幕适配/autoLayout autoresizingMask
#pragma mark-- 屏幕适配/autoLayout autoresizingMask 1> 发展历程 代码计算frame -> autoreszing(父控件和子控件的关系) - ...
- 论MyBatis日志
Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具: SLF4J Apache Commons Logging Log4j 2 Log4j JDK logging 具体选择哪个日志 ...
- asp.net中怎样调用存储过程和存储过程的写法(转载,留着自己看)
asp.net中怎样调用存储过程和存储过程的写法 创建一个只有输入参数的存储过程 create procedure proc_user@name varchar(20),@Password varch ...