Hibernate深入Session
来源:互联网 发布:mac软件卸载不了 编辑:程序博客网 时间:2024/06/15 14:06
session概述
Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法.
session的产生方式
session的产生方法一
session的产生方法二
配置hibernate.cfg.xml文件
测试session的产生方式
package cn.itcast.hibernate0909.session;import java.lang.annotation.Target;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.junit.Test;import cn.itcast.hibernate0909.onetomany.doubl.Classes;/** * * hibernate中的crud操作是利用session来完成的 * * hibernate中的事务是依赖于session环境的 * * session的产生的方式 * * sessionFactory.openSession * 每次都会新创建一个session,只要新创建一个session,hibernate都会打开应用程序和数据库的连接 * 所以这种方式效率比较低 * * sessionFactory.getCurrentSession * * 如果当前线程中没有session,先openSession,然后把session存放到当前线程中 * * 从当前线程中得到session * * crud操作必须有事务环境 * * 不用手动去close掉 * * session的一级缓存 * @author Administrator * */public class SessionTest { private static SessionFactory sessionFactory; static{ Configuration configuration = new Configuration(); //加载配置文件 configuration.configure("cn/itcast/hibernate0909/session/hibernate.cfg.xml"); //采用了工厂模式创建sessionFactory sessionFactory = configuration.buildSessionFactory(); } private void testSession(String name){ Session session = sessionFactory.getCurrentSession(); //Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); //classes.setCname(name); //transaction.commit(); //session.close(); } @Test public void test(){ SessionTest sessionTest = new SessionTest(); sessionTest.testSession("aaa"); }}
junit测试结果
session产生方式总结
* * hibernate中的crud操作是利用session来完成的 * * hibernate中的事务是依赖于session环境的 * * session的产生的方式 * * sessionFactory.openSession * 每次都会新创建一个session,只要新创建一个session,hibernate都会打开应用程序和数据库的连接 * 所以这种方式效率比较低 * * sessionFactory.getCurrentSession * * 如果当前线程中没有session,先openSession,然后把session存放到当前线程中 * * 从当前线程中得到session * * crud操作必须有事务环境 * * 不用手动去close掉 * * session的一级缓存
理解session的缓存
- 在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期
- 当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。没有在查询数据库
session.get方法
junit测试结果:
可以看出只查询了一次数据库
session.save方法
junit测试结果:
可以看出并没有发出select语句去查询班级
session.update方法
junit测试结果:
可以看出第二次查询并没有发出select语句去查询班级
清理session的缓存
- Session 具有一个缓存, 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点,
按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为清理缓存(flush) - 默认情况下 Session 在以下时间点清理缓存:
- 当应用程序调用 Transaction 的 commit()方法的时,
该方法先清理缓存(session.flush()),然后在向数据库提交事务(tx.commit()) - 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先清理缓存,以保证查询结果能够反映持久化对象的最新状态
- 显式调用 Session 的 flush() 方法.
- 当应用程序调用 Transaction 的 commit()方法的时,
区别:
flush: 进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步 执行一些列sql语句,但不提交事务,;
commit:先调用flush() 方法,然后提交事务. 则意味着提交事务意味着对数据库操作永久保存下来。
reresh:刷新,让session和数据库同步,执行查询,把数据库的最新信息显示出来,更新本地缓存的对象状态.
clear:清空缓存,等价于list.removeAll();
session.flush方法
junit测试结果:
junit测试结果:
session.flush方法总结
session.flush方法 hibernate内部会去检查session缓存中的所有的对象 如果该对象是持久化对象,并且该对象的ID在数据库中有对应的记录,并且该对象的属性 有变化,则会自动发出update语句,如果该对象的属性没有变化,则不发出update语句 检查持久化对象中是否有关联的对象,如果有关联的对象,并且设置了级联操作,这个时候 会检查级联对象的id在数据库中有没有对应的记录,如果有,则发出update语句,如果没有,则 发出insert语句 如果有维护关系的代码,则还会改变关系 全部检查完成以后,就发出sql语句,把一级缓存中的内容同步到数据库中
session.reflush方法总结
junit测试结果:
利用Session缓存读取持久化对象的数据
1 Customer c = new Customer(“TOM”,new HashSet());2 session.save(c); //customer对象被持久化,并且加入到session的缓存中 3 Long id = c.getId();4 c = null; //c变量不再引用customer对象 5 //从session缓存中读取customer对象,使c2变量引用customer对象6 Customer c2 = (Customer)session.load(Customer.class,id);7 tx.commit(); //缓存中的对象和数据库同步8 session.close(); //关闭session 清空缓存9 System.out.println(c2.getName()); //访问customer对象10 C2 = null; //C2对象不再引用customer对象,customer对象结束生命周期
缓存的作用:
1。减少访问数据库的频率。
2。保证缓存中的对象与数据库中的相关记录保持同步。
Session执行批量操作
可以写一个for循环,Session可以批量插入上万条数据。如下面的代码:
For(int i=0;i<10000;i++){ Session.save(object); }
这样写的代码会产生一个什么问题?会使一万个对象的缓存全部存在于内存中,这样做加大了内存的压力。所以应该定期清理session的缓存,也就是flush一下,这样内存才能保证足够的空间。
Session.load与session.get方法
不同场合的不同解决方案
场合一:当用户要取数据库的一张表的一个字段,这个字段很可能就是一个字符,总而言之长度是比较短的。
场合二:当用户要取数据库的一张表的一个字段的值,而这个值很可能是blob类型,也许存取的是一个很大的视频文件。
两种场合的取数据的方法一样吗?是用load还是用get方法?
一级缓存的测试源码
package cn.itcast.hibernate0909.session.cache;import java.util.Set;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.junit.Test;import cn.itcast.hibernate0909.onetomany.doubl.Classes;import cn.itcast.hibernate0909.onetomany.doubl.Student;/** * 1、一级缓存的生命周期 * 一级缓存在session中存放,只要打开session,一级缓存就存在了,当session关闭的时候,一级缓存就不存在了 * 2、一级缓存是依赖于谁存在的 * 依赖于session存在的 * 3、怎么样把数据存放到一级缓存中 * 利用session.get、update、save * 4、怎么样从一级缓存中获取数据 * 利用session.get方法可以获取数据 * 5、怎么样把缓存中的数据同步到数据库 * * 只要是一个持久化状态的数据就在一级缓存中 * * 利用session.flush方法 * 6、怎么样把数据库的数据同步到一级缓存中 * session.reflesh方法 只能同步一个对象 * 7、一级缓存的特性 * 也叫session级别的缓存 * session中存放私有数据 * 可以通过新建session和从当前线程中获取session保证数据的安全性 * 8、从一级缓存中清楚某一个对象 * session.evcit方法 并且把一个对象从持久化状态转化成脱管状态 * 9、清空一级缓存中所有的数据 * @author Administrator * */public class OneCacheTest { private static SessionFactory sessionFactory; static{ Configuration configuration = new Configuration(); //加载配置文件 configuration.configure("cn/itcast/hibernate0909/session/hibernate.cfg.xml"); //采用了工厂模式创建sessionFactory sessionFactory = configuration.buildSessionFactory(); } /** * session.get方法 * * 通过该方法得到的对象是一个持久化对象 * * 通过该方法可以把该对象存放到一级缓存中(session缓存中) */ @Test public void testGet(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); session.get(Classes.class, 1L); transaction.commit(); } /** * session.save方法 * * 可以把一个对象变成持久化状态的对象 * * 可以把一个对象放入到一级缓存中 */ @Test public void testSave(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = new Classes(); classes.setCname("重点班"); classes.setDescription("高材生"); session.save(classes); Classes classes2 = (Classes)session.get(Classes.class, classes.getCid()); transaction.commit(); } /** * session.update方法 * * 能把一个对象的状态转化成持久化状态 * * 能把一个对象存放到一级缓存中 */ @Test public void testUpdate(){ /** * 1、利用get方法获取 * 2、利用session.evict方法清空 * 3、再利用update方法 * 4、再用get方法获取 */ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 2L); session.evict(classes);//用session.evict方法清空 classes.setDescription("aaa"); session.update(classes); Classes classes2 = (Classes)session.get(Classes.class,2L); transaction.commit(); } @Test public void testFlush(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); //持久化状态的数据 Classes classes = (Classes)session.get(Classes.class, 1L); Set<Student> students = classes.getStudents(); for(Student student:students){ student.setClasses(null); } Student student = new Student(); student.setSname("菜肉哥!"); student.setDescription("厉害!!!!!"); Student student2 = new Student(); student2.setSname("包子哥!"); student2.setDescription("真厉害!!!!!");// student.setClasses(classes);// student2.setClasses(classes); students.add(student); students.add(student2); /** * session.flush方法 * * hibernate内部会去检查session缓存中的所有的对象 * * 如果该对象是持久化对象,并且该对象的ID在数据库中有对应的记录,并且该对象的属性 * 有变化,则会自动发出update语句,如果该对象的属性没有变化,则不发出update语句 * * 检查持久化对象中是否有关联的对象,如果有关联的对象,并且设置了级联操作,这个时候 * 会检查级联对象的id在数据库中有没有对应的记录,如果有,则发出update语句,如果没有,则 * 发出insert语句 * * 如果有维护关系的代码,则还会改变关系 * * 全部检查完成以后,就发出sql语句,把一级缓存中的内容同步到数据库中 */ session.flush(); transaction.commit(); } @Test public void testFlush2(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Student student1 = (Student)session.get(Student.class, 1L); Student student2 = (Student)session.get(Student.class, 2L); student1.getClasses().setCname("aaa"); student2.getClasses().setDescription("asdf"); session.flush(); transaction.commit(); } @Test public void testReflesh(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.get(Classes.class, 1L); classes.setCname("bbb"); //把一个对象对应的数据库的数据重新更新到一级缓存中 session.refresh(classes); session.clear();//清空一级缓存中的所有的数据 classes = (Classes)session.get(Classes.class, 1L); System.out.println(classes.getCname()); transaction.commit(); } /** * 批量操作 */ @Test public void testBatchSave(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); for(int i=0;i<100000;i++){ if(i%50==0){ session.flush(); session.clear(); } Classes classes = new Classes(); classes.setCname(i+"aaa"); session.save(classes); } transaction.commit(); }}
延迟加载
类的延迟加载
lazy 为true或者为false
断点debug运行发现在classes.getCname();发出sql语句
lazy 设置为false重新测试
断点debug运行发现在session.load(Classes.class, 1L);就发出了sql语句
集合的延迟加载
True false extra
extra为更进一步的延迟加载策略。
当调用getStudents()时不会加载hql语句,当加载student的属性的时候才会发出SQL语句
调用getStudents().size()方法的时候,会触发类似于:Hibernate: select count(id) from T_Student where classid =? 这样的SQL查询语句(这是一种很聪明的做法,如果lazy=”true”,getStudents().size()将会使得hibernate加载所有集合的数据到内存中)。
调用getStudents().contains()方法的时候(即判断是否包含某个对象),会触发类似于:select 1 from T_Student where classid =? and id =? 这样的SQL查询语句。
lazy=”true”
断点debug运行
lazy=”false”
断点debug运行
lazy=“extra”
单端关联
False proxy no-proxy
proxy:当前对象的単值相关对象只有在调用它的主键外的其他属性的get方法时才加载它。
no-proxy:当前对象的単值相关对象只有在调用它的属性时才加载,需要字节码增强。
懒加载的测试源码
package cn.itcast.hibernate0909.lazy;import java.util.Set;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.junit.Test;/** * 懒加载 * 针对数据库中的大数据,不希望特别早的加载到内存中,当用到它的时候才加载 * 类的懒加载 * 集合的懒加载 * 单端关联的懒加载 * @author Administrator * */public class LazyTest { private static SessionFactory sessionFactory; static{ Configuration configuration = new Configuration(); //加载配置文件 configuration.configure("cn/itcast/hibernate0909/lazy/hibernate.cfg.xml"); //采用了工厂模式创建sessionFactory sessionFactory = configuration.buildSessionFactory(); } /** * 类的懒加载 * * 在默认情况下,类就是执行懒加载 * * 只有使用了load方法以后才能用懒加载 * * 如果在相应的映射文件中,设置<class>的lazy="false"懒加载将失去效果 */ @Test public void testLoad(){ Session session = sessionFactory.getCurrentSession(); Transaction transaction = session.beginTransaction(); Classes classes = (Classes)session.load(Classes.class, 1L); String cname = classes.getCname();//发出sql语句 System.out.println(cname); transaction.commit(); } /** * 集合的懒加载 * 针对一多对的情况或者多对多的情况 * 根据一方加载set集合,决定在什么时候给set集合填充数据 * true * 在遍历集合中的每一个元素的时候发出sql语句 * false * 在得到集合的时候,发出sql语句 * extra * students.size()这个时候用extra仅仅能够得到大小 */ @Test public void testCollectionLazy(){ Session session = sessionFactory.openSession(); Classes classes = (Classes)session.load(Classes.class, 2L); Set<Student> students = classes.getStudents(); System.out.println(students.size()); session.close(); } /** * 单端关联 * 根据多的一方加载一的一方 * false * proxy 就相当于true * no-proxy * 根据多的一方加载一的一方数据量特别少,所以怎么样都行 */}
- Hibernate深入Session
- Hibernate session
- Hibernate Session
- Hibernate Session
- Hibernate Session
- Hibernate Session
- Hibernate Session
- Hibernate Session
- hibernate session
- Hibernate Session
- Hibernate--Session
- Hibernate-Session
- Hibernate-Session
- Hibernate Session
- Hibernate session
- hibernate session
- Hibernate-Session
- Hibernate session
- 模拟placeholder效果
- TCP协议与UDP协议的定义与区别
- mysql插入数据,获取最新插入的ID(自增列)
- 盾神与条状项链
- Centos搭建docker环境
- Hibernate深入Session
- 欢迎使用CSDN-markdown编辑器
- 胡侃软件开发之C#的委托
- 计算文件的 MD5 值
- 正则验证数字
- 第一天学习powershell总结
- Android开发:最全面、最易懂的Android屏幕适配解决方案
- 采集获取网页内容
- 【Python爬虫系列】内容解析之BeautifulSoup