SSH框架之Hibernate进阶持久化对象及事务管理(二)

第一节: 持久化类的编写规则

1.1 什么是持久化类

  • 持久化:将内存中的一个对象持久化到数据库中的过程,Hibernate是持久层的ORM映射框架。
  • 持久化类:一个java对象与数据库表建立了映射关系,则该类被称为持久化类。

1.2 持久化类的编写规则

  • ①对持久化类提供一个无参数的构造方法 :Hibernate底层需要使用反射生成实例;
  • ②属性需要私有,对私有属性提供public的get和set方法:Hibernate中获取对象值;
  • ③对持久化类提供一个唯一标识OID与数据库主键对应:Hibernate中通过持久化类的OID的属性来区分是否是同一个对象。
  • ④持久化类中的属性尽量使用包装类型类来定义:基本数据类型的默认值为0,易引起歧义。
  • ⑤持久化类不要使用final进行修饰:延迟加载本身是Hibernate一个优化的手段,返回的是一个代理对象(对没有实现接口的类产生代理,javassist使用了非常底层的字节码增强技术,集成这个类进行代理)如果该类不能被继承,则不能产生代理对象,则延迟加载也就失效了。

1.3 Hibernate中主键生成策略

  • 1.3.1 主键的分类
    自然主键:主键的本身就是表中的一个字段(实体中的一个具体属性);
    代理主键:主键的本身不是表中必须的一个字段(不是实体中的某个具体的属性)。
    在实际的开发中,尽量使用代理主键,满足OCP原则(对程序的扩展是open的,对源代码的修改是close)

  • 1.3.2 主键的生成策略
    在实际开发中一般不允许用户手动设置主键,一般将主键交给数据库。在Hibernate中提供了多种主键的生成策略。如下:

<id name="cust_id" column="cust_id">
            <!--主键生成策略-->
            <!--
            * increment:Hibernate中提供的自动增长的机制,适用于long,short或int类型的主键。在单线程中使用,
                在集群下不要使用(存在线程安全的问题);
            * identity:适用于short,int,long类型的主键,使用的是数据库底层的自动增长机制,适用于有自动增
                长机制的数据库(MySql,MSSQL),Oracle不适用。
            * sequence:适用于short,int,long类型的主键,采用的是序列的方式。Oracle支持。
            * uuid:适用于字符串类型的主键,使用hibernate中的随机方式生成字符串主键。
            * native:本地策略,可以在identity和sequence之间自动切换。
            * assigned:hibernate放弃主键的管理,需要用户自行设定
            * foreigen:使用另外一个相关联的对象的标识符。它通常和 <one-to-one> 联合起来使用。
            -->
            <generator class="native"/>
        </id>

第二节:持久化类的三种状态

Hibernate是持久层框架,通过持久化类完成ORM操作。Hibernate为了更好的管理之间化类,将持久化类分成三种状态。

  • 瞬时态(transient)
    瞬时态也称为临时态或者自由态,瞬时态的实例是由new命令创建,开辟内存空间的对象,不存在持久化标识OID(相对于主键值),尚未与Hibernate session关联,在数据库中也没有记录,失去引用后将被JVM回收。瞬时状态的对象在内存中是gu孤立存在的,与数据库中的数据无任何关联,仅是一个信息携带的载体。
  • 持久态(presistent)
    持久态的对象拥有持久化标识OID,加入到了Session缓存中,并且相关联的Session没有关闭,在数据库中有对应的记录,每条记录只对应唯一的持久化对象,需要注意的是,持久态对象是在事务还未提交前变成持久态的。(持久态的对象可以自动更新数据库)
  • 脱管态(detached)
    脱管态也称离线态或者游离态,当某个持久化状态的实例与session的关联被关闭时就变成了脱管态。脱管态对象存在持久化标识OID,并且仍然与数据库中的数据存在关联,只是失去了与当前Session的关联,脱管状态对象发生改变时Hibernate不能检测到。

2.1 如何区分这三种状态?

瞬时态对象,没有唯一标识OID,没有被session管理。
持久态对象,拥有唯一标识OID且被session管理。
脱管态对象,拥有唯一标识OID,但没有被session管理。

2.2 持久化对象的三种状态转换

image.png

第三节 Hibernate的一级缓存

缓存是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提供应用的运行性能。缓存汇总的数据是数据存储源中数据的拷贝。缓存的物理介子通常是内存。
Hibernate的缓存分为一级缓存和二级缓存,Hibernate的这两级缓存都位于持久化层,存储的都是数据库数据的备份。其中第一级缓存为Hibernate的内置缓存,不能被卸载。

3.1 什么是Hibernate的一级缓存

Hibernate的一级缓存就是指Session缓存,Session缓存是一块内存空间,用来存放相互管理的Java对象,在使用Hibernate查询对象的时候,首先会使用对象属性的OID值在Hibernate的一级缓存中进行查找,如果找到匹配的OID值的对象,就直接将该对象从一级缓存中取出使用。不会再查询数据库。如果没有找到相同OID值的对象,则会去数据库中查找相应数据。当从数据库中查询到所需数据时,该数据信息也会放置到一级缓存中。Hibernate的一级缓存的作用就是减少对数据库的访问次数。
在Session接口的实现中包含一系列的Java集合,这些Java集合构成了Session缓存。只要Session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。固一级缓存也被称为Session基本的缓存。

3.2 Hibernate的一级缓存特点:

①当应用程序调用Session接口的save()、update()、saveOrUpdate时,如果Session缓存中没有相应的对象,Hibernate就会自动把从数据库中查询到的相应对象信息加入到一级缓存中去。
②当调用Session接口的load()、get()方法,以及Query接口的list()、iterator()方法时,会判断缓存中是否存在该对象,有则返回,不会查询数据库,如果缓存中没有要查询对象,再去数据库中查询对应对象,并添加到一级缓存中。
③当调用session的close()方法时,Session缓存会被清空。

