hibernate学习之 Session
来源:互联网 发布:淘宝店铺首页怎么上传 编辑:程序博客网 时间:2024/05/17 22:24
Session概述
- session接口是hibernate向应用程序提供的操作数据库的最主要接口,它提供了基本的保存,更新,删除和加载java对象的方法
- session具有一个缓存,位于缓存中的对象称为持久化对象,他和数据库中的相关记录对应,session能够在某些时间点按照缓存中对象的变化来执行相关的sql语句,来同步更新数据库,这一过程被称为刷新缓存flush。
- 站在持久化的角度,hibernate把对象分为4中状态,持久化状态,临时状态,游离状态,删除状态,session特定的方法能使对象从一个状态转换到另外一个状态。
马哥的淘宝店:https://shop592330910.taobao.com/
这里我们建立一个HibernateTest测试类。其中放置了Session和Transaction成员变量,这个在开发中不能放置为成员变量,会有并发问题的,这里我们只是测试可以放置一下。
我们通过单元测试的 @Before public void init()来初始化我们成员变量,然后通过@After public void destroy() 来关闭。
public class HibernateTest { private SessionFactory sessionFactory = null; private Session session = null; private Transaction transaction = null; @Before public void init() { System.out.println("init"); //1.创建一个SessionFactory 对象,创建session的工厂的一个类 //1.1创建一个Configuration对象,对应hibernate的基本配置信息和对象关系映射信息 Configuration configuration = new Configuration().configure(); //1.2创建一个ServiceRegistry对象,hibernate4.x新添加的对象,hibernate任何的配置和服务都要在该对象中注册才能有效。 ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); //1.3 sessionFactory = configuration.buildSessionFactory(serviceRegistry); //2.创建一个Session对象,这个和jdbc中的connection很类似 session = sessionFactory.openSession(); //3.开启事务 transaction = session.beginTransaction(); } //马哥的淘宝店:https://shop592330910.taobao.com/ @After public void destroy() { System.out.println("destroy"); //5.提交事务 transaction.commit(); //6.关闭session对象 session.close(); //7.关闭SessionFactory 对象 sessionFactory.close(); //马哥的淘宝店:https://shop592330910.taobao.com/ } @Test public void testSession() { //4.执行保存操作 News news = new News("title:java", "author: mamh", new Date(new java.util.Date().getTime())); session.save(news); Object o = session.get(News.class, 1); System.out.println(o); //马哥的淘宝店:https://shop592330910.taobao.com/ }
session的缓存
@Test public void testSession() { //4.执行保存操作 //News news = new News("title:java", "author: mamh", new Date(new java.util.Date().getTime())); //session.save(news); Object news1 = session.get(News.class, 1); System.out.println(news1); Object news2 = session.get(News.class, 1); System.out.println(news2); }
这个代码的输出,从中我们可以看到news对象打印了两遍,但是sql语句只打印了一边,说明第二次没有去执行sql语句。这个是一级缓存。一级缓存是session级别的。
Hibernate: select news0_.hb_id as hb1_0_0_, news0_.hb_title as hb2_0_0_, news0_.hb_author as hb3_0_0_, news0_.hb_date as hb4_0_0_ from atguigu.hb_news news0_ where news0_.hb_id=?News{id=1, title='java', author='sun', date=2017-10-18}News{id=1, title='java', author='sun', date=2017-10-18}destroyProcess finished with exit code 0
session缓存的flush()方法
@Test public void testSessionFlush(){ News news = (News) session.get(News.class, 1); System.out.println(news); news.setAuthor("mamh"); }
Hibernate: select news0_.hb_id as hb1_0_0_, news0_.hb_title as hb2_0_0_, news0_.hb_author as hb3_0_0_, news0_.hb_date as hb4_0_0_ from atguigu.hb_news news0_ where news0_.hb_id=?News{id=1, title='java', author='mamh', date=2017-10-18}=destroy=Hibernate: update atguigu.hb_news set hb_title=?, hb_author=?, hb_date=? where hb_id=?Process finished with exit code 0
在执行(News) session.get(News.class, 1)
会调用select查询数据库的,后面的news.setAuthor("mamh");
设置对象一个新的属性,这个时候会调用update的更新数据库的方法的。
这个是因为session发现缓存中的对象被更改了,然后会调用flush()。修改对象属性的时候session的可以感知到的,在提交事务之前会执行update方法的。在调用commit()方法的时候会先进行flush,然后在执行commit。
flush()的作用:数据库表中的记录和session缓存中的对象保持一致。为了保持一致有可能会发送对应的sql语句。对象状态一模一样是不会发送sql语句的。
在transaction.commit();
中的commit()方法中先调用session的flush()然后在调用commit()。flush()方法可能会发送sql语句,但是不会提交事务的,只有提交事务之后数据库表中的数据才会变化。
flush()什么时候会被调用:
注意:在未提交事务或显示的调用flush()方法之前也有可能会进行flush操作的。
- 执行HQL或QBC查询,会先进行flush操作,以得到数据表的最新的记录。
- 若记录的ID是有底层数据库使用自增方式生成的,则调用save()之后就会立即发送insert语句,save之后必须保证对象的id是存在的。
session缓存的refresh()方法
refresh()方法会强制发送select语句,以使session缓存中对象的状态和数据库表中对应的保持一致。
session缓存的clear()方法
清理缓存
@Test public void testClear(){ News news0 = (News) session.get(News.class, 1); session.clear(); News news1 = (News) session.get(News.class, 1); }
Hibernate: select news0_.hb_id as hb1_0_0_, news0_.hb_title as hb2_0_0_, news0_.hb_author as hb3_0_0_, news0_.hb_date as hb4_0_0_ from atguigu.hb_news news0_ where news0_.hb_id=?Hibernate: select news0_.hb_id as hb1_0_0_, news0_.hb_title as hb2_0_0_, news0_.hb_author as hb3_0_0_, news0_.hb_date as hb4_0_0_ from atguigu.hb_news news0_ where news0_.hb_id=?
第一次调用获取new对象的时候会发送一条select查询语句的,然后调用了session的clear()方法,清空缓存了,第二次在调用获取new对象的时候会再次发送一条select查询语句。
session中的save()和perssit()方法
@Test public void testPersist() { //和save()方法很类似,区别: //在调用persist方法之前,调用了setId(),对象已经有了ID了,则不会执行insert操作,会抛出异常 News news = new News(); news.setAuthor("mm"); news.setTitle("ssssssssss"); news.setDate(new Date(new java.util.Date().getTime())); news.setId(234234); session.persist(news); } @Test public void testSave() { //把临时对象变为持久化对象 //为对象分配ID,在save()方法之前设置ID是无效的,save()之后也是不能改这个ID的 //持久化的对象的ID是不能进行修改的 //在flush缓存时候会发送一条insert语句 //把临时对象保存到数据库中 News news = new News(); news.setAuthor("mm"); news.setTitle("ssssssssss"); news.setDate(new Date(new java.util.Date().getTime())); session.save(news); }
session中的get()和load()方法
load和get的区别:
get会立即加载对象,load方法若不用该对象则不会立即查询,而返回一个代理对象。
get立即检索,load是延迟检索。
若数据表中没有对应的记录,session也没有关闭,同时要使用该对象时候:get返回null,load抛出异常。
load方法可能会抛出懒加载异常:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
在需要初始化代理对象之前关闭了session就会抛出这个异常。
@Test public void testLoad(){ //load和get的区别: //get会立即加载对象,load方法若不用该对象则不会立即查询,而返回一个代理对象。 //get立即检索,load是延迟检索。 //若数据表中没有对应的记录,session也没有关闭,同时要使用该对象时候:get返回null,load抛出异常。 //load方法可能会抛出懒加载异常: // org.hibernate.LazyInitializationException: could not initialize proxy - no Session // 在需要初始化代理对象之前关闭了session就会抛出这个异常。 News news1 = (News) session.load(News.class, 10); //session.close(); System.out.println(news1); } @Test public void testGet(){ News news1 = (News) session.get(News.class, 1); System.out.println(news1); }
session的update()方法
若更新一个持久化对象,不需要显示的调用update()方法,因为在调用transaction的commit方法时候,会先执行flush方法的。
更新一个游离对象,需要显示的调用session的update()方法,可以把游离对象变为持久化对象。
无论要更新的对象 是否和数据库表中的记录是否一致都会发送update语句的。
@Test public void testUpdate(){ //若更新一个持久化对象,不需要显示的调用update()方法,因为在调用transaction的commit方法时候,会先执行flush方法的。 //更新一个游离对象,需要显示的调用session的update()方法,可以把游离对象变为持久化对象。 //无论要更新的对象 是否和数据库表中的记录是否一致都会发送update语句的。因为是第二次开的一个新的session。 News news = (News) session.get(News.class, 1); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); //这个时候news对象已经变成游离对象了,应为前面关闭了session,后续又重新打开了session。 news.setAuthor("sun"); System.out.println(news); //session.update(news); }
Hibernate: select news0_.hb_id as hb1_0_0_, news0_.hb_title as hb2_0_0_, news0_.hb_author as hb3_0_0_, news0_.hb_date as hb4_0_0_ from atguigu.hb_news news0_ where news0_.hb_id=?News{id=1, title='java', author='oracle', date=2017-10-18}Hibernate: update atguigu.hb_news set hb_title=?, hb_author=?, hb_date=? where hb_id=?
如何让update盲目的发送update语句呢?在.hbm.xml 中设置select-before-update=”true”(默认false),通常不设置为true,会影响效率。
若数据库表中没有对应的记录还继续调用update()方法,这时候会抛出异常。
@Test public void testUpdate(){ //若更新一个持久化对象,不需要显示的调用update()方法,因为在调用transaction的commit()方法时候,会先执行flush()方法的。 //更新一个游离对象,需要显示的调用session的update()方法,可以把游离对象变为持久化对象。 //无论要更新的对象 是否和数据库表中的记录是否一致都会发送update语句的 //如何让update盲目的发送update语句呢?在.hbm.xml 中设置select-before-update="true"(默认false),通常不设置为true,会影响效率。 //若数据库表中没有对应的记录还继续调用update()方法,这时候会抛出异常。 News news = (News) session.get(News.class, 1); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); //这个时候news对象已经变成游离对象了,应为前面关闭了session,后续又重新打开了session。 news.setAuthor("sun"); news.setId(120); System.out.println(news); session.update(news); }
同一个session中不能有ID相同的对象,会抛出异常NonUniqueObjectException
@Test public void testUpdate(){ //若更新一个持久化对象,不需要显示的调用update()方法,因为在调用transaction的commit方法时候,会先执行flush方法的。 //更新一个游离对象,需要显示的调用session的update()方法,可以把游离对象变为持久化对象。 //无论要更新的对象 是否和数据库表中的记录是否一致都会发送update语句的 //如何让update盲目的发送update语句呢?在.hbm.xml 中设置select-before-update="true"(默认false),通常不设置为true,会影响效率。 //若数据库表中没有对应的记录还继续调用update()方法,这时候会抛出异常。 //同一个session中不能有ID相同的对象,会抛出异常NonUniqueObjectException News news = (News) session.get(News.class, 1); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); //这个时候news对象已经变成游离对象了,应为前面关闭了session,后续又重新打开了session。 News news2 = (News) session.get(News.class, 1); news.setAuthor("sun"); session.update(news); }
session的saveOrUpdate()方法
@Test public void testSaveOrUpdate() { News news = new News("ff", "fff", new Date(new java.util.Date().getTime())); session.saveOrUpdate(news); }
这个没有ID,这个时候会执行insert语句。
Hibernate: insert into atguigu.hb_news (hb_title, hb_author, hb_date) values (?, ?, ?)
如果有ID:会执行update语句
@Test public void testSaveOrUpdate() { News news = new News("ff", "fff", new Date(new java.util.Date().getTime())); news.setId(1); session.saveOrUpdate(news); }
Hibernate: select news_.hb_id, news_.hb_title as hb2_0_, news_.hb_author as hb3_0_, news_.hb_date as hb4_0_ from atguigu.hb_news news_ where news_.hb_id=?Hibernate: update atguigu.hb_news set hb_title=?, hb_author=?, hb_date=? where hb_id=?
如果有id,但是没有对应的记录,这个时候会抛出异常
@Test public void testSaveOrUpdate() { News news = new News("ff", "fff", new Date(new java.util.Date().getTime())); news.setId(23121); session.saveOrUpdate(news); }
session的delete方法
执行删除操作,只要OID和数据库表中的记录对应就会执行删除操作,如果没有对应的记录就抛出异常。
@Test public void testDelete() { //执行删除操作,只要OID和数据库表中的记录对应就会执行删除操作,如果没有对应的记录就抛出异常。 News news = new News("ff", "fff", new Date(new java.util.Date().getTime())); news.setId(1); session.delete(news); }
Hibernate: delete from atguigu.hb_news where hb_id=?
可以通过设置hibernate配置文件use_identifier_rollback属性为true,是删除对象后,把其OID置为null
@Testpublic void testDelete() { //执行删除操作,只要OID和数据库表中的记录对应就会执行删除操作,如果没有对应的记录就抛出异常。 //可以通过设置hibernate配置文件use_identifier_rollback属性为true,是删除对象后,把其OID置为null News news = new News(8, "ff", "fff", new Date(new java.util.Date().getTime())); System.out.println(news); session.delete(news); System.out.println(news);}
session的evict()方法,从缓存中移除某个对象
@Test public void testEvict(){ News news1 = (News) session.get(News.class, 1); news1.setAuthor("11"); News news2 = (News) session.get(News.class, 2); news2.setAuthor("=============="); // session.evict(news1);//加了这一句就不会更新到数据库中了 }
new 语句 –> 临时对象
|
|
持久化对象
|
|
|
游离状态
通过hibernate调用存储过程
@Test public void testDoWork(){ session.doWork(new Work() { public void execute(Connection connection) throws SQLException { //在这个里面调用存储过程 System.out.println(connection); } }); }
输出:org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler@7526515b[valid=true]
hibernate与触发器协同工作(了解)
hibernate与触发器协同工作时会造成两类问题
触发器使session的缓存中的持久化对象与数据库中对应的数据不一致,触发器运行在数据库中,它执行的操作对session是透明的。
session的update方法盲目的激发触发器,无论游离对象的属性是否发生变化,都会执行update语句,而update语句会激发数据库中相应的触发器
解决方法:
在执行完session的相关操作后,立即调用session的flush和refresh方法,迫使session的缓存与数据库同步
在映射文件的class元素中设置select-before-update属性,当session的update或saveOrUpdate方法更新一个游离对象时,会先执行select语句,获得当前游离对像在数据库中的最新数据,只有在不一致的情况下才会执行update语句。
- hibernate学习之 Session
- hibernate学习之 session的产生方式
- Hibernate学习笔记之Session管理
- 7.7--SSH学习之Hibernate Session
- Hibernate学习笔记 之 configuration、sessionFactory、session
- Spring学习之(Hibernate)Session接口
- Hibernate学习---第十五节:hibernate之session线程安全
- Hibernate学习之------>Hibernate中Session.load与Session.get的区别
- Hibernate 之 session
- Hibernate之session
- Hibernate之session
- Hibernate之Session.flush()
- Hibernate之session
- hibernate之session方法
- hibernate之session缓存
- hibernate 之session 事务管理
- Hibernate开发之session
- 北软实训之hibernate session
- Eclipse安装反编译插件
- [PAT]1028. List Sorting (25)@Java实现
- Android特效开发(仿zaker用手向上推动的效果(推动门效果))
- ECharts_05_折线图
- Java学习笔-----------面试题
- hibernate学习之 Session
- 线程安全(一)
- Vim基本命令
- break-word;
- 线上集群服务器性能参数查看命令
- Eclipse快捷键
- 【Codeforces717F】Heroes of Making Magic III
- 机器学习-神经网络之激活函数(Activation Function)
- Apache Flink:详细入门