zoukankan      html  css  js  c++  java
  • Hibernate 生成策略和缓存策略

    主键生成策略

    一、主键分类

    1. 自然主键

    主键本身就是表中的一个字段,实体中一个具体的属性,对象本身唯一的特性

    比如:创建一个学生表:姓名、年龄、身份证号(自然主键)

    2. 代理主键

    主键本身不是表中必须的一个字段

    同样创建一个学生表:姓名、年龄 、身份证号、SID(代理主键)

    在实际开发当中尽量要使用代理主键

    • 设计以学生身份证号为主键
    • 在业务上添加学生身份证号,不小心录入错误
    • 主键修改是如果两个相同是允许修改的。所以一旦参于业务,就可能存在一些问题
    • 主键一般只作为条件,查询,不参与修改,使用代理主键就和表当中的业务信息没有关系

    开发中为什么要使用代理主键

    • 一旦自然主键参与到业务逻辑当中,后期有可能修改源代码
    • 一个好的程序设计要满足开闭原则(Open Closed Principle)
      • 对程序的扩展是open开放的
      • 对修改源码是close的

    二、主键的生成策略

    • 在使用代理主键的过程当中,尽量要做到自动生成主键,不能让用户手动设置主键
    • 一般交给数据库自动增长,让程序生成唯一的标识
    • 在hibernate当中,为了减少程序的编写,内部提供了多种的主键生成策略

    1. increment

    • 自动增加策略(long、short、int)

    • 原理

      • 首先先发送一条语句:select max(id) from 表
      • 然后让id加1
    • 在单线程中使用,不要在多线程中使用

      • 两个线程同时对数据库当中的id字段查询
      • 两个人查询的内容都是1
      • 其中一个肯定会报错

    2. identity

    • 自动增长
    • 原理
      • 使用是数据库底层的增长策略
      • 适用于有自动增长机制的数据库
        • Mysql有自动增长
        • Oracle是没有自动增长的:通过序列来完成这种效果的

    3. sequence

    • 自动增长
    • 原理
      • 采用序列的方式
      • 必须得要支持序列
        • Oracle支持序列
        • Mysql不支持序列

    4. uuid

    • 适用于字符串类型的主键
    • 使用hibernate中随机生成字符串的主键

    5. native

    • 本地策略
    • 在 identity 和 sequence 自动切换

    6. assigned

    • hibernate不会帮你管理主键
    • 自己手动调用或通过程序来去生成主键

    持久化

    一、什么是持久化

    • 将内存中的一个对象持久化到(存储到)数据库的过程
    • hibernate框架就是一个持久化的框架

    二、什么是持久化类

    • 一个Java类与数据库建立的映射关系
    • 持久化类 = Java类 + 映射文件

    三、持久化类编写规则

    1.对持久化类提供一个无参的构造方法

    • 底层会通过反射创建对象
    • 如果没有无参构造,反射是无法创建对象的

    2.对内部私有的字段要提供get与set方法

    • 不提供的话。hibernate就无法获取对象的值

    3.对象持久化类提供一个OID与数据库表当中的主键对应

    • Java中通过对象的地址来区别是否为同一个对象
    • 数据库中通过主键来区别是否是同一条记录
    • Hibernate中通过持久化类的OID属性来区分是否是同一个对象

    4.持久化类中的属性尽量使用包装类型

    • 包装类型的默认值为NULL
    • 基本数据类型的默认值为数字

    5.持久化类不要使用final修饰

    • 跟延时加载有关系
    • 延时加载是Hibernate优化的手段
    • 返回的是一个代理对象
    • 使用动态代理 ,低层使用的是字节码增强技术,继承这个类来进行代理。
    • 如果使用了final,就不能被继承,不能被继承,代理对象就无法创建,延时加载就无效了。

    持久化类的划分

    • Hibernate是持久层的框架,通过持久化类完成ORM操作
    • 持久化类:Java类+映射文件

    Hibernate为了更好的管理持久化类,将持久化类对象分为三种状态

    1. 瞬时态

    • 没有唯一的OID
    • 没有被session管理
    • 这种对象我们称为瞬时态对象

    2.持久态

    • 有唯一的OID
    • 有被session管理
    • 这种对象我们称为持久态对象

    3.游离态/托管态/离线态

    • 有唯一的OID
    • 没有被session管理

    三种状态区分

    1. 瞬时态

    刚new出对象时,还没有设置id,还没有被session所管理。

    2. 持久态

    已经有了id,调用session方法,把对象给session,才被session所管理 。

    添加到session之后, 对象一直处理持久态。当对象处理持久态时, 可以自动更新数据库。

    持久态对象特征
    • 自动更新数据,只要成为持久态对象,不用调用update也会自动更新数据
    • 如果值和数据库当中的值一样, 就不会发送update
    • 原理:依赖了hibernate当中的一级缓存

    3. 游离态

    把session关闭掉时close时,对象处理游离态。

    代码演示

    三种状态之间的转换

    一级缓存

    一、什么是缓存

    • 缓存是一种优化的方式,分为一级缓存和二级缓存。
    • 将数据存入到内存当中,使用的时候直接从缓存中获取,不用直接到存储源中取数据了。

    二、一级缓存

    • session级别的缓存
    • 生命周期与Session一致:一级缓存是由Session中的一系列Java集合构成的
    • 是自带的, 不可卸载

    三、二级缓存

    • SessionFactory级别的缓存
    • 需要自己去配置,默认是开启的,在企业当中一般都不用了,现在都 redis。

    四、一级缓存特点

    当应用程序用Session接口的Save(),update(),saveOrUpdate()时,如果session缓存中没有相应的对象,就会自动的从数据库查询相应的信息,写到缓存当中。

    当调用Session接口的load,get()方法,以及Query接口的list iterator方法时, 会判断缓存中是否存在该对象,有则返回, 不会查询数据库,如果缓存中没有要查询的对象,再到数据库当中查询对应的对象,并添加到一级缓存中。

    当调用session.close方法时,缓存会被清空。

    代码:

    五、一级缓存内部结构

    一级缓存当中有一个区域:快照区

    • 使用id进行查询数据库,将查询得到的结果放置到session一级缓存中,同时复制一份数据,放置到session的快照中
    • 当使用tr.commit()的时候,同时清理session的一级缓存(flush)
    • 当清理session一级缓存的时候,会使用OID判断一级缓存中对象和快照中的对象进行比对
    • 如果2个对象(一级缓存的对象和快照的对象)中的属性发生变化,则执行update语句,此时更新数据库,更新成一级缓存中的数据
    • 如果2个对象中的属性不发生变化,此时不执行update语句

    目的:确保和数据库中的数据一致

    清空一级缓存

    • clear():清空所有缓存
    • evict(obj):清空一个对象

    事务管理

    一、事务

    • 逻辑上的一组操作
    • 要么全都成功,要么全都失败

    二、事务特性

    1. 原子性

    事务不能分隔

    2. 隔离性

    执行一个事务时, 不应受到其它事务的干扰

    • 脏读:一个事务读取某一个事务未提交的数据
    • 不可重复读:一个事务读取取另一个事务已经提交的update数据,导致在前一个事务多次查询的结果不一样
    • 幻读:一个事务读取到别一个事务已经提交的insert数据,导致在前一个事务多次查询的结果不一样

    3. 持久性

    事务完成后, 数据就持久到数据库当中

    4. 一致性

    事务执行前后 ,数据的完整性要保持一致

    三、事务的隔离级别

    • Read uncommitted
      • 所有问题都会发生
    • Read committed
      • 解决脏读问题
    • Repeatable read
      • 解决脏读和不可重复读
    • Serializable
      • 解决所有问题,效率较低

    四、Hibernate设置事务的隔离级别

    • 在核心配置文件hibernate.cfg.xml当中
    • 通过数字来代表不同的隔离级别
    <property name="hibernate.connection.isolation">4</property>
    

    五、事务业务层连接

    在业务层使用事务时,必须得要保证获取事物的连接和dao层操作的连接是同一个,否则就管理了不对应的操作

    1. 使用jdbc当中事务业务层处理方法

    (1)向下传递

    就开始在业务层先创建好一个连接,传给dao层,让dao层使用这个连接执行操作

    (2)使用ThreadLocal对象

    在service方法当中把创建的连接绑定到对应的threadLocal当中,在dao方法当中,通过当前的线程获得连接对象

    2. hibernate当中处理方法

    • Hibernate框架,内部已经绑定好了ThreadLocal
    • 在SessionFactory中,提供了一个方法,getCurrentSession() 方法,获取当前线程中的session
    • 此方法默认不能用,要通过配置完成
    • 在核心配置文件(hibernate.cfg.xml)当中配置
    <property name="current_session_context_class">thread</property>
    
    • 创建一个session绑定到当前线程
    • 通过它来操作时, 不需要 close,执行结束后, 会自动的close()
  • 相关阅读:
    Sentry异常捕获平台
    docker部署RabbitMQ(单机)
    Elasticsearch参数调优
    docker 部署Elasticsearch-权限认证(单节点)
    ElementUI 实现el-table 列宽自适应
    vue 弹幕插件
    linux 命令笔记
    swoole安装笔记
    Swoole学习笔记
    VM安装centos8实战
  • 原文地址:https://www.cnblogs.com/xzh0717/p/10806827.html
Copyright © 2011-2022 走看看