3.3 Hibernate一级缓存的特殊区域(快照区)

image.png

第四节 Hibernate的事务管理

4.1 数据库事务的回顾

  • 4.1.1 什么是事务:
    事务指的是逻辑上的一组操作,组成这组操作的各个逻辑单元执行时要么全部成功,要么全部失败;

  • 4.1.2 事务的特性:
    原子性:代表事务不可分割
    一致性:代表事务执行前后,数据完整性保持一致
    隔离性:代表一个事务的执行过程中,不应该受到其他事务的干扰
    持久性:代表事务执行完成后,数据就持久化保持中数据库中

  • 4.1.3 如果不考虑事务的隔离性,会引发那些问题:
    ①读问题

    • 脏读:一个事务读到另一个事务未提交的数据
    • 不可重复读:一个事务读到另一个事务已经提交update的数据,导致在前一事务中多次查询结果不一致
    • 虚读:一个事务读到另一个事务已经插入insert数据,导致在前一个事务多次查询结果不一致

    ②写问题(了解)

    • 引发两类丢失更新问题。
  • 4.1.4 读问题的解决方法
    设置事务的隔离级别:

    • Read uncommitted:以上读问题都会发生
    • Read committed:解决脏读,不可重复读和虚读有可能发生
    • Repeatable read:解决脏读和不可重复读,虚读有可能发生
    • Serializable:解决所有读的问题

4.2 Hibernate中事务隔离级别的设置

在hibernate配置文件中配置如下属性:

   <!--设置事务的隔离级别-->
        <!--
            隔离级别取值对应关系:
            1 : Read uncommitted isolation
            2 : Read committed isolation
            4 : Repeatable read isolation
            8 : Serializable isolation
        -->
        <property name="hibernate.connection.isolation">4</property>

4.3 Service层事务管理

Service业务层的复杂业务对DAO层的调用必须保证连接对象是同一个,通常的解决方案有:
①:向下传递
②:使用ThreadLocal对象进行绑定,将连接对象绑定到当前线程中,在DAO的方法调用中,通过当前线程来获取连接对象。

4.5 Hibernate中针对Service层事务的管理方法

Hibernate框架内部已经绑定了ThreadLocal,在SessionFactory中提供了一个方法getCurrentSession()来获取连接对象。但这个方法的调用前提需修改Hibernate的属性,如下

 <!--配置Hibernate对Session事务的管理方式-->
        <!--
            用于指定session管理方式
            * thread : Session对象的生命周期与本地线程绑定。
            * jta:Session对象的生命周期与JTA事务绑定
            * managed: Hibernate委托程序来管理Session对象的生命周期
        -->
        <property name="hibernate.current_session_context_class">thread</property>

则session连接对象的获取方式:该连接对象在执行完成后无需手动关闭。

/**
     * currentSission对象的获取
     * @return
     */
    public static Session getCurrentSission(){
        return sessionFactory.getCurrentSession();
    }

第五节:Hibernate中的查询对象简介

5.1 Query

Query代表面向对象的一个Hibernate查询操作。在Hibernate中,通常使用session.createQuery()方法接受一个HQL语句,然后调用Query的list()或uniqueResult()方法执行查询。所谓的HQL是Hibernate Query Language缩写,其语法很像SQL语法,但它是完全面向对象的。

在Hibernate中使用Query对象的步骤:

  • 获得Hibernate的Session对象
  • 编写HQL语句
  • 调用session.createQuery()创建查询对象
  • 如果HQL语句包含参数,则调用Query的setXxx设置参数
  • 调用Query对象的list()或uniqueResult()方法执行查询
    @Test
    public void findByQuery(){
        Session currentSission = HibernateUtil.getCurrentSission();
        Transaction transaction = currentSission.beginTransaction();
        //查询所有人员数据
//        String hql = "from Customer";
        //条件查询(使用命名参数的方式)
//        String hql = "SELECT c from Customer c where c.cust_name like :name ";
        //分页查询
        String hql = "from Customer";

        Query query = currentSission.createQuery(hql);
        //插入检索条件
//        query.setParameter("name","小%");
        //插入分页查询条件
        query.setFirstResult(0);//从第i条开始
        query.setMaxResults(1);//每页展示的数据为0条
        List<Customer> list = query.list();
        for (Customer customer: list) {
            System.out.println(customer.toString());
        }
        transaction.commit();
    }

5.2 criteria

Query by Criteria 是更加面向对象的一种查询方式。

 @Test
    public void findByCriteria(){
        Session currentSission = HibernateUtil.getCurrentSission();
        Transaction transaction = currentSission.beginTransaction();
        //通过criteria进行查询
//        Criteria criteria = currentSission.createCriteria(Customer.class);已过时
        //1.import javax.persistence.criteria.CriteriaQuery;获取Criteria对象
        CriteriaQuery<Customer> query = currentSission.getCriteriaBuilder().createQuery(Customer.class);
        //2.指定根条件
        query.from(Customer.class);
        //3.执行查询
//        List<Customer> resultList = currentSission.createQuery(query).getResultList();
        //3.1 执行分页查询
        List<Customer> resultList = currentSission.createQuery(query)
                .setFirstResult(0)//设置开始位置
                .setMaxResults(1)//设置每页条数
                .getResultList();
        for (Customer customer: resultList) {
            System.out.println(customer.toString());
        }
        transaction.commit();
    }

5.3 SQL Query

SQLQuery用于结束sql,特别复杂的情况下使用SQL。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352