JPA进阶&二级缓存

数据持久化

数据的持久化是指将从数据库取出的数据进行封装,放在一个对象里,目的是为了以后的使用更加高效,不必每次都从数据库里取数据。

JPA中常用注解

@Entity 实体,表示将这个类交给JPA管理,代表这个类是个实体类
@Table(name=“表名”) 对应数据库产生的表名
@Id 表示该实体的主键
@GeneratedValue 设置主键自增长策略
@ManyToOne 默认是急切加载,(多对一,适用于关联表)
@ManyToOne(fetch = FetchType.EAGER) 急切加载,数据不管用不用都会直接查询出来
@ManyToOne(fetch = FetchType.LAZY) 懒加载,要用到对应的数据的时候才会查询
@JoinColumn(name = “列名”) 设置外键名
@Cacheable(true) 开启二级缓存

JPA的主键生成策略

 @GeneratedValue(strategy = GenerationType.IDENTITY) -- 就是主键自增策略
 @GeneratedValue(strategy = GenerationType.SEQUENCE) --序列 mysql不支持 但是oracle支持(不用)
 @GeneratedValue(strategy = GenerationType.TABLE) --表的策略 兼容好 可以mysql 支持oracle 性能有点低
@GeneratedValue(strategy = GenerationType.AUTO) -- 默认根据方言来选择 

