JavaEE学习笔记之SSH—Hibernate(4)

今天来讲讲 Hibernate 的灵魂所在——> Session 缓存

session缓存是由一系列的Java集合构成的。当一个对象被加入到Session缓存中,这个对象的引用就加入到了java的集合中,以后即使应用程序中的引用变量不再引用该对象,只要Session缓存不被清空,这个对象一直处于生命周期中。

Session缓存的作用:

1)减少访问数据库的频率。

2)保证缓存中的对象与数据库中的相关记录保持同步。

Session清理缓存的时机:

 1)当调用Transaction的commit()方法时,commit()方法先清理缓存(前提是FlushMode.COMMIT/AUTO),然后再向数据库提交事务。

 2)当应用程序调用Session的createQuery().list()或者createQuery().iterate()时,如果缓存中的持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能反映持久化对象的最新状态。

    hibernate2中Session.find()对应于3中的session.createQuery().list()
    hibernate2中Session.iterate()对应于3中的session.createQuery().iterate()

 3)当应用程序显示调用Session的flush()方法的时候。

Session的setFlushMode()方法用于设定清理缓存的时间点。FlushMode类定义了三种不同的清理模式:FlushMode.AUTO、FlushMode.COMMIT和FlushMode.NEVER。

FlushMode.AUTO是默认值:

session.setFlushMode(FlushMode.COMMIT);

Session清理模式执行清理缓存操作的时间点:

假设现在想把两个客户信息插入到数据库中:

        Session session = HibernateSessionFactory.getSession();
        Transaction transaction = session.beginTransaction();
        Customer customer1 = new Customer(null, "张三", "78784854", "南昌");
        Customer customer2 = new Customer(null, "李四", "45646463", "北京");
        session.save(customer1);
        session.save(customer2);
        transaction.commit();

首先创建两个客户对象,这时会在栈区有两个引用指向堆区的两个客户对象即

    Customer customer1 = new Customer(null, "张三", "78784854", "南昌");
    Customer customer2 = new Customer(null, "李四", "45646463", "北京");

然后执行save()方法,会在session缓存即session对象中 创建两个引用指向堆区的这两个客户对象。并且会生成两条 insert (插入)语句保留在session中。

最后 等执行到 commit() 的时候就将事务提交。 这时因为 session 的清理缓存的时机默认为 FlushMode.AUTO ,所以当 commit() 的时候会先调用 session.flush()—>是将刚刚保留的 insert 语句发送到 数据库中。等 commit() 完之后就将 insert 语句的数据永久保存在数据库中了。

在刚才的基础上,现在来看看这段代码:

Transaction transaction = session.beginTransaction();
Customer customer = (Customer) session.load(Customer.class, 1L);
        customer.setName("流川枫");
        transaction.commit();

这段代码是要将 id 为 1 的用户的用户名更新为“流川枫”。很奇怪这段代码并没有调用 update()方法,那能更新到吗?答案是肯定的。现在我们来看看内存图:

来分析下:

首先执行 load()方法,会将数据库的对应数据加载到内存中即地址B01所对应的内容。这时session 和 栈区都指向 地址B01。

因为bo1是持久态对象,而持久态对象发生变化时,session会监听到这种变化,并且产生出对应sql保证在事务提交之后让内存中的对象和数据库中的数据保持一致。执行到 coustomer.setName() 方法时,持久态对象发生变化,随即 session 产生一条 update 语句。当 commit 之后就将update 语句发送到数据库并更新。

所以这个对象并不需要调用 update()方法去更新也会更新。

那么我们就得来了解下什么是持久态对象了。

在 Hibernate 中判断对象的状态,可以从以下两个方面去判断:

a.对象与 session 之间的关系

b.对象与数据库数据之间的关系

Hibernate对象的状态:

1)瞬时态Transient

由new操作符创建,且尚未与Hibernate Session关联的对象。处于瞬时态的java对象成为临时对象。

特点

    不处于Session的缓存中,即不被任何一个Session实例关联。

    在数据库中没有对应的记录。

2)持久态Persistent

已经被持久化,加入到Session的缓存中,处于持久化状态的java对象被称为持久化对象。

特点

位于一个Session实例的缓存中。

持久化对象在数据库中有相应的记录

Session在清理缓存时,会根据持久化对象的属性变化来同步更新数据库。

当一个持久化对象关联一个临时对象,在允许级联保存的情况下,Session在清理缓存的时候会把这个临时对象也转变为持久化对象。

3)脱管态Detached

已经被持久化,但不再处于Session的缓存中,处于脱管状态的java对象称为游离对象。

