什么是主键:
1.不能为空而且唯一 ,
2.唯一标识 (每一行区分其他键)

主键分类:
代理主键:

  • 使用没有实际意义的列作为一个主键 (比如id)

自然主键:

  • 使用具体实际意义的列作为的主键(就像name)

主键生成策略

若是交给了jpa主键策略@GeneratedValue 在保存数据的时候就不需要设置该主键的值了因为这个值已经交给jap进行维护了


  @GeneratedValue(strategy=GenerationType.AUTO)         
 自己会根据你的配置的方言 来选择使用的生成策略 -- 主键自增(mysql) --序列(oracle)


@GeneratedValue (strategy = GenerationType.IDENTITY)
                                          主键由数据库自动生成(主要是自动增长型)  

            
@GeneratedValue (strategy = GenerationType.SEQUENCE)
                                        序列 mysql不支持 但是oracle支持序列        
      
@GeneratedValue(strategy = GenerationType.TABLE) 
                                       表的策略 兼容好 可以mysql 支持oracle 性能有点低() 使用一个特定的数据库表格来保存主键。

JPA实体对象的状态:

瞬时状态
刚刚创建出来(new)还没有和entityManager发生关系(属于临时对象)
托管状态:
已经和entityManger 发生关系(调用方法进行增删改的时候)已经发生关系被持久化加入到entityManager的一级缓存中(填充一级缓存)
游离状态
已经和entity脱离关系 已经被持久化,但不处于entityManager中。(类似于分手)
删除状态
若是我们要删除一个内容remove这个状态的 只有调用了entityManager.remove(domain对象)方法对象有关联的ID,并且在entityManager管理下,但是已经被计划删除,事务提交就真的被删除了。

脏数据更新:

什么是脏数据:

  1. 是指源系统中的数据不在给定的范围内或对于实际业务毫无意义,或是数据格式非法,以及在源系统中存在不规范的编码和含糊的业务逻辑。
  2. 通俗的讲就是当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

脏数据更新:

若是修改了主键的值则会报错 n-to-n问题
一个持久化状态的数据,如果修改非主键的值,在commit的时候,会自动发送update语句更新

代码体现

@Test
         public void test01(){

         /*
          *    当我查询一条数据的时候 从数据库里面拿到值
          *    此时实例entil对象状态改变改为托管状态持久化状态
          *     当你拿到查询到的值(此时的值是缓存中的值)然后修改它 此时修改后的值存在在内存里面
          *    当你提交事务的时候
          *    jpa会将内存中的值跟缓存中的进行比较若是一致则不修改值 若是不一致则修改缓存里面的值修改数据库里面的值
          */
         EntityManager manager = Util.getEntityManager();
         manager.getTransaction().begin();
         // 此时这个对象已经被持久化并且添加到一级缓存里面了
         Student student = manager.find(Student.class, 1L);
         //设置值
         student.setName("你几号啊");
         Student student1 = manager.find(Student.class, 1L);
         System.out.println(student.equals(student1));
         manager.getTransaction().commit();
         System.out.println(student);
         manager.close();
     }

实体定义规则:

  1. 实体类不能定义成final(最终的)类型 因为不能被继承* 后面讲 lazyload 在使用懒加载的时候,会在内存里面创建一个子类
    2.若是使用了find就无法使用懒加载 实体里面的字段全部包装类型底层很多代码都是判断 是否为null
    3.若是基本数据类型如何比较是否为null 如果实体里面有有参数的构造方法,一定要提供一个无参数构造方法
    比如使用find,要使用无参数的构造方法创建对象

实体之间的关系:

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

关联关系(jpa难点):

按照内容或者性质来分: 类和类之间有关联性 比如 员工和部门

  • 多对一 多个成员对应一个部门
  • 一对多 :一 个老师对应多个学生
  • 多对多 : 一个角色(演员学生 老师) 对应多个权限 ,一个 权限 被多个角色管理
  • 一对一:一夫一妻 一个人对应一个身份证 一个qq号 对应一个qq空间
    按照导航性分:
    单向:只能从A方获取另外一个方b方,但是b方无法获取a方(单恋 暗恋)
    双向:**相互都可以获取 热恋
    单向多对一员工和部门

组合关系:
(多对一 或者一对多 整体和部分之间,整体和部分不能分割)比如人 和 人的部位
在项目中的体现:比如涉及单据的地方 订单当你在下单之后在后台就是不可以分割的一部分

聚合关系:
(多对一 或者一对多 整体和部分之间,整体和部分可以分开存在)
电脑台式机 鼠标 硬盘 风扇
泛化关系:体现继承

组合关系单项多对一代码实现:

