1.1 主键生成策略
- 自然主键:有业务含义的主键
- 代理主键:这个主键没有意义,用来区别每行的数据是不同的,最常用
@GeneratedValue
- GenerationType.AUTO 自动检测数据库产品类型,选择适当的主键生成策略
- GenerationType.IDENTITY 主键自动递增
- GenerationType.SEQUENCE 使用序列来实现主键自动递增,适用于Oracle数据库
- GenerationType.TABLE 单独使用一张表来记录其他表的主键
1.2 持久对象状态
图解:
_1 new或者反射创建出来的是临时状态(瞬时状态)
_2 调用persist方法变成持久状态(托管状态)
_3 事务提交后变成游离状态(脱管状态)
_4 如果调用meger方法会变成持久状态
_5 remove执行变成删除状态
_6 find查询出来的都是持久状态的对象
1.3 脏数据更新
- 产生时机: 持久状态的对象与快照备份对象不一致,就会产生脏数据
- 产生原因: 从数据库中查询出来的数据一定是持久状态的,会复制一份至一级缓存中的同时快照也会备份一份,当提交事务时,快照中备份的对象会与持久状态的对象进行对比,一致则不发送sql语句,直接保存;不一致则会发送update语句将其持久化后保存;
- ps:利用脏数据更新修改时,可以不用meger方法即可达到修改的效果
1.4 持久对象的定义规则
- 类不能使用final修饰(使用了就不能继承改类,无法使用懒加载)
- 必须提供公共无参构造
- 提供getXxx/setXxx方法
- 所用属性都是包装类(默认值为null)
1.5 对象之间的关系
依据对象关系的紧密程度划分
1.5.1 java中对象的关系
耦合度从高到低: 泛化(继承)—>实现—>组合—>聚合---->关联---->依赖
1.5.2 JPA中对象的关系
只关注: 组合—>聚合—>关联
JPA具有:
//多重性(组合/聚合/关联的细分):
单项多对一
单项一对多
双向一对多/多对一
单项多对多
双向多对多
单向一对一
双向一对一
//导航性:
单向:通过A类可以找到B类,通过B类找不到A类
双向:通过A类可以找到B类,通过B类也可以找到A类
1.6 配置关系后的CRUD
- 查询: —>未配置懒加载会查询一方数据
- 添加: 查询/new—>设置关系—>都persist();
- 修改: 查询—>修改,不能设置游离状态的对象----->修改主键会报:N to N
- 删除: 先查询再删除
1.7 懒加载原理
- 产生时机: 调用多方关联一方对象属性的getXxx方法时
- 产生原因:
_1 employee.getDeptment()底层执行了以下步骤:
*使用javassits.jar工具打包生成了一个Department对象的子类对象源文件:Deptment_$$_jvst22e_0.java
*子类重写父类所有的getXxx方法,并在重写的方法中调用了EntityManager对象的find方法;
*使用动态编译技术,生成字节码文件;
*使用类加载器(ClassLoader)将其加载到JVM中运行,获得字节码对象;
*使用反射技术创建子类实例: 字节码对象.newInstance();
_2 deptment.getName()
*本质上是在调用子类重写后的方法,所以会查询一方数据
- 按需配置: 可以依据需求配置抓取策略为懒加载,只用调用多方关联一方对象属性的get方法时才会去查询一方数据
@ManyToOne(fetch = FetchType.LAZY) //抓取策略默认为及时加载
private Department department;
1.8 二级缓存
配置:
公共pom.xml中配置
<!--配置二级缓存-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.8.Final</version>
</dependency>
JPA核心配置文件中配置
<persistence-unit name="jpa_day02" transaction-type="RESOURCE_LOCAL">
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<!--二级缓存的相关配置-->
<property name="hibernate.cache.use_second_level_cache" value="true" />
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.EhCacheRegionFactory" />
<!-- 启用查询缓存 需要在实体类上添加 @Cacheable(true)-->
<property name="hibernate.cache.use_query_cache" value="true" />
省略以下....
<!--必有属性-->
<!--必有属性_方言-->
<!--可选配置-->
</properties>
</persistence-unit>
测试
/**
* 二级缓存命中条件:
* 同一个EntityManagerFactory 不同EntityManager 同一个OID\
*
*/
public class SecondCacheTest {
@Test
public void test() throws Exception {
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("jpa_day02");
EntityManager entityManager01 = entityManagerFactory.createEntityManager();
//第一次到一级缓存中查询,未找到查询并将数据备份至一级缓存和二级缓存
Employee employee01 = entityManager01.find(Employee.class, 1L);
//第二次一级缓存命中,不查询
Employee employee02 = entityManager01.find(Employee.class, 1L);
entityManager01.close();
EntityManager entityManager02 = entityManagerFactory.createEntityManager();
//第三次,先到一级缓存中查找,未找到再到二级缓存中查找,找到了二级缓存命中并将数据备份至一级缓存,不查询
Employee employee03 = entityManager02.find(Employee.class, 1L);
//第四次,一级缓存命中,不查询
Employee employee04 = entityManager02.find(Employee.class, 1L);
entityManager02.close();
entityManagerFactory.close();
}
}
使用场景:
- 读取大于修改;
- 对数据要有独享控制,数据不会被第三方修改;
- 可以容忍出现无效数据,非关键数据(不是财务数据等)
- 数据量不能超过内存容量,数据量特别巨大,此时不适合于二级缓存(钝化)