1       对象状态与一级缓存

1.1   状态介绍

l  hibernate 规定三种状态:瞬时态、持久态、脱管态

l  状态

瞬时态:transient,session没有缓存对象,数据库也没有对应记录。

OID特点:没有值

持久态:persistent,session缓存对象,数据库最终会有记录。(事务没有提交)

OID特点:有值

脱管态:detached,session没有缓存对象,数据库有记录。

OID特点:有值

1.2   转换

1.2.1   瞬时态/临时态

l  获得:一般都只直接创建(new)

l  瞬时态 转换 持久态

一般操作:save方法、saveOrUpdate

l  瞬时态 转换 脱管态

一般操作:通过setId方法设置数据

例如:

User user = new User();        //瞬时态

user.setUid(1);                      //脱管态

1.2.2   持久态

l  获得:

查询操作:get、loat、createQuery、createCriteria 等 获得都是持久态【】

执行save之后持久态

执行update之后持久态

l  持久态 转换 瞬时态

官方规定执行delete()  --民间:删除态

先转游离,再设置主键为 null;

l  持久态 转换 脱管态(游离态)

session没有记录

session.close () 关闭

session.clear() 清除所有

session.evict(obj) 清除指定的PO对象

1.2.3   脱管态/游离态

l  获得:

创建、并设置OID的

通过api获得

l  脱管态 转换 瞬时态

手动去除OID,设置成默认值

l  脱管态 转换 持久态

一般操作:update()、saveOrUpdate

@Test

public void demo01(){

User user = new User();     //瞬时态

user.setUsername("jack");

user.setPassword("1234");   //瞬时态(与oid没有关系)

Session session = factory.openSession();

session.beginTransaction();

session.save(user);         //持久态

//持久态就应该有持久态的行为(特性,虽然此时没有改变数据库,但是最终会改变)

//user.setUsername("rose");  //持久态对象 被修改后,hibernate将自动生成update语句

//session.flush();

session.getTransaction().commit();

session.close();

System.out.println(user);  //脱管态

}

注意: 在hibernate中所有的改变过一级缓存中的数据的(与快照对象不等的),都会在事物结束时使用update

语句,来更新数据库中的数据(save方法不会,因为其已经操作数据库了,但其虽然在save处打印的

   Insert语句, 也是在事物提交的时才会改变数据库中的数据)

      在hibernate中,持久化的id,是不允许修改的

2       一级缓存

2.1   介绍

    l  一级缓存:又称为session级别的缓存。当获得一次会话(session),hibernate在session中创建多个集合(map),

  用于存放操作数据(PO对象),为程序优化服务,如果之后需要相应的数据,hibernate优先从session缓存中获取,

  如果有就使用;如果没有再查询数据库。当session关闭时,一级缓存销毁。

  注意: 只要与session产生关联,无论是从数据库中查找得到,还是程序存入,都会有一级缓存对象,

   但是,快照只有在从数据库中获得数据后才会存在

2.2   一级缓存操作

2.2.1   证明一级缓存

@Test

public void demo02(){

//证明一级缓存

Session session = factory.openSession();

session.beginTransaction();

//1 查询 id = 1

User user = (User) session.get(User.class, 1);

System.out.println(user);

//2 再查询 -- 不执行select语句,将从一级缓存获得

User user2 = (User) session.get(User.class, 1);

System.out.println(user2);

session.getTransaction().commit();

session.close();

}

2.2.2   移除( clear() , evict() )

@Test

public void demo03(){

//清除缓存

Session session = factory.openSession();

session.beginTransaction();

User user = (User) session.get(User.class, 1);  //--select

System.out.println(user);

//清除

//session.clear();  //清空1级缓存。

session.evict(user);   //将缓存中的对象移除。

// 一级缓存没有缓存对象,从数据库直接查询

User user2 = (User) session.get(User.class, 1);  //--select

System.out.println(user2);

session.getTransaction().commit();

session.close();

}

