欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Hibernate】从0开始学Hibernate--004(完) -- 关联映射、缓存、三层架构

程序员文章站 2024-02-19 23:45:16
...

向上连接到Hibernate--002 Session操作数据库、关联查询、数据存储的三种状态、脏数据与刷新缓存。

https://blog.csdn.net/hekaikai666/article/details/81913142

回顾与总结

(一)Hibernate中查询数据的三种方式

          HQL语句查询(注意区分HQL和SQL语句的关系:没有半毛钱关系)

          动态参数查询(静态方法很多,注意返回值和参数列表)

          原生SQL语句查询(不建议用,就相当于绕了一大圈,封装好的JDBC又使用全JDBC)

(二)Hibernate中的关联查询

          一对多,多对一(级联操作)

          多对多

          一对一

(三)脏数据与刷新缓存

一、关联映射级联关系

        (一)映射级联关系

          在配置文件中,可以进行关联映射配置,属性为(cascade)、值可以分为四个(none、save-update、delete、all)

              none -->                 默认值只操作当前对象,忽略它所关联的所有对象

              save-update -->     当前对象执行save/update/saveOrUpdate会级联的去往它所关联的表中插入数据或修改数据

              delete -->               对当前对象执行delete()删除,他会级联的去删除关联对象以及表中数据

              all -->                     baohansave-updaye/delete的级联行为

       (二)延迟加载

         延迟加载方法(懒加载):lazy-load 在尽可能晚的情况下,当真正需要使用到数据时,才会向数据库发送sql语句执行查询加载数据到内存中.避免无谓的性能开销。其中有两个属性方式:load()延迟加载不发送SQL语句,默认返回代理对象,只保存对象的id;get()非延迟加载但是只会查询当前对象的完整信息 如果当前对象还有关联的对象或集合数据。

         延迟加载属性:

         1.一对多和多对一延迟加载对方集合信息。属性lazy,值为

             true --> 默认值 延迟加载,只会加载当前表中数据,不会发送sql语句去加载其关联的集合信息,当真正需要使用到集合中数据时,才会发送sql语句查询;

             false --> 取消延迟加载,当加载当前表中数据时,会立即发送sql语句去向其关联的表中执行查询;

             extra --> 增强延迟加载,如果调用了集合中的size()/contains()方法时,不会发送查询所有数据的sql语句,而是按照需求发送一条sql语句查询所需要知道的信息

        2.多对多和一对一的延迟加载对方实体信息。属性lazy,值为

             false --> 取消延时加载,在加载当前对象信息时,也会发送sql语句级联的去关联的一方对象信息

             proxy --> 默认值 延迟加载,加载当前对象信息时,不会加载对方完整信息,而是返回一个代理对象

             no-proxy --> 延迟加载,默认只加载当前对象信息,当需要使用对方对象信息时,发送sql 返回一个非代理对象

二、OpenSession与getCurrentSession方法比较(*)

openSession() :无论当前线程有没有session对象,都会直接去创建一个session

getCurrentSession():

        1.从当前线程获取一个session对象 ,如果当前线程没有session则创建一个并绑定到当前线程中去

        2.无论是DML操作还是DQL操作,要求当前线程必须绑定一个事物(界定事务边界)

        3.在事物提交后session会自动关闭

        4.在主配置文件中添加配置(上下文配置)

<!--给当前线程绑定一个session  -->
<property name="hibernate.current_session_context_class">thread</property>

openSession()与getCurrentSession()方法比较

        1.创建方式不同 一种是get 一种是open(MDZZ脑残说的话)

// 通过session工厂获取session对象
Configuration cfg = new Configuration(); // 获得配置信息对象
SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂
Session session = sf.getCurrentSession(); // 获得Session
Session session = sf.openSession(); // 打开Session

        2.实现过程不同

           openSession 可以看得出来,是打开一个新的session对象,而且每次使用都是打开一个新的session,假如连续使用多次,则获得的session不是同一个对象,并且使用完需要调用close方法关闭session。

           getCurrentSession 可以看得出来,是获取当前上下文一个session对象,当第一次使用此方法时,会自动产生一个session对象,并且连续使用多次时,得到的session都是同一个对象,这就是与openSession的区别之一,简单而言,getCurrentSession 就是:如果有已经使用的,用旧的,如果没有,建新的。

          注意:在实际开发中,往往使用getCurrentSession多,因为一般是处理同一个事务(即是使用一个数据库的情况),所以在一般情况下比较少使用openSession这比较老旧的一套接口了;

       3.简单实例

// openSession方式 :

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.hibernate.model.Student; // 注意包路径

public class StudentTest {
    public static void main(String[] args) {

        Student s = new Student();
        s.setId(1);
        s.setName("s1");
        s.setAge(1);

        Configuration cfg = new Configuration(); // 获得配置信息对象
        SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂
        Session session = sessionFactory.openSession(); // 打开Session

        session.beginTransaction(); // 看成一个事务,进行操作
        session.save(s); // 会找到 Student 这个类,寻找set方法
        session.getTransaction().commit(); // 提交对数据的操作
        session.close();

        sf.close();
    }
}
 // getCurrentSession方式 :

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

import com.hibernate.model.Student; // 注意包路径

