[ Hibernate ] Hibernate 的主键生成策略、一级缓存以及事务管理(2)

Hibernate 主键生成策略、一级缓存及事务管理

    • 1.持久化类的编写规则
    • 2.主键生成策略
      • 2.1主键的分类
        • 2.1.1自然主键
        • 2.1.2代理主键(尽量使用)
      • 2.1.3主键生成策略
        • 2.1.3.1 Hibernate 的主键生成策略
      • 2.2 持久化类的三种状态
        • 2.2.1 瞬时态
        • 2.2.2持久态*
        • 2.2.3 脱管态
        • 2.2.4 持久态对象可以自动更新数据库
      • 2.3 Hibernate 的一级缓存
        • 2.3.1 缓存概述
          • 2.3.1.1 什么是缓存
        • 2.3.2 Hibernate 的缓存
          • 2.3.2.1 Hibernate 的一级缓存
          • 2.3.2.2 一级缓存证明
      • 2.4 Hibernate 的事务管理
        • 2.4.1 事务回顾
          • 2.4.1.1什么是事务
          • 2.4.1.2事物特性
          • 2.4.1.3 如果不考虑隔离性,引发安全性问题
          • 2.4.1.4 读问题的解决
        • 2.4.2 Hibernate 中设置事务的隔离级别
        • 2.4.3 Service 事务管理
          • 2.4.3.1 Hibernate 解决service 的事务管理
      • 2.5 Hibernate 的其他API
        • 2.5.1 Query (HQL)
        • 2.5.2 Criteria :QBC (Query By Criteria)
        • 2.5.3 SQLQuery

1.持久化类的编写规则

  • 对持久化类提供一个无参的构造方法 底层:反射生成实例
  • 属性需要私有,提供public 的set和get方法 :Hibernate 中获取,设置对象的值。
  • 对持久化类提供一个唯一标识的 OID 与数据库主键对应 :java中通过对象地址区分是否是同一对象,数据库中通过主键确认是否是同一个记录,在hibernate中通过持久化类的OID的属性区分是否是同一对象。
  • 持久化类中的属性尽量使用包装类属性,包装类型默认值为null,基本数据类型默认值为0,有歧义。
  • 持久化类不要使用final修饰 :延迟加载本来就是Hibernate 的一种优化手段,返回的是一个代理对象(javassist,可以对没有实现接口的类产生代理—是用来非常底层字节码增强技术,继承这个类进行代理)。如果类被final 修饰不能被继承了,就不能产生代理对象,延迟加载也就失效,此时的get 方法和load方法 一致。

2.主键生成策略

2.1主键的分类

2.1.1自然主键

  • 主键本身就是表中的一个字段(实体中的一个具体的属性)
  • 创建一个人员表,人员都会有一个身份证号(唯一不可重复),人员的身份证号作为主键,这种主键为自然主键。

2.1.2代理主键(尽量使用)

  • 主键的本身不是表中必须的一个字段(不是实体类的牧歌具体的属性)
    • 创建一个人员表,没有使用人员中的身份证号,用了一个与这个表不相关的字段ID(PNO),这种主键就是代理主键。
  • 在实际开发中,尽量使用主键。、
    • 一旦主键参与到业务逻辑中,后期可能要修改源代码。
    • 好的程序设计满足OCP 原则:对程序的扩展是open的,对修改源码是close的。

2.1.3主键生成策略

2.1.3.1 Hibernate 的主键生成策略

  • 在实际开发中一般不容许用户手动设置主键,一般将主键交给数据库,手动编写程序进行设置,在Hibernate中为减少程序编写,提供了很多种主键的生成策略。
<hibernate-mapping>
    <!--建立类与表的影射-->
    <!--当类名与表名同名时,可省略表名的映射-->
    <class name="com.sunlong.hibernate01.domain.Custom" table="cst_customer">
        <!--建立类中的属性与表中的主键对应-->
        <id name="cust_id" column="cust_id">
            <!--主键的生成策略-->
            <generator class="native"/>
        </id>
