zoukankan      html  css  js  c++  java
  • 你很了解hibernate吗?

       Hibernate是好多的传统项目的首选,因其自动化程度高,使用书写方便,深得好多的传统项目的青睐,估计您也是使用的Hibernate吧, 既然使用了,那么您对他很熟吗? 我就问他俩问题: 1.Hibernate底层是怎么实现的?2.Hibernate的二级缓存用过吗? 估计大部分人都会懵逼特斯拉。不要紧,今天这个文章会让你对Hibernate刮目相看!

    Hibernate的核心配置文件

    在src下创建一个hibernate.cfg.xml

    以下为配置文件的详情。

    <?xml version="1.0" encoding="utf-8"?>

    <hibernate-configuration>

    <session-factory>

    <!-- 必须去配置的属性 -->

    <!-- 配置数据库连接的基本信息: -->

    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

    <property name="hibernate.connection.url">jdbc:mysql:///hibernate3_day01</property>

    <property name="hibernate.connection.username">root</property>

    <property name="hibernate.connection.password">123</property>

    <!-- Hibernate的方言 -->

    <!--

    为实现HQL语句向不同数据库的SQL语句转换时,解决不同数据库之间的差异而制定的一套”规范”。

    举例来说,我们在MySQL数据库里进行分页查询,只需使用limit关键字就可以了;而标准SQL并不支持limit关键字,例如Oracle则需要使用行内视图的方式来进行分页。同样的应用程序,当我们在不同数据库之间迁移时,底层数据库的访问细节会发生改变,而Hibernate也为这种改变做好了准备,现在我们需要做的是:告诉Hibernate应用程序的底层即将使用哪种数据库——这就是Hibernate方言。为了适配不同的数据库的规范而设计的适配方式。每一种数据库的方言方式都不一样。

    -->

    <!-- 生成底层SQL不同的 -->

    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

    <!-- 以下是可选的属性 可以使用也可以不适用 -->

    <!-- 显示SQL -->

    <property name="hibernate.show_sql">true</property>

    <!-- 格式化SQL -->

    <property name="hibernate.format_sql">true</property>

    <!-- hbm:映射 to DDL: create drop alter -->

    <property name="hibernate.hbm2ddl.auto">update</property>

    <!-- 通知Hibernate加载那些映射文件(配置hibernate与数据库的字段的映射文件 ) -->

    <mapping resource="cn/itcast/hibernate3/demo1/Customer.hbm.xml"/>

    <!--可选的配置:

    hibernate.show_sql true 在控制台上输出SQL语句

    hibernate.format_sql true 格式化控制台输出的SQL语句

    hibernate.connection.autocommit true 事务是否自动提交

    hibernate.hbm2ddl.auto create/create-drop/update/validate

    * create :每次执行的时候,创建一个新的表.(如果以前有该表,将该表删除重新创建.) 一般测试的时候的使用.

    * create-drop :每次执行的时候,创建一个新的表,程序执行结束后将这个表,删除掉了. 一般测试的时候使用.

    * update :如果数据库中没有表,创建一个新的表,如果有了,直接使用这个表.可以更新表的结构.

    * validate :会使用原有的表.完成校验.校验映射文件与表中配置的字段是否一致.不一致报错.-->

    <!--在Hibernate中使用c3p0连接池:

    * 引入c3p0的jar包

    * 在核心配置中添加一段配置:

    <!-- C3P0连接池设定-->

    <!-- 使用c3po连接池 配置连接池提供的供应商-->

    <!--

    <propertyname="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider </property>

    <!--在连接池中可用的数据库连接的最少数目 -->

    <!--<property name="c3p0.min_size">5</property>

    <!--在连接池中所有数据库连接的最大数目 -->

    <!--<property name="c3p0.max_size">20</property>

    <!--设定数据库连接的过期时间,以秒为单位,

    如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->

    <!--<property name="c3p0.timeout">120</property>

    <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->

    <!--<property name="c3p0.idle_test_period">3000</property>-->

    </session-factory>

    </hibernate-configuration>

    接下来再说说hibernate的缓存机制:

    1. 使用一级缓存的目的是为了减少对数据库的访问次数,从而提升hibernate的执行效率;(当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据,如果有数据就不查询数据库,直接从缓存中获取数据);

    1.2:Hibernate中的一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数,只在session范围内有效,session关闭,一级缓存失败;

    1.3:一级缓存的特点,只在session范围有效,作用时间短,效果不是特别明显,在短时间内多次操作数据库,效果比较明显。

    1.4:当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session缓存中;

    1.5:session的缓存是由hibernate维护的,用户不能操作缓存内容;如果想操作缓存内容,必须通过hibernate提供的evict/clear方法操作

    1.6:缓存相关的方法(在什么情况下使用上面方法呢?批量操作情况下使用,如Session.flush();先与数据库同步,Session.clear();再清空一级缓存内容):

    session.flush();让一级缓存与数据库同步;

    session.evict();清空一级缓存中指定的对象;

    session.clear();清空一级缓存中所有的对象;

    1.7:面试题,不同的session是否会共享缓存数据?

    答:不会哦~~~

    1.8:list和iterator的区别?

        (1)list查询:

          答: 一次性把所有的记录都查询出来了;会放入缓存,不会从缓存中取数据;

        (2)iterate(N+1次查询):

          答: N表示所有的记录总数,即会发送一条语句查询所有的记录的主键,这是第一条查询语句,再根据每一个主键取数据库查询,这是根据第一次查询的条数进行N次查询操作;会放入缓存,也会从缓存中取出数据;

    2:Hibernate的懒加载:

    2.1:懒加载概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。

    使用懒加载的目的,是提高程序执行效率。

    2.2:查询操作:get()方法/load()方法

        (1)get()方法,及时加载。及时查询操作;只要调用get方法立刻向数据库查询。

        (2)load()方法,默认懒加载,即在使用数据的时候,才向数据库发送查询的sql语句。session关闭以后,不可以使用懒加载。

    复制代码

    #懒加载默认为true,即为懒加载,可以改为非懒加载。即lazy="false"

    #lazy="false" 关闭懒加载

    #lazy="true"使用懒加载

    #lazy="extra"在真正使用数据的时候才向数据库发送查询的sql语句。集合属性懒加载的时候提升效率。如果调用集合的size()/isEmpty()方法只是统计,不真正查询数据。

    <class name="类名称" table="数据表名称" lazy="false">

    ......

    </class>

    2.3:懒加载异常: 

    Session关闭后,不能使用懒加载数据,如果session关闭后,使用懒加载数据报错如:

    org.hibernate.LazyInitializationException: could not initialize proxy - no Session

    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.

    ........................

    如何解决session关闭后不能使用懒加载加载数据的问题:

          方式一:可以先在关闭session之前使用一下数据,这样关闭以后就可以使用此数据了。如Dept.getDeptName();

          方式二(推荐):强迫代理对象初始化操作:Hibernate.initialize(对象);

          方式三:关闭懒加载(lazy="false");

          方式四(推荐):在使用数据之后再关闭session;

    3:二级缓存:

    Hibernate提供的缓存

    有一级缓存、二级缓存。 目的是为了减少对数据库的访问次数,提升程序执行效率!

    一级缓存:

    基于Session的缓存,缓存内容只在当前session有效,session关闭,缓存内容失效!

    特点:

    作用范围较小! 缓存的事件短。

    缓存效果不明显。

    二级缓存:

    Hibernate提供了基于应用程序级别的缓存即为二级缓存,可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。

    Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。

        如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。  

    3.2:查看hibernate.properties配置文件,二级缓存如何配置?

    相关配置的文件:

    ### Second-level Cache ###

    #hibernate.cache.use_second_level_cache false【二级缓存默认不开启,需要手动开启】

    #hibernate.cache.use_query_cache true 【开启查询缓存】

    ## choose a cache implementation 【二级缓存框架的实现】

    #hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider

    #hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider

    hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider 默认实现

    #hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider

    #hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider

    #hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider

    二级缓存配置:

    <!--****************** 【二级缓存配置】****************** -->

    <!-- a. 开启二级缓存 -->

    <property name="hibernate.cache.use_second_level_cache">true</property>

    <!-- b. 指定使用哪一个缓存框架(默认提供的) -->

    <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>

    <!-- 开启查询缓存 -->

    <property name="hibernate.cache.use_query_cache">true</property>

    <!-- c. 指定哪一些类,需要加入二级缓存 -->

    <class-cache usage="read-write" class="com.bie.lesson11.Dept"/>

    <class-cache usage="read-only" class="com.bie.lesson11.Employee"/>

    <!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] -->

    <collection-cache usage="read-write" collection="com.bie.lesson11.Dept.emps"/>

    缓存策略:

    <class-cache usage="read-only"/> 放入二级缓存的对象,只读;

    <class-cache usage="nonstrict-read-write"/> 非严格的读写

    <class-cache usage="read-write"/> 读写; 放入二级缓存的对象可以读、写;

    <class-cache usage="transactional"/> (基于事务的策略)

     适合放入二级缓存中的数据:

    很少被修改

    不是很重要的数据, 允许出现偶尔的并发问题

    不适合放入二级缓存中的数据:

    经常被修改

    财务数据, 绝对不允许出现并发问题

    与其他应用数据共享的数据

    Hibernate常用的两种分页的方式

    1. criteria分页
    public Page getPage(int currentPage,int pageSize,Criterion...crts){
    Criteria c=session.createCriteria(House.class);
    List list=null;
    for (int i = 0; i < crts.length; i++) {
    c.add(crts[i]);
    }
    c.setProjection(Projections.rowCount());
    int totalRecord=Integer.valueOf(c.uniqueResult().toString());
    c.setProjection(null);
    c.setFirstResult((pageSize)*(currentPage-1));
    c.setMaxResults(pageSize);
    list=c.list();
    Page page=new Page();
    page.setCurrentPage(currentPage);
    page.setPageSize(pageSize);
    page.setTotalRecord(totalRecord);
    page.setList(list);
    return page;
    }
    2. hql分页
    public Page getPage(int currentPage,int pageSize,String hql,Object...args){
    String countHql="select count(*) "+hql.substring(hql.indexOf("from"));
    Session session=HibernateUtil.getInstance().getSession();
    Query query=session.createQuery(countHql);
    for (int i = 0; i < args.length; i++) {
    query.setParameter(i, args[i]);
    }
    int totalRecord=Integer.valueOf(query.uniqueResult()+"");
    query=session.createQuery(hql);
    for (int i = 0; i < args.length; i++) {
    query.setParameter(i, args[i]);
    }
    query.setFirstResult(pageSize*(currentPage-1));
    query.setMaxResults(pageSize);
    List<House> list=(List<House>)query.list();
    Page page=new Page();
    page.setCurrentPage(currentPage);
    page.setPageSize(pageSize);
    page.setTotalRecord(totalRecord);
    page.setList(list);

    return page;
    }

                                                    喜欢就加关注哦

    --------------------------------------------------------------------------

    老铁福利:

    本公众号是分享知识,共同学习、交流的平台,欢迎大家踊跃推荐,共同打造一个共建共享的平台!作为礼物: 回复以下文字可自动获取相关资料:

    回复:"高并发"可获取 JAVA高并发秒杀系统实战系列视频
    回复“jvm” 可获取深入理解java虚拟机电子书以及全套视频讲解资料
    回复“javase” 可获取 java基础相关的整理资料;
    回复“html” 可获取html+css+js 相关的整理资料;
    回复“shm” 可获取Struts+Hibernate+MyBatis相关的整理资料;
    回复“数据库” 可获取数据库相关知识整理资料;
    回复"springcloud" 可获取Spring Cloud微服务实战电子书;
    回复:"鸟哥" 可获取鸟哥linux 私房菜相关的电子书;
    更多的惊喜敬请期待!

    微信扫一扫
    关注该公众号

  • 相关阅读:
    分布式事务之可靠消息
    分布式事务之本地消息表
    分布式事务
    数据库之 事务
    WePY开发小程序(二):项目入口及注册页面、组件
    WePY开发小程序(一):入门
    vue学习笔记-事件监听
    vue学习笔记-列表渲染
    vue学习笔记-缩写
    vue学习笔记-常用指令
  • 原文地址:https://www.cnblogs.com/wangdong811/p/10336245.html
Copyright © 2011-2022 走看看