public class StudentTest {
    public static void main(String[] args) {

        Student s = new Student();
        s.setId(1);
        s.setName("s1");
        s.setAge(1);

        Configuration cfg = new Configuration(); // 获得配置信息对象
        SessionFactory sf = cfg.configure().buildSessionFactory(); //解析并建立Session工厂
        Session session = sessionFactory.getCurrentSession(); // 打开Session

        session.beginTransaction(); // 看成一个事务,进行操作
        session.save(s); // 会找到 Student 这个类,寻找set方法
        session.getTransaction().commit(); // 提交对数据的操作

        sf.close();
    }
}
// Student 类代码 :

package com.hekaikai666.test1;

public class Student {
    private int id;
    private String name;
    private int age;
    // 此处省略get&&set&&constructor
}

三、HIbernate缓存机制

(一)什么是缓存?

       缓存时介于应用程序和永久性存储数据源之间的介质。

(二)缓存的作用?

       一般把一些不经常修改,但是会经常去访问的数据放入缓存中,那么下一次可以直接从缓存中读取数据,从而减少与服务器或者数据库的交互。从而提升系统的性能(速度、流量)

(三)Hibernate中缓存(Hibernate中的一级、二级缓存和Mybatis中的一级、二级缓存有什么区别)

       3_1:一级缓存

           主要是session缓存,主要缓存持久化对象,当调用方法想数据查询对象时(get/load)会先查询session中有没有这个对象,如果有就直接返回,如果没有,就直接发送SQL语句到数据库执行查询,并将查询结果存入到session缓存中。一级缓存在Hibernate中是默认开启的。

            当session关闭时,session缓存消失。

       3_2:二级缓存

             二级缓存的特点:

                   1.二级缓存时sessionFactory级别的缓存,是所有session所共享的

                   2.二级缓存是应用程序级别缓存,其生命周期依赖于应用程序

                   3.二级缓存在Hibernate中默认没有开启,需要在主配置文件中主动开启

                  4.二级缓存需要借助一个第三方插件完成,可以将数据缓存在内存(内存中有很多的session区),也可以将数据缓存到硬盘中。第三方插件:EHCache、OSCache、SwarmCache、JBossCache(集群范围内、分布式都需要使用Redis)

                 (EH/OS:应用程序范围内的缓存,可以将数据缓存在内存或者硬盘中;S/JB:集群范围内缓存,不支持查询缓存)

             二级缓存的使用步骤:

                   1.导入插件jar和配置文件ehcache.xml

                   2.主配置文件中开启二级缓存

                   3.指定二级缓存提供商

                   4.指定哪些类,集合需要二级缓存

                   5.设置ehcache.xml配置(以下为常用参数)

                      maxElementsInMemory: 占用内存的空间存1000个对象.

                      eternal: 缓存里面的对象是否是永久有效?只有是false,下面的两个参数才能配置

                      timeToIdleSeconds: 空闲的时间:指定对象使用间隔超过60秒,从缓存移除该对象

                      timeToLiveSeconds: 活跃时间:进入缓存空间最多呆300s,超过就清出.

                      overflowToDisk: 超出1000个对象,也存,存在 diskStore path="java.io.tmpdir",这个磁盘存储路径里面

       3_3:查询缓存

            查询缓存的特点: 查询缓存是基于二级缓存之上的;查询缓存主要缓存对象的属性值;查询缓存是以key-value键值对的形式对数据进行缓存的,两次发送相同的SQL语句,会使用查询到缓存

            key:SQL语句

           value:SQL语句的查询结果(value值一般都是对象的属性值,如果value值是一个对象,那么他只会存储代理,只有id的对象(oid),当需要使用这个对象时,会根据对象的id去一二级缓存中进行查询,一二级缓存中没有则去数据库中查询)

           查询缓存使用步骤:主配置文件中开启缓存配置

<!-- 开启二级缓存,使用EhCache缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.provider_class">
    org.hibernate.cache.EhCacheProvider
</property>
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>

// 获取session工厂对象        
Session session = sessionFactory.openSession();
// 通过对象开启事务
session.beginTransaction();
// 创建查询对象
Query query = session.createQuery("from Users where id = :id");
// 设置属性值
query.setParameter("id", 6);
// 启动查询缓存
query.setCacheable(true); //启用查询缓存
// 获取缓存对象里的属性值
Users user = (Users)query.list().get(0);
System.out.println("用户名:" + user.getUsername());
// 提交事务
session.getTransaction().commit();
// 关闭session
session.close();

四、三层架构和openSessionInView

    三层架构:软件生成

        表现层:面向用户(UI:User Interface 面向用户)

          1、用户能看到的(UI-->jsp、html、swing、androad)

          2、能接受用户请求的

          3、给用户返回数据(servlet、struts2、SpringMVC)

        业务层:用于要处理的业务逻辑

        数据层:面向数据库的一层(jdbc、Hibernate、MyBatis)

    MVC是一种表现层设计模式,属于三层架构中的表现层;三层架构是一种软件工程设计架构

    Dao层属于数据持久层

    openSessionInView:在表现层打开session。

         本来的session的开启与关闭应该在业务层完成,但是这样在数据延迟加载时会存在session已经关闭的异常,所以把session的开启和关闭从业务层提到表现层,在Spring中提供了一个openSessionInViewFilter,可以把它配置在web.xml中,当一个请求到来时可以打开session,开启事务,当请求完成返回页面时提交事务,关闭session,这样也可以保证一个请求(一个响应)对应一个session对象。

使用场景:SSH+表关联查询+延迟加载

SSH与三层架构之间的关系:

【Hibernate】从0开始学Hibernate--004(完) -- 关联映射、缓存、三层架构

感谢威哥的图,对理解很有用