JAPday2

本文深入探讨了JPA中的关键概念,包括主键生成策略、对象状态管理、脏数据更新机制、域对象定义规则及关系、抓取策略和二级缓存的使用。详细解释了这些概念如何影响数据持久化和应用性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JAPday2

1.主键的生成策略

什么是主键?

主键能够区分表面的每一行数据,并且非空且唯一
主键分为两总:
1.自然主键:基友实际意义的列来作为主键。
2.代理主键:没有实际意义的列来作为主键—一般适用于单体项目

什么是主键的生成策略?

JPA生成主键的方式有四种:
1.AUTO----自动 并且默认为这一种:
1.1在mysql方言中 是使用自增策略
2.Table—额外生成一张表来维护主键
3.equence策略
3.1在Oracle方言中 使用序列sequence策略
4. identity(代理主键)策略------mysql采用这种 自增策略

OID管理

JPA使用OID(对象标识符)来建立内存中的对象和数据库中记录的对应关系。
对象的OID和数据库表的主键对应。
为保证OID的唯一性和不可变性,应该让JPA而不是应用程序来为OID赋值。
总结:主键的管理直接由JPA来处理

2.JPA的状态

2.1.临时状态(transient):瞬时状态
刚刚用new语句创建,没有和entityManager发生关系
没有被持久化,不处于entityManager中。该对象成为临时对象
2.2.持久化状态(persistent):托管状态
和entityManager发生关系
已经被持久化,加入到entityManager的一级缓存中(填充一级缓存)。
该状态的对象为持久化对象。
2.3.游离状态(detached):脱管状态
已经被持久化,但不处于entityManager中。
该状态的对象为游离对象。
2.4.删除状态(removed):从JPA才开始有的状态
只有调用了entityManager.remove(domain对象)方法
对象有关联的ID,并且在entityManager管理下,
但是已经被计划删除,事务提交就真的被删除了。

代码实现
@Test
public void save() throws Exception {
  StateDomain stateDomain = new StateDomain();// 临时状态
  stateDomain.setName("itsource");// 临时状态

  EntityManager entityManager = JPAUtils.getEntityManager();
  entityManager.getTransaction().begin();
  entityManager.persist(stateDomain);// 持久状态
  entityManager.getTransaction().commit();
  entityManager.close();// 游离状态
}

3.脏数据更新

什么是脏数据更新?
一个持久状态对象在事务管理内,如果改变原来的数据(非主键),此时出现脏数据,在事务提交的时候自动发出update语句去修改。
代码案例

@Test
public void update() throws Exception {
  save();

  EntityManager entityManager = JPAUtils.getEntityManager();
  entityManager.getTransaction().begin();
  
  StateDomain stateDomain = entityManager.find(StateDomain.class, 1L);// 持久状态
  stateDomain.setName("stateDomain");
  // 写不写效果是一样
  entityManager.merge(stateDomain);// 持久状态

  entityManager.getTransaction().commit();
  entityManager.close();// 游离状态
}
脏数据更新的执行流程

第一步:拿到entityManager,开启事务
第二步:
通过entityManager拿到一个对象,那么现在这个对象就是持久化的对象
这个对象会放到一级缓存里面
JPA会为当前这个对象准备一个快照(把这个对象进行了备份)
第三步:提交事务
它会把快照 与 你现在这个对象的数据进行对比
如果相同,就不需要修改,也不会发送SQL(性能就高了)
当不相同的时候,JPA就会认为现在这个数据是脏数据
脏数据它就会在事务提交的时候,把它进行数据库的同步(发送update SQL语句)

注意:
久状态的对象是不能修改OID(不能修改主键)
持久层修改id会报下面的错误,大家要注意小心:
org.hibernate.HibernateException: identifier of an instance of cn.itsource.jpa.state.StateDomain was altered from 1 to 200

4.持久对象(domain层)的定义规则

4.1.类不能定义为final类
因为domain类需要被继承的,否则延迟加载会失效
4.2.所有属性的类型都必须是包装类型
不能是8个基本类型(int,byte,short,long,char,boolean,float,double)
因为JPA内部代码很多判断都是基于是否等于null
4.3.必须有默认无参构造方法
因为find方法获取的时候会在内存实例化domain对象
否则报org.hibernate.InstantiationException: No default constructor for entity异常

5.域对象(domain对象)之间的关系

5.1.依赖关系
JavaBean之间的依赖关系
分层:表现层,业务层,持久层(依赖关系)
依赖:一般指controll,service,dao层之间的关系
类之间访问关系。无需定义成属性。在A中访问B中的方法或属性,或者A负责实例化B。
Controller表现层依赖于Service业务层,Service依赖于Dao持久层

5.2.关联关系
类之间的引用关系,以属性定义的方式表现。
关联按照多重性可分为一对一、一对多、多对一和多对多。 主要指的数据库(类)的关系
按照导航性可分为单向关联和双向关联。
主要指的java类的导航,导航可以从一个类获取另一个的类的实例
员工和部门是什么关系? 多个员工对应一个部门 多对一
一个类的对象与它的属性之间的关系
注意:关系的判定一定要根据一般的情况,而不是特殊的情况

5.3.聚合关系(本质还是双向多对一,一对多)
表示整体与部分的关系,整体和部分可以分开单独存在。
电脑(主板,CPU,IO,内存条)
5.4.组合关系(本质还是聚合关系,双向多对一,一对多)
强聚合关系,整体和部分之间不能分开。

6.fetch抓取策略

抓取策略就是告诉JPA怎样发出sql获取关联对象

6.1.FetchType.EAGER:fetch的默认值,立即加载
默认情况下,JPA持续性提供程序使用获取类型EAGER:这将要求持续性提供程序运行时必须迫切左外连接获取数据。
6.2FetchType.LAZY:延迟加载
FetchType.LAZY:这将提示持续性提供程序在首次访问数据时并不急于获取数据。

7.二级缓存

二级缓存的命中条件
二级缓存类配置:命中条件:同一个SessionFactory,不同的entityManager,OID相同

第一步:在pom文件中配置

<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" />
<!-- ALL:所有的实体类都被缓存 -->
<!-- NONE:所有的实体类都不被缓存. -->
<!-- ENABLE_SELECTIVE:标识 @Cacheable(true) 注解的实体类将被缓存 -->
<!-- DISABLE_SELECTIVE:缓存除标识 @Cacheable(false) 以外的所有实体类 -->
<!-- UNSPECIFIED:默认值,JPA 产品默认值将被使用 -->
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

第三步 domain的实体类注解的配置

// 一条sql
// @Entity
// @Cacheable(true)

代码实现

@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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值