1.在字段上打上@GeneratedValue就相当于给该字段设置了自动自增长策略
@GeneratedValue 默认使用了(strategy = GenerationType.AUTO
@GeneratedValue且等效域@GeneratedValue(strategy = GenerationType.IDENTITY)
当我们在字段上添加了@GeneratedValue时,那我们就不能在保存数据时手动去更改他的值,否则就会报错,因为这个主键交给了JPA管理

JPA中的四种状态

1.瞬时状态 就是指new实体对象的时候
2.托管状态(即保存数据) 和实体管理对象产生关系
3.游离状态 和实体管理对象解离关系
4.删除状态 当上方的托管状态将数据存在内存中时,那么删除在内存中的内容

@Test
public void testStatus() throws Exception {
    //瞬时状态,就是指new实体对象的时候
    JpaStatus jpaStatus = new JpaStatus();
    jpaStatus.setId(1L);
    jpaStatus.setName("呼呼");
    //获得实体管理对象
    EntityManager entityManager = JpaUtils.getEntityManager();
    //开启事务
    entityManager.getTransaction().begin();
    //托管状态(即保存数据) 和实体管理对象产生关系
    entityManager.merge(jpaStatus);
    //游离状态      和实体管理对象解离关系
    //entityManager.detach(jpaStatus);
    //删除状态 当上方的托管状态将数据存在内存中时,那么删除在内存中的内容
    //entityManager.remove(jpaStatus);
    //提交事务
    entityManager.getTransaction().commit();
    //关闭资源
    entityManager.close();
}

脏数据更新

一个持久化数据如果去改变它非主键的值,当它事务提交的时候,它会自动产生修改sql语句并且修改数据库中的值
为什么会自动修改呢?
解:因为当在数据库中查询出一条数据时会存放到缓存中以Map的形式存放,给该值修改非主键的值后,提交事务时会去看内存中的数据是否和缓存中的数据是否一样,如果修改后的值和数据库中的值不一样时那么就会将修改的值覆盖到数据库中,保持数据库中的值和缓存中的值一样。

@Test
public void testName() throws Exception {
    EntityManager entityManager = JpaUtils.getEntityManager();
    entityManager.getTransaction().begin();
    //托管状态
    JpaStatus jpaStatus = entityManager.find(JpaStatus.class, 1L);
    //改变非主键的值
    jpaStatus.setName("AAA");
    // 在commit提交的时候,它会自动发送update语句去更新
    entityManager.getTransaction().commit();
}

脏数据更新产生n-to-n错误

当查询出一条数据时,修改了其持久化数据主键的值,那么会产生n-to-n错误

bernate.HibernateException: identifier of an instance of cn.itsource.jpa.JpaStatus was altered from 1 to 10	  

实体对象的定义规则

规则:
1.实体类不能用final修饰
2.实体类中的字段都是由包装类修饰,因为底层很多情况都是判断是否为null
3.实体类中的构造方法如果时有参构造方法,那么一定要提供一个无参的构造方法

实体之间的相互关系

依赖关系:依赖注入DI,把对象注入到类里面这个过程 就叫依赖注入 (IOC控制反转)
关联关系:多对一关系,多对多关系

在使用关联关系保存数据时,先执行一方再执行多方效率要高一些   

组合关系:整体和部分不能分离
聚合关系:整体和部分可以分开存在
泛化关系:体现继承

急切记载和懒加载区别

@ManyToOne(fetch = FetchType.EAGER) 急切加载:数据中对应的某些值不管你用不用都会一次性直接查询出来
@ManyToOne(fetch = FetchType.LAZY) 懒加载:需要用的时候才会去执行
懒加载底层原理:
find–查询出来放入缓存里面 把持久化数据对象放入缓存里面,第二次在获取的时候,从缓存里面找是否有分类的名称,如果没有分类名,就再发送sql查询分类名称

二级缓存

缓存: 先从数据库把数据查询出来,放入缓存里面(内存Map),下次查询数据的时候,先从缓存里找,如果有,直接取出,如果没有,再发送sql查询数据,放入缓存
​ 目的:提高查询效率

一级缓存 是框架自带的缓存,不用做任何配置,就可以使用,它是属于entitymanager级别上面的缓存
一级缓存命中条件:同一个EntityManagerFactory 同一个EntityManager 同一个OID

二级缓存 不是框架自带的,需要做配置,才能使用,它是属于EntityManagerFactory级别
二级缓存命中条件:同一个entitymanagerFactory 不同entityManager 同一个OID
二级缓存生效:entitymanger对象的创建 必须放到find方法之后 ,才能加入到二级缓存。

二级缓存配置信息

1.在pom.xml引入二级缓存Jar包

<!-- 二级缓存支持包-->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-ehcache</artifactId>
      <version>4.3.8.Final</version>
    </dependency>
   

2.在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" />

3…在persistence.xml配置开启实体配置cachebale(true)

        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

查询缓存

查询缓存配置信息:在persistence.xml配置开启查询缓存属性

<property name="hibernate.cache.use_query_cache" value="true" />

查询缓存是基于二级缓存的,但find方法不会有查询缓存的
命中条件:
* 同一个EntityManagerFactory 不同EntityManager 发出jpql语句相同,并且条件值要相同
* 命中极低 条件很多情况下面都不相同

 @Test
    public void testQuery() throws Exception {
        EntityManager entityManager = JpaUtils.getEntityManager();
        String jpql="select o from Product o where o.id=?";
        Query query = entityManager.createQuery(jpql);
        //给jpql语句中?传入id值
        query.setParameter(1,1L);
        query.setHint(QueryHints.HINT_CACHEABLE, true);
        List resultList = query.getResultList();
         System.out.println(resultList.size());
         //清空查寻缓存
        entityManager.close();
        
        EntityManager entityManager2 = JpaUtils.getEntityManager();
        String jpql2 = "select o from Product o where o.id = ? ";
        Query query2 = entityManager2.createQuery(jpql2);
        query2.setParameter(1, 2L);
        //相当于把对象放入查询缓存里面 说明在使用查询缓存
        query2.setHint(QueryHints.HINT_CACHEABLE, true);
        System.out.println(query2.getResultList().size());

        entityManager2.close();
    }

缓存命中条件(面试题)
一级命中条件: --底层自动会用 不用做任何配置
​ 同一个EntityManagerFactory 同一个EntityManager 同一个OID
二级缓存命中: 需要开启二级缓存 做配置 – 选择
同一个EntityManagerFactory 不同的EntityManager 同一个OID
查询缓存命中条件:
​ 同一个EntityManagerFactory 不同的EntityManager 发出jpql语句相同,条件值相同 – 用的很少,条件值相同情况下 很少,命中很低

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值