Hibernate - SessionFactory和Session详解
【1】SessionFactory 接口
SessionFactory 接口是针对单个数据库映射关系经过编译后的内存镜像,是线程安全的。
SessionFactory 对象一旦构造完毕,即被赋予特定的配置信息。
SessionFactory是生成Session的工厂,构造 SessionFactory 很消耗资源,一般情况下一个应用中只初始化一个 SessionFactory 对象。
Hibernate4 新增了一个 ServiceRegistry 接口,所有基于 Hibernate 的配置或者服务都必须统一向这个 ServiceRegistry 注册后才能生效
Hibernate4.0之前创建 SessionFactory 的步骤:
// 创建 Configuration 对象: 对应 hibernate 的基本配置信息和 对象关系映射信息
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");//4.0 之前这样创建
SessionFactory sessionFactory = configuration.buildSessionFactory();
Configuration 类负责管理 Hibernate 的配置信息。包括如下内容:
- Hibernate 运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类,数据库Dialect,数据库连接池等(对应 hibernate.cfg.xml 文件)。
- 持久化类与数据表的映射关系(*.hbm.xml 文件)
Hibernate4.X中创建 SessionFactory 的步骤:
// 创建一个 ServiceRegistry 对象: hibernate 4.x 新添加的对象
//hibernate 的任何配置和服务都需要在该对象中注册后才能有效.ServiceRegistry serviceRegistry =
new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
//或如下方式
StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();//创建一个 SessionFactory 对象
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Hibernate5.X中创建 SessionFactory 的步骤:
StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().configure().build();
SessionFactory sessionFactory = new MetadataSources(ssr).buildMetadata().buildSessionFactory();
【2】Session 接口
Session 是应用程序与数据库之间交互操作的一个单线程对象,生命周期很短,是 Hibernate 运作的中心,所有持久化对象必须在 session 的管理下才可以进行持久化操作(持久化类与 Session 关联起来后就具有了持久化的能力)。
Session 接口是 Hibernate 向应用程序提供的操作数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载 Java 对象的方法。
Session 类的方法:
- 取得持久化对象的方法: get(), load()
- 持久化对象都得保存,更新和删除:save(),update(),saveOrUpdate(),delete()
- 开启事务: beginTransaction().
- 管理 Session 的方法:isOpen(),flush(), clear(), evict(), close()等
Session 对象有一个一级缓存,显式执行 flush 之前,所有的持久层操作的数据都缓存在 session 对象处,位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应。
Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为刷新缓存(flush)。
站在持久化的角度, Hibernate 把对象分为 4 种状态: 持久化状态, 临时状态, 游离状态, 删除状态。 Session 的特定方法能使对象从一个状态转换到另一个状态。
① session缓存 - 一级缓存
在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存。 只要 Session 实例没有结束生命周期, 且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期。
Session 缓存可减少 Hibernate 应用程序访问数据库的频率。
测试代码如下:
@Beforepublic void init(){StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().configure().build();sessionFactory = new MetadataSources(ssr).buildMetadata().buildSessionFactory();session = sessionFactory.openSession();transaction = session.beginTransaction();}@Afterpublic void destroy(){transaction.commit();session.close();sessionFactory.close();}@Testpublic void test1(){News news = (News) session.get(News.class, 1);System.out.println(news); News news2 = (News) session.get(News.class, 1);System.out.println(news2);}
测试结果如下图:
本质上用的是同一个session,由于session一级缓存关系,在第一次发送SQL语句查询后第二次直接使用缓存中的数据,不会再发送SQL。除非session缓存被清空!
如下图所示,Hibernate提供了三种方式操作session缓存:
② 缓存操作之flush
flush:Session 按照缓存中对象的属性变化来同步更新数据库。
默认情况下 Session 在以下时间点刷新缓存:
- 显式调用 Session 的 flush() 方法;
- 当应用程序调用 Transaction 的 commit()方法的时, 该方法先 flush ,然后再向数据库提交事务;
- 当应用程序执行一些查询(HQL, Criteria)操作时,如果缓存中持久化对象的属性已经发生了变化,会先 flush 缓存,以保证查询结果能够反映持久化对象的最新状态。
- 设定刷新缓存的时间点
若希望改变 flush 的默认时间点, 可以通过 Session 的 setFlushMode() 方法显式设定 flush 的时间点 :
清理缓存的模式 | 各种查询方法 | Transaction.commit() | Session.flush() |
---|---|---|---|
FlushMode.AUTO(默认) | 清理 | 清理 | 清理 |
FlushMode.COMMIT | 不清理 | 清理 | 清理 |
FlushMode.NEVER | 不清理 | 不清理 | 清理 |
- flush 缓存的例外情况
如果对象使用 native 生成器生成 OID, 那么当调用 Session 的 save() 方法保存对象时, 会立即执行向数据库插入该实体的 insert 语句。因为 save 方法后, 必须保证对象的 ID 是存在的 !
- commit() 和 flush() 方法的区别
flush 操作可能会执行一系列 sql 语句,但不提交事务;commit 方法先调用flush() 方法,然后提交事务。提交事务意味着对数据库操作永久保存下来。
测试代码如下:
@Testpublic void testSessionFlush(){News news = (News) session.get(News.class, 1);news.setAuthor("Hibernate");session.flush();System.out.println("flush");//这里打断点,debugNews news2 = (News) session.createCriteria(News.class).list().get(0);System.out.println(news2);//这里打断点,debug,并注释掉session.flush()}
③ 缓存操作之refresh
refresh()会强制发送 SELECT 语句, 以使 Session 缓存中对象的状态和数据表中对应的记录保持一致!
测试代码如下:
@Testpublic void testRefresh(){News news = (News) session.get(News.class, 1);System.out.println(news);session.refresh(news); //这里打断点,手动改数据库System.out.println(news); }
测试结果如下:
Hibernate: selectnews0_.ID as ID1_0_0_,news0_.TITLE as TITLE2_0_0_,news0_.AUTHOR as AUTHOR3_0_0_,news0_.DESCRIBLE as DESCRIBL4_0_0_,news0_.DATE as DATE5_0_0_,news0_.CONTENT as CONTENT6_0_0_,news0_.PICTURE as PICTURE7_0_0_ fromNEWS news0_ wherenews0_.ID=?
News [id=1, title=hibernate, author=Oracle, describle=orm, date=2018-10-04 11:39:38.0, content=null, picture=null]//这里再次发送了查询语句
Hibernate: selectnews0_.ID as ID1_0_0_,news0_.TITLE as TITLE2_0_0_,news0_.AUTHOR as AUTHOR3_0_0_,news0_.DESCRIBLE as DESCRIBL4_0_0_,news0_.DATE as DATE5_0_0_,news0_.CONTENT as CONTENT6_0_0_,news0_.PICTURE as PICTURE7_0_0_ fromNEWS news0_ wherenews0_.ID=?
News [id=1, title=hibernate, author=Oracle, describle=orm, date=2018-10-04 11:39:38.0, content=null, picture=null]//但是结果并没有改变--在debug断点处手动改变了Oracle为JPA。
可以看到refresh已经工作,但是news并非最新状态,为什么?
这是由于MySQL中事务隔离级别导致的。MySQL默认的事务隔离级别为可重复读,即在一个事务内,虽然refresh又进行了一次查询,但是读取的数据还是该事务中第一次读取的数据,非最新数据!
- 在 Hibernate 中设置隔离级别
JDBC 数据库连接使用数据库系统默认的隔离级别。在 Hibernate 的配置文件中可以显式的设置隔离级别. 每一个隔离级别都对应一个整数:
1. READ UNCOMMITED
2. READ COMMITED
4. REPEATABLE READ
8. SERIALIZEABLE
Hibernate 通过为 Hibernate 映射文件指定 hibernate.connection.isolation 属性来设置事务的隔离级别。
<!-- 设置 Hibernate 的事务隔离级别 2表示读已提交 -->
<property name="connection.isolation">2</property>
再次测试refresh方法结果如下:
Hibernate: selectnews0_.ID as ID1_0_0_,news0_.TITLE as TITLE2_0_0_,news0_.AUTHOR as AUTHOR3_0_0_,news0_.DESCRIBLE as DESCRIBL4_0_0_,news0_.DATE as DATE5_0_0_,news0_.CONTENT as CONTENT6_0_0_,news0_.PICTURE as PICTURE7_0_0_ fromNEWS news0_ wherenews0_.ID=?
News [id=1, title=hibernate, author=JPA, describle=orm, date=2018-10-04 11:39:38.0, content=null, picture=null]
Hibernate: selectnews0_.ID as ID1_0_0_,news0_.TITLE as TITLE2_0_0_,news0_.AUTHOR as AUTHOR3_0_0_,news0_.DESCRIBLE as DESCRIBL4_0_0_,news0_.DATE as DATE5_0_0_,news0_.CONTENT as CONTENT6_0_0_,news0_.PICTURE as PICTURE7_0_0_ fromNEWS news0_ wherenews0_.ID=?
News [id=1, title=hibernate, author=Oracle, describle=orm, date=2018-10-04 11:39:38.0, content=null, picture=null]
可以看到两个news中author已经不同!
参考博文:
MySQL中事务详解;
一文读懂Spring事务和MySQL事务。
④ 缓存操作之clear
clear()将会清理掉session的缓存。
测试代码如下:
@Testpublic void testClear(){News news1 = (News) session.get(News.class, 1);session.clear();News news2 = (News) session.get(News.class, 1);}
测试结果如下:
Hibernate: selectnews0_.ID as ID1_0_0_,news0_.TITLE as TITLE2_0_0_,news0_.AUTHOR as AUTHOR3_0_0_,news0_.DESCRIBLE as DESCRIBL4_0_0_,news0_.DATE as DATE5_0_0_,news0_.CONTENT as CONTENT6_0_0_,news0_.PICTURE as PICTURE7_0_0_ fromNEWS news0_ wherenews0_.ID=?
Hibernate: selectnews0_.ID as ID1_0_0_,news0_.TITLE as TITLE2_0_0_,news0_.AUTHOR as AUTHOR3_0_0_,news0_.DESCRIBLE as DESCRIBL4_0_0_,news0_.DATE as DATE5_0_0_,news0_.CONTENT as CONTENT6_0_0_,news0_.PICTURE as PICTURE7_0_0_ fromNEWS news0_ wherenews0_.ID=?
可以看到,发送了两条查询语句!
Hibernate - SessionFactory和Session详解相关推荐
- hibernate.hbm2ddl.auto配置详解
hibernate.hbm2ddl.auto配置详解 http://www.cnblogs.com/feilong3540717/archive/2011/12/19/2293038.html hib ...
- Hibernate对象关系映射详解之一对多关系映射
Hibernate对象关系映射详解之"一对多"关系映射 之前学习Hibernate框架的时候,对这七大关系映射一直是云里雾里的,虽然可以仿照写出代码,但是不能独立编写出来.鉴于工作 ...
- JavaWeb 入门篇 (5) Cookie 和 Session 详解
Cookie 和 Session 详解 一.会话的概念 会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话. 有状态会话:一个同学来过 ...
- java 登录session_JavaWeb Session详解
记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + ## Session的由来 上一篇博文介绍了Cookie的相关知识,其中介绍了必须采用一种机制来唯一标识一个用户,同时记录该用户的状态. ...
- cookie 和 session 详解
cookie 和 session 详解 文章目录 cookie 和 session 详解 一.Cookie机制 1.Cookie引入 2.什么是Cookie 3.Cookie的不可跨域名性 4. Un ...
- cookie与session详解、url地址重写
cookie与session详解.url地址重写:https://www.cnblogs.com/l199616j/p/11195667.html
- Hibernate Validation校验注解详解
在前后端传递数据的时候,往往后端需要校验传递数据的格式,比如用户名的格式,密码是否为空.我们可以在service层编写代码判断,但是当我们在多处需要校验传递来的数据的时候,就会出现大量重复的代码,一旦 ...
- Hibernate入门(二)——hibernateAPI详解
Hibernate API 详解 1.Configuration 功能:配置加载类,用于加载主配置,orm元数据加载 .创建: Configuration conf = new Configurati ...
- hibernate(七) hibernate中查询方式详解
序言 之前对hibernate中的查询总是搞混淆,不明白里面具体有哪些东西.就是因为缺少总结.在看这篇文章之前,你应该知道的是数据库的一些查询操作,多表查询等,如果不明白,可以先去看一下 MySQL数 ...
最新文章
- DataTable的Compute功能详解
- FPGA配置 - 基于SPI FLASH的FPGA多重配置(Xilinx)
- 自定义Background
- django 三天写个人博客
- 【PP生产订单】入门介绍(四)
- python sum 数组原理_Python - Sum 4D数组
- ebs 供应商地点信息_供应商,地址,业务实体,地点关联银行账户
- C# GDI绘制波形图
- 阶段3 2.Spring_04.Spring的常用注解_6 用于注入数据的注解
- Quartz定时器实现
- The run destination''''is not valid for Running the scheme
- linux 批量删除任务,Linux-Shell脚本学习心得之批量创建、删除用户
- Python moviepy 快速视频剪辑编辑神器
- 前端js,将英文字符转换大小写
- 数学之美2 - 概率篇
- 企业微信可以统计加班时长吗?如何查看?
- 【数据库】四(1)、数据查询之单表查询
- canvas孙悟空脚踩白云今年是猴年
- 安卓drawable基本属性corners、solid、gradient、stroke、size、padding详解
- ZigBee协议栈简介和流程