zoukankan      html  css  js  c++  java
  • Hibernate入门(二)

    一、主键生成策略

    1.主键的类型

    • 自然主键: 把有特定业务含义的字段作为了主键 eg: 用户的名字, 身份证号码

    • 代理主键: 把没有特定业务含义的字段作为了主键 eg: id

      开发里面的话通常用代理主键

    2.主键的生成策略

    2.1概述

    ​ Hibernate中为了更好的维护数据, 提供很多种主键生成策略.

    2.2 主键策略类型
    • increment :自动增长,适用类型:short,int,long类型主键.在多进程和集群下不要使用.用的不是数据库的自动增长, hibernate底层的增长策略,select max(id) from customer; 然后+1作为下一条记录的ID.

    • assigned:需要用户手动输入OID的.

    • identity:自动增长,用的是数据库的自动增长。适用类型:short,int,long类型主键.支持自动增长数据库如Mysql

    • sequence:序列,适用类型:short,int,long类型主键.支持序列的数据库如:Oracle.

    • native:本地策略,根据数据库的底层采用使用identity还是sequence.

    • uuid:随机的字符串,适用于字符串类型的主键.

      规则: 如果主键类型是 int short long 用 native

    ​      如果主键类型是字符串, 用uuid

    二、持久化类的编写规则

    1.持久化类概述

    ​   在Hibernate中,用来描述数据库表结构的类,称之为持久化类.

    ​   Java类与数据库的某个表建立了映射关系.这个类就称为是持久化类

    ​   持久化类 = Java类 + hbm的配置文件

    2.持久化类定义规范

    • 遵循JavaBean定义规范

      ​ 类是公有的

      ​ 需要一个无参的构造函数

      ​ 属性是私有的,需要提供公共的getter和setter方法进行访问属性

    • 必须用一个属性描述数据库表的主键

    • 主键属性的类型必须是引用类型,且需要实现Serializable接口

    三、 持久化对象的三种状态

    1.概述

    ​   由持久化类创建的对象就是持久化对象。Hibernate为了管理持久化对象:将持久化对象分成了三个状态.hibernate底层实现过程中,定义的三种状态主要方便开发人员调用session的API.

    ​   区分三种状态:

    ​     瞬时态 :没有持久化标识OID的,没有纳入到session的管理.

    ​     持久态 :有持久化标识OID的,已经纳入到session的管理.

    ​     托管(游离态)态:有持久化标识OID的,没有纳入到session的管理.

    java代码:

    /**
     * 区分三种状态:
     * 瞬时态: 没有持久化标识oid,没有纳入Session管理
     * 持久态: 有持久化标识oid,并且纳入了Session管理
     * 托管态: 有持久化标识oid,但没有纳入Session管理
     */    
        @Test
        public void fun01(){
            Session session = HibernateUtils.openSession();
            Transaction transaction = session.beginTransaction();
            transaction.begin();
            
            User user = new User();//瞬时态
            user.setUname("张三");
            user.setUage(18);
            
            session.save(user);
            System.out.println(user.toString());//持久态
            
            transaction.commit();
            session.close();
            System.out.println(user.toString());//托管态
        }

    2.三种状态的转换

    2.1瞬时态对象

    没有持久化标识OID, 没有被纳入到Session对象的管理

    • 获得:new对象

    • 状态转换:

      ​ 瞬时态--->持久态:save()/saveOrUpdate();

      ​ 瞬时态--->托管态:把瞬时态对象设置一个id

    2.2持久态对象

    有持久化标识OID,已经被纳入到Session对象的管理

    • 获得:get()/load()/find()..

    • 状态转换:

      ​ 持久态--->瞬时态:session.delete(); (Hibernate中不建议使用的)

      ​ 持久态--->托管态:close()/clear()/evict(Object obj);

    2.3托管态对象

      有持久化标识OID,没有被纳入到Session对象的管理

    • 获得:new对象,给对象设置id

    • 状态转换:

      ​ 托管态-->瞬时态:把对象的id设置为null

      ​ 托管态--->持久态:update()/saveOrUpdate();

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

      持久态对象依赖于缓存可以自动更新数据库

    • Java代码

     1     @Test
     2     public void fun05(){
     3         Session session = HibernateUtils.openSession();
     4         Transaction transaction = session.beginTransaction();
     5         transaction.begin();
     6         //持久态对象
     7         User user = session.get(User.class, 1);
     8         user.setUname("李四");
     9         //session.update(user);可以不写,因为当前的user是持久化对象
    10 
    11         transaction.commit();
    12         session.close();
    13     }

    四、hibernate的缓存

    1.缓存概述

    ​   缓存就是一块内存空间。

    ​   将数据源(数据库或者文件)中的数据读取出来存放到缓存中,再次获取的时候 ,直接从缓存中获取,这样可以提升程序的性能!

    ​   作用:提升程序的性能

    2.Hibernate的缓存类别

    ​   一级缓存:session对象的缓存,自带的不可卸载的. 一级缓存的生命周期与session一致。

    ​   二级缓存:二级缓存可以在多个session中共享数据。一般不会用,企业里通常使用Redis

    3.一级缓存

    ​   在 Session 接口的实现中包含一系列的 Java集合,这些 Java 集合构成了 Session 缓存. 只要 Session 实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期.

    ​   当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图get()、 load()对象时,会判断缓存中是否存在该对象,有则返回,此时不查询数据库。没有再查询数据库.

        @org.junit.Test
        public void fun03(){
            Session session = HibernateUtils.openSession();
            Transaction transaction = session.beginTransaction();
    
            //持久态对象
            User user1 = session.get(User.class, 1);//马上发送一条sql语句
            System.out.println(user1.toString());
    
            User user2 = session.get(User.class, 1);//马上发送一条sql语句
            System.out.println(user1 == user2);//true
    
            transaction.commit();
            session.close();
        }

    测试结果:

    Hibernate:
      select
        user0_.uid as uid1_0_0_,
        user0_.uname as uname2_0_0_,
        user0_.uage as uage3_0_0_
      from
        user user0_
      where
        user0_.uid=?
    User{uid=1, uname='李四', uage=18}
    true

    4.一级缓存的内部结构:(缓存区, 快照区)

    五、Hibernate的事务

    1.事务的概念

    ​   事务就是逻辑上的一组操作,组成事务的各个执行单元,操作要么全都成功,要么全都失败.

    2.事务的特性

    ​   原子性: 事务不可分割.

    ​     eg: 张三 1000 李四 1000; 张三给李四转100, 要么转账成功,要么失败

    ​   一致性: 事务执行的前后数据的完整性保持一致.

    ​     eg: 张三 1000 李四 1000 =2000; 张三给李四转100, 成功了 张三 900 李四1100 = 2000; 失败

      ​ 隔离性: 一个事务执行的过程中,不应该受到其他的事务的干扰.

    ​   持久性: 事务一旦提交,数据就永久保持到数据库中.

    ​     eg: 张三 1000 李四 1000, 给李四转520;

    3.不考虑隔离性会出现的相关问题

    • 脏读: 一个事务读到了另一个事务未提交的数据.

    • 不可重复读: 一个事务读到了另一个事务已经提交的update数据,导致多次查询结果不一致. 张三 1000 ; 李四 1000

    • 虚读: 一个事务读到了另一个事务已经提交的insert数据,导致多次查询结构不一致.

    4.隔离级别

    隔离级别含义
    READ_UNCOMMITTED 允许你读取还未提交的改变了的数据。可能导致脏、幻、不可重复读
    READ_COMMITTED 允许在并发事务已经提交后读取。可防止脏读,但幻读和 不可重复读仍可发生
    REPEATABLE_READ 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读仍可能发生。
    SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中涉及的数据表来完成的。

    实际开发中,不会选择最高或者最低隔离级别,选择 READ_COMMITTED(oracle 默认)、REPEATABLE_READ (mysql默认)

    5.Hibernate配置隔离级别

      hibernate通过在hibernate.cfg.xml的配置文件中设置隔离级别:

    <property name="hibernate.connection.isolation">4</property>

      取值

        ​ 1: Read uncommitted isolation,读未提交

    ​     2: Read committed isolation,读已提交,解决脏读。

    ​     4: Repeatable read isolation,可重复读

    ​     8: Serializable isolation,串行化

    6.hibernate对 session的管理

    6.1把Session绑定在当前线程

    ​   在开发中,通常在业务层进行事物管理,在Dao层操作数据库. 也就是说业务层需要连接(Session)开启事物,Dao层需要连接(Session)操作数据库,如何保证这些连接是同一个呢?

    ​ 在JDBC阶段,我们通过了两种方式解决:

      ​ 1.向下传递参数

    ​   2.绑定到TreadLocal里面.

    ​   在Hibernate中,Session 对象与本地线程绑定很简单,只需要两步:

    • 在hibernate.cfg.xml文件中,添加属性,开启与本地线程绑定的session

      <property name="hibernate.current_session_context_class">thread</property>
    • 通过SessionFactory的getCurrentSession()方法获得Session

      Session session = sessionFactory.getCurrentSession();

      注意:通过getCurrentSession()方法获得的session,无需调用close方法释放资源。当事物提交或者回滚,会自动释放资源.

    6.2 Session获取方式的区别
    • 调用getCurrentSession()方法时,会判断当前线程中是否绑定了session。

      ​ 如果绑定了,直接返回线程中绑定的session

      ​ 如果没有绑定,先去创建一个session,然后讲session存储到当前线程中,再返回。

    • 调用openSession()方法时,只会创建一个新的session,且不会存储到当前线程。

    • 通过getCurrentSession()方法获得的session,无需调用close方法释放资源. 通过openSession()方法获得的session需要手动释放资源。

  • 相关阅读:
    vs2008支持ajax extender控件
    ComponentArt控件分析之CallBack(1)
    asp.net控件开发技巧(2)关闭基类不必要的功能
    asp.net控件开发技巧(1)使用HtmlTextWriter类规范输出标签
    开了一论坛,专门讨论控件技术
    出来透个气
    道歉
    Kubuntu 9.10 Karmic Koala 预览
    让Nginx 的URL目录自动加斜线”/”
    Nginx的Rewrite正则表达式,匹配非某单词
  • 原文地址:https://www.cnblogs.com/gdwkong/p/8324200.html
Copyright © 2011-2022 走看看