2.2.3   一级缓存快照【掌握】

     快照:与一级缓存一样的存放位置,对一级缓存数据备份。保证数据库的数据与 一级缓存的数据必须一致。

  如果一级缓存修改了,在执行commit提交时,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库。

  注意: 只要与session产生关联,无论是从数据库中查找得到,还是程序存入,都会有一级缓存对象,

但是,快照只有在从数据库中获得数据后才会存在

  作用: 提高效率 : 只要最后缓存对象的值对比与快照没有改变,就不会执行update语句。

2.2.4   refresh , flush

     refresh 保证 一级缓存的数据 与 数据库的数据 保持一致。将执行select语句查询数据库,

  将一级缓存中的数据覆盖掉。只要执行refresh都将执行select语句。(演示注意隔离级别,oracal中直接用)

     flush  对比快照,如果数据有改变,会立刻提交缓存对象,(数据库在提交事物之后才会改变)

@Test

public void demo04(){

//刷新

Session session = factory.openSession();

session.beginTransaction();

User user = (User) session.get(User.class, 1);  //--select

System.out.println(user);

session.refresh(user); //将缓存中的对象与数据库同步,立刻发送一个select语句

session.flush();        // 立刻提交session缓存中的对象到数据库

session.getTransaction().commit();

session.close();

}

2.2.5   快照演示(一级缓存刷新)

@Test

public void demo05(){

//快照

Session session = factory.openSession();

session.beginTransaction();

User user = (User) session.get(User.class, 1);  //--select

System.out.println(user);

//修改持久态对象内容(一级缓存内容)--默认在commit时,将触发update语句。

user.setUsername("rose2");

session.getTransaction().commit();

session.close();

}

   问题:一级缓存什么时候刷新?(了解)

       默认情况提交(commit())刷新。

@Test

public void demo06(){

//设置刷新时机

Session session = factory.openSession();

session.beginTransaction();

//1 设置

session.setFlushMode(FlushMode.MANUAL);

User user = (User) session.get(User.class, 1);

user.setUsername("rose4");

//1 查询所有 -- AUTO , 查询之前先更新,保存一级缓存和数据库一样的

//List<User> allUser = session.createQuery("from User").list();

//2手动刷新 --MANUAL 将执行update,注意:一级缓存必须修改后的

session.flush();

// 如果MANUAL 在执行commit 不进行update

session.getTransaction().commit();

session.close();

}

2.3   PO对象操作

2.3.1   save & persist

l  save方法:瞬时态 转换 持久态 ,会立即初始化OID

1.执行save方法,立即触发insert语句,从数据库获得主键的值(OID值)

2.执行save方法前,设置OID将忽略(非自然主键的情况下)。

3.如果执行查询,session缓存移除了,在执行save方法,将执行insert

l  persist方法:瞬时态 转换 持久态 ,不会立即初始化OID

    1.执行save方法,不会立即触发insert语句,从数据库获得主键的值(OID值)

2.执行save方法前,设置OID将报错(非自然主键的情况下)。

  3.如果执行查询,session缓存移除了,在执行save方法,将执行insert

注意: persist方法不会立即得到ID,所以执行sql语句的时机要靠后.

@Test

public void demo01(){

User user = new User();

user.setUid(100);

user.setUsername("jack");

user.setPassword("1234");

Session session = factory.openSession();

session.beginTransaction();

session.save(user);

session.getTransaction().commit();

session.close();

}

@Test

public void demo03(){

//代理  assigned

User user = new User();

//user.setUid(100);

user.setUsername("jack");

user.setPassword("1234");

Session session = factory.openSession();

session.beginTransaction();

session.save(user);

session.getTransaction().commit();

session.close();

}

l  注意:持久态对象不能修改OID的值   (否则会报错)

@Test

public void demo04(){

Session session = factory.openSession();

session.beginTransaction();

User user = (User) session.get(User.class, 100);

user.setUid(101);

session.save(user);

session.getTransaction().commit();

session.close();

}

