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

向上连接到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与三层架构之间的关系:

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值