JPA 02 进阶
主键生成策略(掌握);
主键:能够区分表里面每一行数据
主键特点:非空且唯一
主键的分类:
自然主键:具有实际意义的列来作为主键
代理主键:没有实际意义的列来作为主键 — 单个项目使用
JPA直接不定义 @GeneratedValue 就可以了,在保存之前设置主键的值
如果定义看 @GeneratedValue ,再去设置主键的值就会报错 不能修改主键值
什么是主键的生成策略:
JPA采取的方案方式去生成主键;
JPA主键生成策略:
auto策略: – 默认使用给这种: 根据数据库的方言来选择到底使用哪种策略(常用的)
比如 配置Mysql的方言 – 策略, 自增策略
配置oracle的方言 – 序列sequence策略
table策略:表的生成策略 额外创建一张表来维护
count | table_name |
---|---|
1 | t_employee |
sequeence策略:序列策略
identity策略:mysql采用这种自增策略
Hibernate内置主键生成策略的定义:
在这个类里面 org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory
public DefaultIdentifierGeneratorFactory() {
this.register("uuid2", UUIDGenerator.class);
this.register("guid", GUIDGenerator.class);
this.register("uuid", UUIDHexGenerator.class);
this.register("uuid.hex", UUIDHexGenerator.class);
this.register("hilo", TableHiLoGenerator.class);
this.register("assigned", Assigned.class);
this.register("identity", IdentityGenerator.class);
this.register("select", SelectGenerator.class);
this.register("sequence", SequenceGenerator.class);
this.register("seqhilo", SequenceHiLoGenerator.class);
this.register("increment", IncrementGenerator.class);
this.register("foreign", ForeignGenerator.class);
this.register("sequence-identity", SequenceIdentityGenerator.class);
this.register("enhanced-sequence", SequenceStyleGenerator.class);
this.register("enhanced-table", TableGenerator.class);
}
Hibernate是实现了JPA接口的主键生成策略, Hibernate和JPA主键生成策略是一样的,没有区别,JPA就是 Hibernate的规范。
JPA持久对象的状态(掌握);
一个实体交给JPA维护的时候,这个实体在不同的时期,状态不一样
临时(瞬时)状态:刚刚创建出来,没有和JPA进行发生关系
持久(托管)状态:这个实体对象已经和JPA发生关系
游离(脱管)状态:脱离entityManager的管理,已经被持久化,不存在entityManager里面
删除状态:即将要删除的时候,remove,还没有提交事务
entityManager的方法改变持久对象的状态
图解:四大状态
new:瞬时状态
Mnagerd:持久状态
commit . clear :游离状态
removed: 删除状态
脏数据更新 :
一个持久化状态的数据,如果修改的非主键的数据之后,在commit的时候,自动会去发送update语句更新,底层通过缓存来操作的
所以要 clear一下 清理缓存
如果一个持久化数据,改变了主键的值 —会报错 报错 n-to-n的错误,持久化状态的数据
实体的类定义规则:
1.类不要定义成final 否则延迟加载会受影响;
2.实体里面属性的类型定义成包装类型,很多底层代码都是通过判断是否为null
3.实体里面有默认无参的构造方法
域对象之间的关系;
对象和对象之间,存在一定关系
存在什么关系?
依赖关系:
一个类去依赖另外一个类,比如Service层Dao层 —> 依赖注入(DI)spring
关联关系:
一个类和另外一个类他们之间是有关系的;
比如员工和部门 — 多对一 — 一对多— 多对多 — 一对一
聚合关系:
整体和部分的关系,整体和部分可以分开存在
组合关系:
也是整体和部分的关系,整体和部分是不可以分开存在的
持久对象(domain层)定义规则
1.类不能定义为final类
因为domain类需要被继承的,否则延迟加载会失效
而且final的类无法产生子类
2.所有属性的类型都必须是包装类型
不能是8个基本类型(int,byte,short,long,char,boolean,float,double)
因为JPA内部代码很多判断都是基于是否等于null
3.必须有默认无参构造方法
因为find方法获取的时候会在内存实例化domain对象
否则报org.hibernate.InstantiationException: No default constructor for entity异常
如果只有有参的构造方法默认的无参构造方法就会消失,就会报错,所以必须在再写一个无参的构造方法(底层通过反射 通过无参构造方法创建对象)
脏数据更新: 一个持久化状态数据,修改非主键的值,会在commit提交的时候自动发送sql
**n-to-n问题:**一个持久化状态数据,如果修改主键的之后,就会报错,也就是说持久化状态的数据,不能改变主键值!
单向多对一(重点掌握);
单向就是java的一个类Product可以获取另一个类ProductDir
@ManyToOne 多对一
@JoinColumn(name=“dir_id”) @JoinColumn指定外键ID
//方产品类型
public class ProductDir {
@Id
@GeneratedValue
private Long id;
private String name;
//多方产品
@Entity
public class Product {
@Id
@GeneratedValue
private Long id;
private String name;
// 多Product对一ProductDir
// 多个产品属于一个产品类型
// 外键在那个表,这个表就是多
@ManyToOne(fetch = FetchType.LAZY) // 实现延迟加载
// @ManyToOne(fetch = FetchType.EAGER) // 默认值,左外连接查询
// JoinColum设置了外键的名字,不配置默认一方属性名_id
// @JoinColumn(name = "dir_id")
private ProductDir dir;
二级缓存(掌握);
一级缓存:属于EntityManager级别的缓存,他是自带的
命中条件:
同一个EntityManagerFactory 同一个EntityManager同一个OID
二级缓存:
属于EntityManagerFactory级别缓存,它不是自带(可以用可以不用),
如果要使用二级缓存,相应配置之后,才能使用二级缓存 ------ 通过Encache(缓存框架)框架来实现二级缓存
/*
第一步
先在Pom.xml里面配置
<!--二级缓存的jar包-->
*/
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.8.Final</version>
</dependency>
// 第二步: 二级缓存配置 添加persistence.xml配置信息
<!-- 启用二级缓存 -->
<property name="hibernate.cache.use_second_level_cache" value="true" />
<!-- 二级缓存的实现类,文档里面的包名有错的 -->
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
<!-- 启用查询缓存 -->
<property name="hibernate.cache.use_query_cache" value="true" />
/* 第三步
在<properties>上面添加配置二级缓存扫描的策略
<!-- ALL:所有的实体类都被缓存 -->
<!-- NONE:所有的实体类都不被缓存. -->
<!-- ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存 -->
<!-- DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类 -->
<!-- UNSPECIFIED:默认值,JPA 产品默认值将被使用 -->
*/
// ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
二级缓存命中条件:同一个entityManagerFactory,不同的entityManager,OID相同
// 一条sql
// @Entity
// @Cacheable(true)
// public class Department
@Test
public void test2() throws Exception {
EntityManager entityManager = JPAUtils.getEntityManager();
//先从一级缓存,二级缓存取数据?取不到,发出sql去获取,填充一级缓存,二级缓存
Department department1 = entityManager.find(Department.class, 1L);
//先从一级缓存,二级缓存取数据?一级缓存取到了,返回
Department department2 = entityManager.find(Department.class, 1L);// 一级缓存命中
entityManager.close();
EntityManager entityManager2 = JPAUtils.getEntityManager();
//先从一级缓存,二级缓存取数据?一级缓存没有取到,但是二级缓存取到了,返回
Department department3 = entityManager2.find(Department.class, 1L);// 二级缓存命中
//先从一级缓存,二级缓存取数据?一级缓存取到了,返回
Department department4 = entityManager2.find(Department.class, 1L);// 一级缓存命中
entityManager2.close();
}
查询缓存:依赖于二级缓存 如果查询缓存有查询条件,就不要使用查询缓存,因为命中率非常低 基本上不用
// 一条sql
// 命中条件:同一个EntityManagerFactory,不同一个entityManager,发出的sql语句必须相同并且查询的条件值也要相同
// 1.如果查询缓存有查询条件,就不要使用查询缓存,因为命中率非常低
// 2.查询缓存里面查询指的是使用jpql,sql进行的查询,就是调用了createQuery方法,find方法不是走查询缓存
// 3.进行domain类的二级缓存的配置
// @Cacheable
// public class Employee {
JPA抓取策略:
JPA告诉程序员使用哪种方式去获取数据
抓取策略配置:
@ManyToOne(fetch = FetchType.LAZY) //懒加载抓取 需要使用的时候,才发送sql查询
//懒加载(lazyload)会默认生成一个 子类。 ---- 底层代理模式
"类千万一定不要定义成 final,不然懒加载会失效,因为定义为final的类是太监类 无法有子类,所以懒加载底层的代理模式就无法生成子类,虽然不会报错,但是懒加载会失效"
@ManyToOne(fetch = FetchType.EAGER) //迫切加载 --默认为迫切加载-- 不使用都把数据加载出来,发送左外连接查询数据
----占用内存
缓存理论
什么情况下使用二级缓存(掌握)
(1)读取大于修改的使用 --查询居多的时候使用二级缓存
(2)对数据要有独享的控制,不能被第三方程序修改
(3)可以容忍一些无效数据,非关键性数据(财务金额不适合放入缓存里面)
日志信息
(4)如果数据大于内存,不适合放入缓存里面 – 钝化
内存100M 数据500M
ehcache支持钝化
http://www.mamicode.com/info-detail-1291774.html
缓存淘汰策略:
LRU(Least Recently Used):最近最少使用 --> 时间为参考点
LFU(Least Frequently Uesd):最不经常使用 -->次数为参考点
FIFO(First in First Out):先进先出 quene
缓存命中条件(掌握)
一级缓存:自带
同一个EntityManagerFactory 同一个EntityManager 同一个OID
二级缓存: 需要配置才能实现
同一个EntityManagerFactory 不同EntityManager 同一个OID
查询缓存:依赖二级缓存
同一个EntityManagerFactory 不同EntityManager 相同jpql 和条件相同