@Test
    public void testname() throws Exception {
    /*若是先保存多方在保存一方则 发送sql为3条  反之为5条
当你将一方的方在上面先执行的时候 先设置的值为dir  然后在设置 员工对象里面的name和age 若是你先保存多方的值则
 先设置 员工表的 age和nane 然后再去设置部门表的 name 此时员工表的外键 idr是没有值的 当你设 他会在发送两条修改的sql 修改值
Hibernate: update t_employee set age=?, dpt_id=?, name=? where id=?
 Hibernate: update t_employee set age=?, dpt_id=?, name=? where id=?
  */
        // 单项多对一
        Department department = new Department();
        department.setName("市场部");// 设置部门
        employee employee = new employee();//创建第一个员工对象
        employee.setAge(22);//设置值
        employee.setName("小胡");
         employee.setDpt(department);// 设置外键
        employee employee2 = new employee();//第二个员工对象
        employee2.setAge(22);
        employee2.setName("小xiang");
        employee2.setDpt(department);
        EntityManager manager = Util.getEntityManager();
        manager.getTransaction().begin();
        
        manager.persist(department);
        manager.persist(employee);
        manager.persist(employee2);
        manager.getTransaction().commit();
        manager.close();
    }

懒加载和急加载:

懒加载@ManyToOne(fetch = FetchType.LAZY) 
        就是当你需要的时候采取数据库里面取数据:
        延时加载   即需要使用的时候采取加载可能会相对慢点但是对于内存占用率少
       急加载 @ManyToOne(fetch = FetchType.EAGER)
       同懒加载相反

懒记载底层原理:为什么不使用finad
懒加载测试代码

@Test
    public void testLazy()throws Exception{
/*
* 理解 底层原理  懒加载
 *          非find--查询出来放入缓存里面employee 把放入缓存里面
 *          第二次在获取的时候,从缓存里面找是否有分类的名称,如果没有分类名称
 *          getName,在发送sql查询分类名称
 *         延迟加载 跟你生成额外的 departenmt的子类 cn.itsource.jpa.Departmentt_$$_jvsta7d_1 若是使用find 则无法生成子类则
 *         无法使用懒加载默认急加载
* */
        EntityManager entityManager = Util.getEntityManager();
        employee employee = entityManager.find(employee.class, 8L);
        //得到分类名称
        if(employee.getDpt() == null){
            System.out.println("没有外键");
        }else{
            System.out.println("有外键");
        }
        System.out.println(employee.getDpt().getName());//.getName 的时候才发出sql语句
        System.out.println(employee.getDpt().getClass());//延迟加载 跟你生成额外的 departenmt的子类 cn.itsource.jpa.Departmentt_$$_jvsta7d_1


    }

二级缓存:
什么是二级缓存:

缓存命中条件:

一级缓存命中条件 :
同一个工厂对象 同一个管理着对象 同一个oid
二级缓存命中条件:
同一个工厂对象 不同的管理着对象 同一个oid

什么时候使用二级缓存:

  1. 读取大于修改,因为修改数据的时候,缓存同步变化
  2. 对数据要有独享控制,数据不会被第三方修改;如果修改数据,缓存也需要改变
  3. 缓存里面数据 可以容忍无效数据(日志信息等对实时性要求不高数据)
  4. 如果数据量比较大,也不适合放入缓存(钝化encache 支持内存 磁盘存储)

测试二级缓存代码

@Test
          public void test11()throws  Exception{
        /*      当我们第一次查询到数据的时候会将数据放入一级缓存和二级缓存里面 一级缓存依赖的是管理着对象
             二级缓存依赖的是工厂对象 两种方式依赖的对象不一样
        *       当我们使用 manger。close的时候是清除一级缓存二级缓存并没有被清除
        *       所以当我们使用不同的管理着对象查询的时候先去的一级缓存里面找然后去二级缓存里面找
        *        若是匹配则 直接拿来用所以 此代码只发送一条sql语句
        * */


            // 测试二级缓存  同一个 共工厂对象  不同的管理着对象  同一个oid
          EntityManager manager1 = Util.getEntityManager();
          manager1.find(employee.class, 8L);
          manager1.close();
          EntityManager manager2 = Util.getEntityManager();
          manager2.find(employee.class,8L );
          manager2.close();
      }

二级缓存注意事项代码:

@Test
        public void test12()throws  Exception{
     /*        当我们在find查询方法之前床创建对象的时候 此的的这个对象是顺时状态 所以没有加入二级缓存
     *           若是在find之后创建的对象就会加如二级缓存
                   此代码发送两条sql
            
     * */

        EntityManager manager1 = Util.getEntityManager();
        EntityManager manager2 = Util.getEntityManager();
        manager1.find(employee.class,8L );
        manager1.close();
        manager2.find(employee.class,8L );
        manager2.close();

        }


}