插入讲解:

  1、在使用HQL语句查询的时候,如果是批量查询,则结果会放入缓存中,但是查询动作本身不会

    使用一级缓存

  2、在使用SQL  语句查询的时候,如果将查询结果封装到了对象中,那么对象会被放入一级缓存中,

    如果没有将查询结果封装到对象中,则不会放入一级缓存。

  3、  在使用criteria 对象查询时,会将查询结果放入一级缓存. 但是查询不会使用一级缓存.

    与Hql查询结论一致

2.3.2   update

l  update:脱管态 转换 持久态

如果OID在数据存放的,将执行update语句

如果OID不存在将抛异常

@Test

public void demo01(){

//自然 assigned

User user = new User();

user.setUid(101);

user.setUsername("jack1");

user.setPassword("12345");

Session session = factory.openSession();

session.beginTransaction();

session.update(user);

session.getTransaction().commit();

session.close();

}

l  注意1:如果数据没有修改,执行save方法,将触发update语句。

     查询速度 比 更新速度快

  通过<class select-before-update> 来设置更新前先查询,如果没有改变就不更新。

总结:

update 之后对象 持久态

@Test

public void demo03(){

// merge 合并

User user = new User();

user.setUid(1);

user.setUsername("jack3");

user.setPassword("12345");

Session session = factory.openSession();

session.beginTransaction();

// 1 oid =1 持久态对象

User user2 = (User) session.get(User.class, 1);

//    session.update(user);

session.merge(user);

session.getTransaction().commit();

session.close();

}

2.3.3   saveOrUpdate

l  代理主键:

判断是否有OID

如果没有OID,将执行insert语句

如果有OID,将执行update语句。

@Test

public void demo02(){

// 代理 native

User user = new User();

//    user.setUid(2);

user.setUsername("jack2");

user.setPassword("12345");

Session session = factory.openSession();

session.beginTransaction();

session.saveOrUpdate(user);

session.getTransaction().commit();

session.close();

}

l  自然主键:

先执行select语句,查询是否存放(不许主键属性为空)

如果不存在,将执行insert

如果存在,将执行update

@Test

public void demo02(){

// 自然 assigned

User user = new User();

user.setUid(2);

user.setUsername("jack2333");

user.setPassword("12345333");

Session session = factory.openSession();

session.beginTransaction();

session.saveOrUpdate(user);

session.getTransaction().commit();

session.close();

}

l  注意1:native下,默认OID是否存在,使用默认值。例如:Integer 默认null

通过<id  unsaved-value="1"> 修改使用默认值,如果设置1进行insert语句。此内容提供hibernate使用的,录入到数据库后,采用自动增长。

在我们使用Hibernate时候,注意要避免出现,两个相同的ID对象.放入一级缓存的情况.

2.3.4   delete

总结:

PO对象状态:瞬时态、持久态、脱管态

3       多表设计

l  在开发中,前期进行需求分析,需求分析提供E--R图,根据ER图编写表结构。

l  表之间关系存在3种:一对多、多对多、一对一。(回顾)

一对多:1表(主表)必须主键 和 多表(从表)必须外键,主表的主键 与 从表外键 形成主外键关系

多对多:提供中间表(从表),提供2个字段(外键)分别对应两个主表。

一对一:主表的主键在从表中作为外键,并且唯一对应(或者主表的主键为从表的主外键)

l  面单对象描述 对象与对象 之间关系?【掌握】

一对多:客户和订单

private class Customer{

//一对多:一个客户 拥有 多个订单

private Set<Order> orderSet;

}

private class Order{

//多对一:多个订单 属于 一个客户

private Customer customer;

}

多对多:Student学生 和 Course课程

private class Student{

//多对多:多个学生(当前)学习 【不同课程】

private Set<Course> courseSet ...;

}

private class Course{

//多对多:多个课程 可以被 【不同学生】学习

private Set<Student> student = ...;

}

一对一:公司company 和 地址address

private class Company{

private Address address;

}

private class Address{

private Company company;

}

4       关联关系映射

4.1   一对多实现【掌握】

4.1.1   实现类

