一、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):从数据库中删除。
@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):先进先出。