JPA总结2

一、JPA主键生成策略

1、主键OID

(1)含义:非空且唯一的,用于标识每条数据的编码,由JPA管理。
(2)分为:自然主键和代理主键

2、JPA自带主键OID生成策略

(1)auto(默认):根据方言自动选择策略,例如mysql的(identity自增策略)。id定义时标注:@GeneratedValue(strategy = GenerationType.AUTO)
(2)table:表生成策略,额外生成一张表来维护主键。
(3)sequence:序列策略
(4)identity:mysql自增策略

3、hibernate带有一些策略。

二、JPA实体Entity状态

1、四种状态

(1)临时状态:刚创建(new)出来未于JPA建立关系,不在entityManager中。
(2)持久状态(托管状态persistent):persist(),find(),merge()等等。
(3)游离状态(脱离管理状态detached):已经被持久化,不存在的entityManager里面,comit()。
(4)删除状态(remove):从数据库中删除。
JPA实体状态

@Test//状态测试
    public void testStatus() throws Exception{
        //创建实体
        OIDdomain oid = new OIDdomain();//1、临时状态
        oid.setName("蛋蛋");
        //获取管理对象
        EntityManager entityManager = JPAUtil.getEntityManager();
        //开启事务
        entityManager.getTransaction().begin();
        //添加
        entityManager.persist(oid);//2、持久状态
        //关闭事务
        entityManager.getTransaction().commit();//3、游离状态
        //关闭
        entityManager.close();
    }

2、脏数据

(1)概念:持久化状态的数据,修改set()方法修改非主键值后,未用merge()修改,EntityManager 在comit()时,会自动发送sql语句修改数据库内容,此时产生脏数据。
(2)解决:EntityManager 在comit()之前clear()一下。

@Test//脏数据测试
    public void testDirty() throws Exception{
        //获取管理对象
        EntityManager entityManager = JPAUtil.getEntityManager();
        //开启事务
        entityManager.getTransaction().begin();
        //查询
        OIDdomain oid = entityManager.find(OIDdomain.class, 2L);//2、持久状态
        //处于持久状态,修改非主键参数,提交事务时,会自动更新数据库,产生脏数据更新
        oid.setName("渣渣辉");
        //清除脏数据
        entityManager.clear();
        //提交事务
        entityManager.getTransaction().commit();
        //关闭
        entityManager.close();
    }

3、报错细节

(1)setId()修改OID会报n(原始值)-n(修改值)的错。
(2)持久对象(domain层)定义规则:domain不能被final修饰,否则影响LAZY懒加载抓取策略;值必须设置包装类;必须提供无参构造方法

三、域对象之间的关系

1、依赖关系

springMVC中javabean各层之间依赖关系。

2、关联关系

(1)概念:类之间的引用关系,以属性定义的方式表现。
(2)分类:
按导航型分为:按照导航性可分为单向关联和双向关联。
按关系分为:1-n,n-1,n-n,单向多对一最常用。

3、聚合关系

特殊一对多:如电脑与配件,可拆分。

4、组合关系

特殊一对多:如人体与器官,不可拆分。

5、单向多对一(最常用,如产品与产品类型)

(1)先保存产品分类属性(一方),再保存产品(多方),否则会发送多条sql使效率降低。

	@Test//多对一测试
    public void testManyTone() throws Exception{
        //创建分类
        ProductDir dir = new ProductDir();
        dir.setName("人类");
       ProductDir dir1 = new ProductDir();
        dir1.setName("非人类");
        //创建临时实体
        Product pro = new Product();
        pro.setName("沙雕");
        pro.setProductDir(dir);//设置产品类别
        Product pro1 = new Product();
        pro1.setName("狗崽子");
        pro1.setProductDir(dir1);//设置产品类别
        //获取工厂
        EntityManager entityManager = JPAUtil.getEntityManager();
        //开始事务
        entityManager.getTransaction().begin();
        //持久化
        // 1、先保存产品再保存分类会重复执行sql语句,降低效率,所以先保存分类,再保存产品
        // 2、persis()保存的产品,若其分类属性为临时状态未持久化处理,会报错
        entityManager.persist(dir);//先保存分类,再保存产品
        entityManager.persist(pro);//保存产品
        entityManager.persist(dir1);
        entityManager.persist(pro1);
        //提交事务
        entityManager.getTransaction().commit();
        //关闭管理对象
        entityManager.close();
    }

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

(1)lazy懒加载,延迟加载:
	@ManyToOne(fetch = FetchType.LAZY ) 需要使用的时候,才发送sql查询,默认生成ProdoctDir(一方)的子类,故一方不能用final修饰,且提供无参构造方法。