public class Customer {

private Integer cid;

private String cname;

//一对多:一个客户(当前客户) 拥有 【多个订单】

// * 需要容器存放多个值,一般建议Set (不重复、无序)

// * 参考集合:List、Map、Array等

// ** 建议实例化--使用方便

private Set<Order> orderSet = new HashSet<Order>();

public class Order {

private Integer xid;

private String price;

//多对一:多个订单属于【一个客户】

private Customer customer;

4.1.2   配置文件

l  Customer.hbm.xml

<class name="com.itheima.b_onetomany.Customer" table="t_customer">

<id name="cid">

<generator class="native"></generator>

</id>

<property name="cname"></property>

<!-- 一对多:一个客户(当前客户) 拥有 【多个订单】

1 确定容器  set <set>

2 name确定对象属性名

3 确定从表外键的名称

4 确定关系,及另一个对象的类型

注意:

在hibernate中可以只进行单向配置

每一个配置项都可以完整的描述彼此关系。

一般情况采用双向配置,双方都可以完成描述表与表之间关系。

-->

<!-- 一对多:一个客户(当前客户) 拥有 【多个订单】 -->

<set name="orderSet" cascade="delete-orphan">

<key column="customer_id"></key>

<one-to-many class="com.itheima.b_onetomany.Order"/>

</set>

</class>

l  Order.hbm.xml

<class name="com.itheima.b_onetomany.Order" table="t_order">

<id name="xid">

<generator class="native"></generator>

</id>

<property name="price"></property>

<!-- 多对一:多个订单属于【一个客户】

* name 确定属性名称

* class 确定自定义类型

* column 确定从表的外键名称

-->

<many-to-one name="customer" class="com.itheima.b_onetomany.Customer" column="customer_id"></many-to-one>

</class>

4.2   一对多操作

4.2.1   保存客户

@Test

public void demo01(){

// 1 创建客户,并保存客户--成功

Session session = factory.openSession();

session.beginTransaction();

Customer customer = new Customer();

customer.setCname("田志成");

session.save(customer);

session.getTransaction().commit();

session.close();

}

4.2.2   保存订单

@Test

public void demo02(){

// 2 创建订单,保存订单--成功,外键为null

Session session = factory.openSession();

session.beginTransaction();

Order order = new Order();

order.setPrice("998");

session.save(order);

session.getTransaction().commit();

session.close();

}

4.2.3   客户关联订单,只保存客户(没有联级操作报错)

@Test

public void demo03(){

// 3 创建客户和订单,客户关联订单,保存客户?

Session session = factory.openSession();

session.beginTransaction();

//1 客户和订单

Customer customer = new Customer();

customer.setCname("成成");

Order order = new Order();

order.setPrice("998");

//2 客户关联订单

customer.getOrderSet().add(order);

//3 保存客户

session.save(customer);

session.getTransaction().commit();

session.close();

}

4.2.4   双向关联,使用inverse

@Test

public void demo04(){

// 4  创建客户和订单,客户关联订单,订单也关联客户,保存客户和订单?

// * 开发中优化程序 , n + 1 问题?(就是会进行多次外键维护)

// ** 解决方案1:客户不关联订单 ,不建议

// ** 解决方案2:客户放弃对订单表外键值的维护。

// **** Customer.hbm.xml <set name="orderSet" inverse="true">

// ** inverse 将维护外键值的权利交予对象。相当于自己放弃。(反转)

Session session = factory.openSession();

session.beginTransaction();

//1 客户和订单

Customer customer = new Customer();

customer.setCname("成成");

Order order = new Order();

order.setPrice("998");

//2 客户关联订单

customer.getOrderSet().add(order);

//3 订单也关联客户

order.setCustomer(customer);

//4 保存客户

// * 1 save(order) -- insert  --> 1,998 null

// * 2 订单管理客户,此时null --预留update --> 更新所有(正常设置)

// * 3 save(customer) -- insert --> 1,成成

// * 4 客户关联订单  --> 预留update --> 更新订单外键 (维护外键)

// * 5 提交commit --> 执行2 和 4

session.save(order);

session.save(customer);

session.getTransaction().commit();

session.close();

}