</hibernate-mapping>
  • increment
    Hibernate 中提供的自动增长机制,适用 short、int、long类型的主键,在单线程中使用。
  • identity
    适用short、int、long类型的主键,使用的是数据库底层的自动增强机制。适用于有自动增器机制数据库(MySQL、MSSQL),Oracle 没有自增长机制。
  • sequence
    适用short、int、long类型的主键,采用的是序列的方式。(Oracle支持序列)MySQL 不能使用。
  • uuid
    适用于字符串类型主键。使用Hibernate 中的随机方式生成字符串主键。
  • native
    本地策略,根据数据库的能力选择 identity、sequence。
  • assigned
    Hibernate 放弃外键的管理,需要通过手动编写程序或者用户自己设置。
  • foreign
    外部的,一对一的一种关联映射的情况下使用。

2.2 持久化类的三种状态

  • Hibernate 是持久层框架,通过持久化类完成ORM操作。Hibernate 为了更好的管理持久化类,将持久化类分为三种状态。 持久化类 = java类 + 映射。

2.2.1 瞬时态

  • 这种对象没有唯一的标识OID ,没有被session 管理,称为瞬时态对象。

  • 瞬时态对象

  • 获得
    Customer c = new Custonmer();

  • 状态转化

    • 瞬时—>持久
      save() saveOrUpdate()
    • 瞬时—>脱管

2.2.2持久态*

  • 这种对象有唯一的标识OID ,被session管理,称为持久态对象。
    • 可以自动更新到数据库。
    • 获得
      get() load() find() iterte()
      Customer c = session.get(Custonmer.class,1L);
  • 状态转化
    • 持久—>瞬时
      -delete()
    • 持久—>脱管
      -close() clear() evict()
  • 获得
    Custonmer c = new Constmer();
    c.setCust_id(1L);
  • 状态转化
    • 脱管—>持久
      update() saveOrUpdate()
    • 脱管—>瞬时
      customer.setCust_id(null);

2.2.3 脱管态

  • 这种对象有唯一的标识OID,没有被session管理,称为脱管态对象。

2.2.4 持久态对象可以自动更新数据库

    @Test
    //修改操作
    public void demo03() {
        Session session = HibernateUtils.openSession();
        Transaction transaction = session.beginTransaction();

        //直接创建对象进行修改
        /*Custom custom = new Custom();
        custom.setCust_id( 1L );
        custom.setCust_name( "悟空" );
        session.update( custom );*/

        //先查询,在修改(推荐)
        Custom custom1 = session.get( Custom.class, 1L );
        custom1.setCust_name( "八戒" );
        //持久化对象可以自动更新数据库数据,如果更新数据和数据库信息一样,那就只进行查询,不进行更新语句操作
        //一级缓存
        //session.update( custom1 );//不写也更新

        transaction.commit();
        session.close();
    }

2.3 Hibernate 的一级缓存

2.3.1 缓存概述

2.3.1.1 什么是缓存
  • 是一种优化方式,将数据存入到内存中,使用的时候直接从缓存中获取,不用通过存储源。

2.3.2 Hibernate 的缓存

2.3.2.1 Hibernate 的一级缓存
  • Hibernate 框架中提供了优化手段:缓存、抓取策略。
  • Hibernate 提供了两种缓存机制:一级缓存 二级缓存
  • Hibernate 的一级缓存:称为session缓存
2.3.2.2 一级缓存证明
    @Test
    public void demo01() {
        /*
         * 一级缓存
         * */
        Configuration cfg = new Configuration().configure( "com/sunlong/hibernate02/hibernate.cfg.xml" );
        SessionFactory sessionFactory = cfg.buildSessionFactory();
        Session session = sessionFactory.getCurrentSession();
        Transaction transaction = session.beginTransaction();

        Customer customer = session.get( Customer.class, 2L );

        System.out.println( customer );

        //清空所有缓存,控制台打印两次查询语句,否则第二次查询同一对象,将会从一级缓存中获取
        //session.clear();

        //清空指定缓存
        session.evict( customer );

        Customer customer1 = session.get( Customer.class, 2L );
        System.out.println( customer1 );

        transaction.commit();
    }

2.4 Hibernate 的事务管理

2.4.1 事务回顾