比如在刚才的基础上,添加如下代码:

Customer customer = new Customer(1L, "", "", "");

因为 id 为 1 的用户存在,但又和 session 没有关联,所以是游离对象。

特点

不再位于Session的缓存中,即不被Session关联。

游离对象是由持久化对象转变过来的,因此在数据库存在与之对应的记录(前提是没有其他程序删除了这条记录)

临时对象VS游离对象

相同:都不被Session关联,Hibernate不会保证它们的属性变化与数据库保持同步。

不同:前者在数据库中没有与之对应的记录。后者由持久化对象转变而来,因此数据库中可能还存在与之对应的记录。

Hibernate 对象状态转换图

脱管状态

session中不维护脱管对象

数据库中有脱管对象对应的数据

save(obj)
  obj 瞬态
    将瞬态转化为持久态对象
  obj 脱管
    重新保存一个新的对象
  obj 持久态
    没意义

update(obj)
  obj 脱管
    将脱管态转换为持久态

saveOrUpdate(obj)
  如果obj是瞬态对象,保存
  如果obj是脱管对象,更新

delete(obj)
  将持久态删除

Session API :

Session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存,更新,删除和查询的方法。

save(): 把一个临时对象加入到缓存中,使它变成持久化对象

-->选用映射文件指定的主键生成器为持久化对象分配唯一的OID

-->计划一条insert语句,把参数对象当前的属性值组装到insert语句中,但是save()方法并不立即执行SQL insert语句,只有当Session清理缓存时候才会执行。

-->如果在save()方法之后,又修改了持久化对象的属性,会使得Session在清理缓存的时候额外执行SQL update语句。

注意:save()方法是用来持久化一个临时对象的!

如果将一个持久化对象传给save()方法将不会执行任何操作,多余的步骤

如果将一个游离态对象传给save()方法,session会将它当作临时对象来处理,再次向数据库中插入一条记录,不符合业务需求!

update():把Customer对象重新加入到Session缓存中,使之变为持久化对象。

--->计划一条update语句,只有在清理缓存的时候才会执行,并且在执行的时候才会把参数对象中的属性值组装到update语句中。

注意:update()是将一个游离对象转变为持久化对象的。

  只要通过update()方法使游离对象被一个session关联,即使没有修改参数对象的任何属性,Session在清理缓存的时候也会执行由update方法计划的Update语句。

saveOrUpdate():同时包含了save()与update()方法的功能,如果传入的参数是临时对象,调用save方法,如果参入参数是游离对象,调用update()方法,如果传入的是持久化对象,直接返回。

load()/get(): 都会根据给定的OID从数据库中加载一个持久化对象,区别在于,当数据库中不存在与OID对应的记录时,load()方法会抛出ObjectNotFoundException异常,而get()方法返回null.

delete():用于从数据库中删除与参数对象对应的记录,如果传入的参数是持久化对象,Session就计划执行一个delete语句,如果传入的参数是游离对象,先使游离对象被Session关联,使它变为持久化对象,然后计划一个delete语句,在清理缓存的时候执行。

evict():从缓存中清除参数指定的持久化对象。

  适用场合:不希望Session继续按照该对象的状态改变来同步更新数据库。
  在批量更新或批量删除的场合,当更新或者删除一个对象后,及时释放该对象占用的内存。当然批量操作优先考虑JDBC.

clear():清空缓存中所有持久化对象。

get VS load

1.get方法,hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查数据库。默认延迟加载,查询当前对象的时候暂时先不查询与之关联的对象。

load方法,为延迟加载即先将查询语句放入缓存中,待到用时再将缓存中的查询语句发送到数据库进行查询。(lazy属性对它不影响)

2.get方法检索不到的话会返回null

load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常

注意:

Java代码

Users user = (Users)session.load(Users.class, userId);
System.out.println(user.getId());  

上面这2句代码,不会去执行数据库操作。因为load后会在hibernate的一级缓存里存放一个map对象,该map的key就是userId的值,但是当你getId()时,它会去一级缓存里拿map的key值,而不去执行数据库查询。所以不会报任何错。不会执行任何数据库操作。

补充点:

cascade

    级联操作,一般谁来维护关系,就谁来级联。如果主表来级联,而从表来维护关系,这时保存的时候就会报错。

    保存或更新(save-update)
            customer
            <set name="orders" cascade="save-update"/>
        这表示customer级联order
            维护关系
                customer 维护 order
                customer.getOrders().add(o1);
                customer.getOrders().add(o2);
                customer.getOrders().add(o3);

            session.save(customer);
                insert into tbl_customer values();
                if(级联){
                    os = customer.getOrders();
                    for(Order o : os){
                        save(o);
                    }
                }
    删除(delete)
    删除保存更新(all)
    解除关系即删除(delete-orphan):必须双方接触关系,删除的是从表的数据
        Customer c = (Customer) session.get(Customer.class, 4L);
        Order order = (Order) session.get(Order.class, 8L);
        //接触关系
        c.getOrders().remove(order);
        order.setCustomer(null);
    删除保存更新,解除关系即删除(all-delete-orphan)

lazy

默认true  延迟加载,查询当前对象的时候暂时先不查询与之关联的对象

false   立即加载,查询当前对象的时候查询所有与之关联的对象。

inverse(维护关系的权利的反转)

一般谁来维护关系谁就来产生外键,不能权利颠倒。如果主表维护从表,而主表的维护关系的权利反转了(即在主表中 inverse="true"),则插入数据的时候不会产生外键即从表中的外键为null。一般1:n关系由多的一方来维护即可。

一般写在set中

默认false 当前方可以维护关系(产生外键)

true        当前方不维护关系(不产生外键)
时间: 2024-10-05 23:46:11

JavaEE学习笔记之SSH—Hibernate(4)的相关文章

JavaEE学习笔记之SSH—Hibernate(2)

对象关系映射 ORM 解决的主要问题就是对象-关系的映射,域模型和关系模型都分别建立在概念模型的基础上,域模型是面向对象的,关系模型是面向关系的,一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录. (可能存在类中多个属性对应一列的情况,映射组成关系) ORM中间件采用元数据来描述对象-关系映射细节,元数据通常采用XML格式,并且存放在专门的对象-关系映射文件中,如果希望把ORM软件集成到自己的java应用中,用户首先要配置对象-关系映射文件(**.hbm.xml). sess

JavaEE学习笔记之SSH—Struts2(1)

现在来学习SSH中的第二个框架--Struts2 Struts2是一个基于MVC设计模式的Web应用框架. 首先将Struts2的框架搭建起来: 1)获取发布包 可以从 Struts2官网.Apache.GitHub等,当然直接百度肯定也是可以的. 2)导入相关 jar 包 将 struts-2.3.24.1-all\struts-2.3.24.1\apps\struts2-blank.war 压缩文件解压,然后将 E:\utils\struts2\struts-2.3.24.1-all\str

JavaEE学习笔记之SSH—Spring(1)

一.Spring相关概念 1:轻量级的容器: 容器:spring容器帮我们管理业务逻辑层,里边有很多业务逻辑对象,有对象就有对象的生命周期的管理(创建,销毁). 轻量级:容器给予的业务逻辑对象多少种服务?spring给用户提供的服务完全由用户自己决定,spring想用什么服务自己开启使用.但是重量级的都是只要你用就把所有的服务都给你,不能自己定制. spring容器从来不能独立运行,一定借助于其他容器启动,或者借助web容器启动,或者ejb容器启动. 特点: 应用模块之间耦合度小,组件都是可重用

JavaEE学习笔记之SSH—Struts2(3)

一.action中如何接受页面传过来的参数 第一种情况:(同名参数) 例如: 通过页面要把id=1 name=tom age=20这三个参数传给action 1.action里面定义三个成员变量id name age,这三个变量的名字一定要和所传变量的名字一致. 2.提供get.set方法 3.将来页面把这三个参数传过来的时候,struts2框架会自动的帮我们把这个三个参数值放action中的三个属性里面.(同时还做了类型的转换) 注意:这个工作其实是由defaultStack这个拦截器栈里面的

JavaEE学习笔记之SSH—Spring(3)

一.代理模式 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务. 注意: 委托类对象就是我们后面说到的 目标对象(需要[被]代理的对象) 代理类对象就是我们后面说到的 代理对象(目标对象就是需要这个对象做为代理) 按照代理类的

JavaEE学习笔记之SSH—Struts2(4)

这篇文章讲讲 Struts2 的核心所在--拦截器 一.strut2框架中的拦截器(interceptor) 1.什么是拦截器(interceptor) 拦截器是strut2框架中提供的一种java类. 作用: 1.可以拦截访问action的请求 2.给这个action加入新的丰富功能(上传.参数自动接收.类型自动转换等等)需要配置之后,指明哪一个拦截器去拦截哪一个action或者哪一些action,这样这个拦截器才会去拦截我们的这个action,每一个拦截器就可以给我们的action加入一个新

[原创]java WEB学习笔记95:Hibernate 目录

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

[原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

[原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------