      在一对多开发中,一方一般都放弃对外键值的维护。及<set inverse="true”>

4.3   级联操作

4.3.1   save-update  级联保存或更新

      cascode=“save-update” : 联级属性设置。

@Test

public void demo032(){

// 32 创建客户和订单,客户关联订单,保存客户? --抛异常

// ** 解决方案2:级联操作--级联保存或更新

// ** Customer.hbm.xml <set cascade="save-update">

// ** 在保存客户的同时,一并保存订单

Session session = factory.openSession();

session.beginTransaction();

//1 客户和订单

Customer customer = new Customer();     //瞬时态

customer.setCname("成成");

Order order = new Order();           //瞬时态

order.setPrice("998");

//2 客户关联订单

customer.getOrderSet().add(order);

//3 保存客户

session.save(customer);              //持久态

// 关联操作都是持久态的,此时 持久态Customer 引用 一个 瞬时态的Order 抛异常

session.getTransaction().commit();

session.close();

}

4.3.2   delete 级联删除

      cascode=“delete” : 联级属性设置。(删除设置了该属性的一方,会删除另一边),切忌 两边都设置 delete属性。

@Test

public void demo05(){

// 5 查询客户,并删除(持久态)

// 默认:当删除客户,默认将订单外键设置成null。

// 级联删除:删除客户时,并将客户的订单删除。

// ** Customer.hbm.xml <set name="orderSet" cascade="delete">

Session session = factory.openSession();

session.beginTransaction();

Customer customer = (Customer) session.get(Customer.class, 10);

session.delete(customer);

session.getTransaction().commit();

session.close();

}

4.3.3   孤儿删除

l  一对多关系,存在父子关系。1表(主表)可以成为父表,多表(从表)也可以子表。

总结:

主表不能删除,从表已经引用(关联)的数据(添加联级操作可以)

从表不能添加,主表不存在的数据。(外键设置为null可以)

@Test

public void demo06(){

// 6 查询客户,并查询订单,解除客户和订单订单的关系

// * 默认:客户和订单解除关系后,外键被设置成null,此时订单就是孤儿。客户和订单都存在。

// * 孤儿删除(孤子删除),当订单称为孤儿,一并删除。客户仍存在。

Session session = factory.openSession();

session.beginTransaction();

//1 查询客户

Customer customer = (Customer) session.get(Customer.class, 9);

//2查询订单

Order order = (Order) session.get(Order.class, 8);

//3 解除关系

customer.getOrderSet().remove(order);

session.getTransaction().commit();

session.close();

}

4.3.4   总结

save-update:A保存,同时保存B

delete:删除A,同时删除B,AB都不存在

delete-orphan:孤儿删除,解除关系,同时将B删除,A存在的。

如果需要配置多项,使用逗号分隔。<set cascade="save-update,delete">

all : save-update 和 delete 整合

all-delete-orphan : 三个整合

Hibernate 二(一级缓存,多表设计之一对多)的更多相关文章

  1. hibernate(二)一级缓存和三种状态解析

    序言 前一篇文章知道了什么是hibernate,并且创建了第一个hibernate工程,今天就来先谈谈hibernate的一级缓存和它的三种状态,先要对着两个有一个深刻的了解,才能对后面我要讲解的一对 ...

  2. Hibernate之一级缓存和二级缓存