2.4.1.1什么是事务
  • 事务:逻辑上的一组操作,组成这组操作的各个逻辑单元要么成功要么失败。
2.4.1.2事物特性
  • 原子性:事务不可分割
  • 一致性:事务执行的前后,数据的完整性保持一致
  • 隔离性:一个事务执行过程中,不应该是受到其他事务的干预。
  • 持久性:事务执行完成后,数据就持久到数据库中。
2.4.1.3 如果不考虑隔离性,引发安全性问题
  • 读问题
    • 脏读:一个事务读到另一个事务未提交的事务.
    • 不可重复读:一个事务读到另一个事务已经提交的update数据,导致在前一个事务对此查询的结果不一致。
    • 幻读:一个事务读到另一个事务已经提交的insert 数据,导致在前一个事务多次查询结果不一致。
  • 写问题
    • 引发两类丢失更新
2.4.1.4 读问题的解决
  • 设置事物的隔离级别
    • 未提交读 :以上读问题都会发生
    • 读已提交 :解决脏读,但是不可重复读和虚读有可能发生
    • 可重复读 ;解决脏读和不可重复读,但是幻读有可能发生
    • 可串行化 :解决所有读问题

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

  • 1 :读未提交
  • 2 :读已提交
  • 4 :可重复读
  • 8 :可串行化
<!--设置事务隔离级别-->
<property name="hibernate.connection.isolation">4</property>

2.4.3 Service 事务管理

2.4.3.1 Hibernate 解决service 的事务管理
  • 事务管理的方式
    <1> 可以在业务层获取到 Session ,并将 Session 作为参数传递到 DAO。
    <2> (最优方案) 可以使用 ThreadLocal 将业务层获取的 Session 绑定到当前线程中,然后在 DAO 中获取 Session 的时候,都从当前线程中获取。
    -Hibernate 提供 sessionFactory.getCurrentSession() 创建一个 session 和 ThreadLocal 绑定方法。
<!--配置当前线程绑定的Session-->
<property name="hibernate.current_session_context_class">thread</property>
  • 配置成功后即可使用 SessionFactory的getCurrentSession() 方法

2.5 Hibernate 的其他API

2.5.1 Query (HQL)

  • Query 代表面向对象的一个 Hibernate 查询操作。在 Hibernate 中,通常使用 session.createQuery() 方法接收一个 HQL 语句,然后调用 Query 的 list() 或 uniqueResult() 方法执行查询。所谓的HQL 是 Hibernate Query Language 的缩写,其语法很像SQL 语句,但它是完全面向对象的。
//Query
public void demo02() {
    Session session = HibernateUtils.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    //简单查询
    //String hql = "from Customer";
    //条件查询
    //String hql = "from Customer where cust_name like ?";
    //分页查询
    String hql = "from Customer";
    Query query = session.createQuery( hql );

    //设置分页
    query.setFirstResult( 3 );
    query.setMaxResults( 3 );
    //以下两种设置占位符的方式都可以
    //query.setParameter( 0 ,"孙%");
    //query.setString( 0,"孙%" );

    List<Customer> list = query.list();
    for (Customer customer : list) {
        System.out.println( customer );
    }

    transaction.commit();
}

2.5.2 Criteria :QBC (Query By Criteria)

  • 更加面向对象的一种方式查询
  • 通过session获得 session.createCriteria()
//Criteria更加面向对象的一种方式查询
public void demo03() {
    Session session = HibernateUtils.getCurrentSession();
    Transaction transaction = session.beginTransaction();

    //查询所有数据
    Criteria criteria = session.createCriteria( Customer.class );

    //条件查询
    criteria.add( Restrictions.like( "cust_name", "孙%" ) );

    //分页查询
    criteria.setFirstResult( 3 );
    criteria.setMaxResults( 3 );

    List<Customer> list = criteria.list();
    for (Customer customer : list) {
        System.out.println( customer );
    }

    transaction.commit();
}

2.5.3 SQLQuery

  • SQLQuery 用于接收SQL ,在特别复杂的情况下使用,一般建议使用以上两种。

  • 以上简单介绍了三种检索方式,后续会在专门章节详细介绍。

你可能感兴趣的:(Java,EE)