(2)EAGER饥渴加载,迫切加载:
@ManyToOne(fetch = FetchType.EAGER)发送左外连接查询数据。
	 @ManyToOne(fetch = FetchType.LAZY)//迫切加載
    @JoinColumn(name = "dir_id")//指定外键名
    private ProductDir productDir;

(3)代码测试:

@Test//抓取策略测试
    public void testFetch() throws Exception{
        EntityManager entityManager = JPAUtil.getEntityManager();
        //LAZY加载(懒加载,延迟加载)的时候:
        // 只有需要查询分类的时候,才会执行,分类查询语句
        //会生成ProductDir的子类:class cn.itsource._01ManyToOne.ProductDir_$$_jvst54f_0
        Product product = entityManager.find(Product.class, 1L);System.out.println(product.getProductDir().getClass());//ProductDir_$$_jvst54f_0
        entityManager.close();
    }
     @Test//多方判断一方是否存在
    public void testNull() throws Exception{
        EntityManager entityManager = JPAUtil.getEntityManager();
        Product product = entityManager.find(Product.class, 3L);
        if (product.getProductDir()!=null){
            System.out.println("该产品分类为:"+product.getProductDir());
        }else {
            System.out.println("该产品没有分类");
        }
    }

四、二级缓存(Encache框架)

1、缓存作用:牺牲内存空间去换取时间

2、一级缓存:属于EntityManager级别的缓存 (自带的)

(1)命中条件:同一个EntityManagerFactory 同一个EntityManager 同一个OID。

3、二级缓存:属于EntityManagerFactory级别缓存(不是自带),如果要使用二级缓存,相应配置之后,才能使用二级缓存 — 通过Encache 框架来实现二级缓存。

(1)导包、配置准备
导包:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>4.3.8.Final</version> </dependency>
配置:

<!-- 启用二级缓存 -->
<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>

(2)测试代码:

@Test//二级缓存测试
    public void test2Level() throws Exception{
        //获取工厂
        EntityManager entityManager = JPAUtil.getEntityManager();
        //查询
        Product product = entityManager.find(Product.class, 1L);//查询
        Product product1 = entityManager.find(Product.class, 1L);//一级缓存中取出
        //二级缓存
        EntityManager entityManager1 = JPAUtil.getEntityManager();
        Product product2 = entityManager1.find(Product.class, 1L);//二级缓存中取出
        Product product3 = entityManager1.find(Product.class, 1L);//一级缓存中取出
    }

五、查询缓存(基于二级缓存)

(1)命中条件:同一个EntityManagerFactory,不同一个entityManager,发出的sql语句必须相同并且查询的条件值也要相同。
(2)如果查询缓存有查询条件,就不要使用查询缓存,因为命中率非常低。
(3)查询缓存里面查询指的是使用jpql,sql进行的查询,就是调用了createQuery方法,find方法不是走查询缓存。
(4)测试代码:

 @Test//查询缓存测试
    public void testHint() throws Exception{
        //获取工厂
        EntityManager entityManager = JPAUtil.getEntityManager();
        //查询缓存(find不走查询缓存,createQuery走)
        String jpql="select o from Product o where id=?";
        TypedQuery<Product> query = entityManager.createQuery(jpql, Product.class).setParameter(1, 1L);
        //设置开启查询缓存,每一个query都要设置,否则查询缓存无效
        query.setHint(QueryHints.HINT_CACHEABLE,true );
        List<Product> list = query.getResultList();

        //二级缓存
        EntityManager entityManager1 = JPAUtil.getEntityManager();
        //查询缓存(find不走查询缓存,createQuery走)
        String jpql1="select o from Product o where id=?";
        TypedQuery<Product> query1 = entityManager.createQuery(jpql, Product.class).setParameter(1, 1L);
        //设置开启查询缓存
        query1.setHint(QueryHints.HINT_CACHEABLE,true );
        List<Product> list1 = query.getResultList();
    }

六、缓存理论部分

1、使用场景

(1)读取大于修改的使用 --查询居多的时候使用二级缓存。
(2)对数据要有独享的控制,不能被第三方程序修改。
(3)可以容忍一些无效数据,非关键性数据(财务金额不适合放入缓存里面)。日志信息。
(4)如果数据大于内存,不适合放入缓存里面 – 钝化
ehcache支持钝化
http://www.mamicode.com/info-detail-1291774.html

2、缓存淘汰策略:

(1)LRU(Least Recently Used):最近最少使用 ,以 时间为参考点。
(2)LFU(Least Frequently Uesd):最不经常使用,以频率,次数为参考点。
(3)FIFO(First in First Out):先进先出。

猜你喜欢

转载自blog.csdn.net/weixin_44671176/article/details/97266350