    1:Hibernate的一级缓存: 1.1:使用一级缓存的目的是为了减少对数据库的访问次数,从而提升hibernate的执行效率:(当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据 ...

  3. hibernate学习(四)hibernate的一级缓存&快照

    缓存:提高效率 硬件的 CPU缓存   硬盘缓存   内存 软件的  io流缓存 hibernate  的一级缓存   也是为了操作数据库的效率. 证明一级缓存在  : Person p=sessio ...

  4. hibernate Session一级缓存 应该注意的地方

    Session缓存 Hibernate的一级缓存是由Session提供的,因此它存在于Session的整个生命周期中,当程序调用save()/update()/saveOrupdate()/get() ...

  5. (转)Hibernate的一级缓存

    http://blog.csdn.net/yerenyuan_pku/article/details/70148567 Hibernate的一级缓存 Hibernate的一级缓存就是指Session缓 ...

  6. 【Hibernate】一级缓存

    一.概述 二.证明Hibernate的一级缓存的存在 三.一级缓存中快照区 四.管理一级缓存 五.Hibernate一级缓存的刷出时机 六.操作持久化对象的方法 一.概述 什么是缓存: 缓存将数据库/ ...

  7. Hibernate的一级缓存

    Hibernate的一级缓存 什么是缓存:缓存将数据库/硬盘上文件中数据,放入到缓存中(就是内存中一块空间).当再次使用的使用,可以直接从内存中获取 缓存的好处:提升程序运行的效率.缓存技术是Hibe ...

  8. Hibernate 之 一级缓存

    本篇文章主要是总结Hibernate中关于缓存的相关内容. 先来看看什么是缓存,我们这里所说的缓存主要是指应用程序与物流数据源之间(例如硬盘),用于存放临时数据的内存区域,这样做的目的是为了减少应用程 ...

  9. JavaWeb_(Hibernate框架)Hibernate中一级缓存

    Hibernate中一级缓存 Hibernate 中的缓存分为一级缓存和二级缓存,这两个级别的缓存都位于持久化层,并且存储的都是数据库数据的备份.其中一级缓存是 Hibernate 的内置缓存,在前面 ...

  10. 四 Hibernate的一级缓存&事务管理及其配置

    持久态对象: 自动更新数据库,原理是一级缓存. 缓存:是一种优化的方式,将数据存入内存,从缓存/内存中获取,不用通过存储源 Hibernate框架中提供了优化手段:缓存,抓取策略 Hibernate中 ...

随机推荐

  1. python数学第七天【期望的性质】

  2. Git官方推荐用书

    用Git看了N多的Blog, 乱七八糟. 官方的推荐用书写得最好,最权威.还可以下载pdf.记录一笔. https://git-scm.com/book/zh/v2/

  3. linux下更改MySQL数据库存储路径

    参考地址:1.https://blog.csdn.net/ArnoBM/article/details/83008212 2.http://www.cnblogs.com/lyongde/p/3725 ...

  4. Nginx 慢启动与拥塞窗口

    L:127

  5. BZOJ3275Number——二分图最大权独立集

    题目描述 有N个正整数,需要从中选出一些数,使这些数的和最大.若两个数a,b同时满足以下条件,则a,b不能同时被选1:存在正整数C,使a*a+b*b=c*c2:gcd(a,b)=1 输入 第一行一个正 ...

  6. 微信小程序——安装开发工具和环境【二】

    准备 开发工具下载 获取APPID 安装工具 安装 接受协议 选择安装位置 等待安装完成 安装完成 选择项目 选择小程序 填写信息 确定 无误后,点击确定进入开发页面 建立普通快速启动模板界面

  7. 安卓Android基础—第二天

    测试的相关概念 好的软件不是开发出来的,是不断测试出回来的 根据是否知道源代码 黑盒测试 白盒测试 根据测试的粒度 方法测试 单元测试 集成测试 系统测试 根据测试的暴力程度 压力测试(谷歌工程师提供 ...

  8. 【XSY1544】fixed 数学 强连通图计数

    题目描述 ​ 给你一个\(n\times n\)的方阵\(A\).定义方阵\(A\)的不动点\((i,j)\)为:\(\forall p,q\geq 0,(A^p)_{i,j}=(A^q)_{i,j} ...

  9. Github Desktop 克隆新项目 Authentication failed. You may not have permission to access the repository or the repository may ha

    原来:ssh://git@github.com/xxx.git 改成:https://git@github.com/xxx.git

  10. 信用算力基于 RocketMQ 实现金融级数据服务的实践

    微服务架构已成为了互联网的热门话题之一,而这也是互联网技术发展的必然阶段.然而,微服务概念的提出者 Martin Fowler 却强调:分布式调用的第一原则就是不要分布式. 纵观微服务实施过程中的弊端 ...