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 私房菜相关的电子书;
    更多的惊喜敬请期待!

    微信扫一扫
    关注该公众号

  • 相关阅读:
    HDU 3401 Trade
    POJ 1151 Atlantis
    HDU 3415 Max Sum of MaxKsubsequence
    HDU 4234 Moving Points
    HDU 4258 Covered Walkway
    HDU 4391 Paint The Wall
    HDU 1199 Color the Ball
    HDU 4374 One hundred layer
    HDU 3507 Print Article
    GCC特性之__init修饰解析 kasalyn的专栏 博客频道 CSDN.NET
  • 原文地址:https://www.cnblogs.com/wangdong811/p/10336245.html
Copyright © 2011-2022 走看看