1.1Hibernate的持久化类状态

1.1.1Hibernate的持久化类状态

  • 持久化类:就是一个实体类和数据库表建立了映射关系。

    • Hibernate为了方便的管理持久化类,将持久化类分成了三种状态。
  • 瞬时态(临时态)  transient
  • 持久态  persistent
  • 脱管态(游离态)  detached  

1.1.2 三种持久化对象的状态

  • 瞬时态  Transient

    • 不存在持久化标识OID,尚未与Hibernate的session关联,被认为处于瞬时态,失去引用将被JVM回收。换句话说,持久化对象没有唯一标识OID,没有纳入Session的管理。
  • 持久态  Persistent
    • 存在持久化标识OID,与当前session有关联,并且相关联的session没有关闭,并且事务没有提交。换句话说,持久化对象有唯一标识OID,已经纳入Session的管理,并且持久化持久态对象具有自动更新数据库的能力。
  • 脱管态 Detached
    • 存在持久化标识OID,但是没有与当前的session关联,脱管状态改变Hibernate不能检测到。换句话说,持久化对象有唯一的标识OID,没有纳入到session管理。

1.1.3区分三种持久化对象的状态

新建cn.hibernate3.demo1.Book.java类

  1. package cn.hibernate3.demo1;
  2. /**
  3. * 实体类
  4. * @author love
  5. */
  6. public class Book {
  7. private Integer id;
  8. private String name;
  9. private Double price;
  10. private String author;
  11. public Integer getId() {
  12. return id;
  13. }
  14. public void setId(Integer id) {
  15. this.id = id;
  16. }
  17. public String getName() {
  18. return name;
  19. }
  20. public void setName(String name) {
  21. this.name = name;
  22. }
  23. public Double getPrice() {
  24. return price;
  25. }
  26. public void setPrice(Double price) {
  27. this.price = price;
  28. }
  29. public String getAuthor() {
  30. return author;
  31. }
  32. public void setAuthor(String author) {
  33. this.author = author;
  34. }
  35.  
  36. }

配置Book.hbm.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo1.Book" table="book">
  8. <id name="id" column="id">
  9. <generator class="native"/>
  10. </id>
  11. <property name="name" column="name" type="java.lang.String"/>
  12. <property name="price" column="price" type="java.lang.Double"/>
  13. <property name="author" column="author" type="java.lang.String"/>
  14. </class>
  15. </hibernate-mapping>

配置核心映射文件(hibernate.cfg.xml文件)

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC
  3. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4. "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
  5. <hibernate-configuration>
  6. <session-factory>
  7. <!-- 配置数据库的基本信息 -->
  8. <!-- 驱动的名称 -->
  9. <property name="hibernate.connection.driver_class">
  10. com.mysql.jdbc.Driver
  11. </property>
  12. <!-- 访问数据库的url -->
  13. <property name="hibernate.connection.url">
  14. jdbc:mysql:///hibernate_day02
  15. </property>
  16. <!-- 用户名 -->
  17. <property name="hibernate.connection.username">root</property>
  18. <!-- 密码 -->
  19. <property name="hibernate.connection.password">root</property>
  20. <!-- 方言 -->
  21. <property name="hibernate.dialect">
  22. org.hibernate.dialect.MySQLDialect
  23. </property>
  24. <!-- C3P0连接池设定-->
  25. <!-- 使用c3po连接池 配置连接池提供的供应商-->
  26. <property name="connection.provider_class">
  27. org.hibernate.connection.C3P0ConnectionProvider
  28. </property>
  29. <!--在连接池中可用的数据库连接的最少数目 -->
  30. <property name="c3p0.min_size">5</property>
  31. <!--在连接池中所有数据库连接的最大数目 -->
  32. <property name="c3p0.max_size">20</property>
  33. <!--设定数据库连接的过期时间,以秒为单位,
  34. 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
  35. <property name="c3p0.timeout">120</property>
  36. <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
  37. <property name="c3p0.idle_test_period">3000</property>
  38. <!-- 可选配置 -->
  39. <!-- 显示SQL -->
  40. <property name="hibernate.show_sql">true</property>
  41. <!-- 格式化SQL -->
  42. <property name="hibernate.format_sql">true</property>
  43. <!-- hbm:映射 2:to ddl:create drop alter -->
  44. <property name="hibernate.hbm2ddl.auto">update</property>
  45. <mapping resource="cn/hibernate3/demo1/Book.hbm.xml" />
  46. </session-factory>
  47. </hibernate-configuration>

新建HibernateUtils.java类

  1. package cn.utils;
  2. import org.hibernate.Session;
  3. import org.hibernate.SessionFactory;
  4. import org.hibernate.cfg.Configuration;
  5.  
  6. /**
  7. * Hibernate抽取工具类
  8. */
  9. public class HibernateUtils {
  10. private static Configuration configuration;
  11. private static SessionFactory sessionFactory;
  12. static{
  13. configuration = new Configuration().configure();
  14. sessionFactory = configuration.buildSessionFactory();
  15. }
  16.  
  17. public static Session openSession(){
  18. return sessionFactory.openSession();
  19. }
  20.  
  21. public static void main(String[] args) {
  22. openSession();
  23. }
  24. }

运行HibernateUtils工具类,即可发现创建了book表

测试

  1. package cn.hibernate3.demo1;
  2.  
  3. import org.hibernate.Session;
  4. import org.hibernate.Transaction;
  5. import org.junit.Test;
  6.  
  7. import cn.utils.HibernateUtils;
  8.  
  9. public class HibernateTest1 {
  10. @Test
  11. //区分持久化对象的三种装填
  12. public void demo1(){
  13. Session session = HibernateUtils.openSession();
  14. Transaction tx = session.beginTransaction();
  15.  
  16. //向数据库中保存一本图书
  17. Book book = new Book();//瞬时态:没有唯一标识OID,没有与session关联
  18. book.setName("Hibernate开发");
  19. book.setAuthor("哈哈");
  20. book.setPrice(65.0);
  21.  
  22. session.save(book);//持久态:有唯一标识OID,与session关联
  23.  
  24. tx.commit();
  25. session.close();
  26.  
  27. book.setName("Struts2开发");//脱管态:有唯一标识,没有与session关联
  28.  
  29. }
  30. }

 1.1.4三种对象的转换

  • 瞬时态:

    • 获取瞬时态  Book book = new Book();
    • 瞬时态-->持久态  save(book);
    • 瞬时态-->脱管态  book.setId(1);
  • 持久态
    • 获取持久态  Book book = (Book)session.get(Book.class,1);

      • get()、load()、find()、iterate();
    • 持久态-->瞬时态  delete(book);
    • 持久态-->脱管态  
      • session.close();
      • close()/clear()/evict(Object obj)。
  • 脱管态
    • 获取脱管态  Book book = new Book();book.setId(1);

      • 脱管态-->持久态  session.update(book);
      • 脱管态-->瞬时态  book.setId(null);

            

1.1.5持久态对象有自动更新数据库的能力

  1. @Test
  2. //测试持久态对象有自动更新数据库的能力
  3. public void demo2(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. //获取一个持久态对象
  8. Book book = (Book) session.get(Book.class, 1);
  9. book.setName("Struts2开发");
  10.  
  11. tx.commit();
  12. session.close();
  13.  
  14. }

自动更新数据库的能力依赖了Hibernate的一级缓存。

1.2Hibernate的一级缓存

1.2.1Hibernate的一级缓存

  • 什么是缓存?

    • 缓存将数据库/硬盘上文件中数据,加入到缓存中(就是内存中的一块的空间),当再次使用的时候,可以直接从内存中获取。
  • 缓存的好处?
    • 提升程序运行的效率,缓存技术是Hibernate的一个优化的手段。
  • Hibernate分为两个基本的缓存?
    • 一级缓存:session级别的缓存。一级缓存和session的生命周期一直。自带的,不可卸载。
    • 二级缓存:sessionFactory级别的缓存。不是自带的。

1.2.2证明Hibernate一级缓存的存在

  1.   @Test
  2. //证明一级缓存的存在
  3. public void demo3(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. //获取一个持久态对象
  8. Book book = (Book) session.get(Book.class, 1);//发送SQL语句
  9. System.out.println(book);
  10.  
  11. Book book2 = (Book) session.get(Book.class, 1);//不发送SQL语句
  12. System.out.println(book2);
  13.  
  14. tx.commit();
  15. session.close();
  16.  
  17. }

1.2.3理解session缓存(一级缓存)

  • 在session接口的实现中包含了一系列的java集合,这些java集合构成了session缓存,只要session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。
  • 当session的save()方法持久化一个对象的时候,该对象被装载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图get()、load()对象时,会判断缓存中是否存在该对象,有则返回,此时不查询数据库,没有再查询数据库。
  • session能够在某些时间点,按照缓存中对象的变化来执行相关的SQL语句,来同步更新数据库,这一过程被称为刷出缓存(flush)。
  • 默认情况下,session在以下时间点刷出缓存:
    • 当应用程序调用Transaction的commit()方法的时候,该方法会先刷出缓存,然后再向数据库提交事务。
    • 当应用程序执行一些查询操作的时候,如果缓存中持久化对象的属性已经发生了变化,会先刷出缓存,以保证查询结果能够反映持久化对象的最新状态。
    • 调用session的flush()方法。

1.2.4Hibernate一级缓存的快照区

  1.   @Test
  2. //快照区
  3. public void demo2(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. //获取一个持久态对象
  8. Book book = (Book) session.get(Book.class, 1);
  9. book.setName("Spring开发");
  10.  
  11. tx.commit();
  12. session.close();
  13.  
  14. }

分析:

  • 情况一:数据库中的数据和要修改的数据不一致

  • 情况二:当数据库中的数据和要修改的数据一致。

 

【总结】向一级缓存中存入数据的时候,放入一级缓存区和一级缓存快照区,当更新了一级缓存的数据的时候,事务一旦提交,会对比一级缓存和快照区,如果数据一致,不更新;如果数据不一致,就更新数据库。       

1.2.5 Hibernate管理一级缓存

  • 一级缓存是与session的生命周期相关的,session的生命周期结束,一级缓存就消失了。
  • clear()/evict()/flush()/refresh()管理一级缓存。
  • clear():清空一级缓存的所有的对象。
  • evict(Object obj):清空一级缓存中的某个对象。
  • flush():刷出缓存。
  • refresh(Object obj):将快照区的数据,覆盖了一级缓存的数据。

1.2.6Hibernate一级缓存刷出时机(了解)

  • FlushMode:

    • 常量

      • ALWAYS:每次查询的时候都会刷出,手动调用flush,事务提交的时候。
      • AUTO:默认值,有些查询会刷出,手动调用flush,事务提交的时候。
      • COMMIT:在事务提交的时候,手动调用flush的时候。
      • MANUAL:只有在手动调用flush才会刷出。
    • 严格程序: MANUAL> COMMIT>AUTO>ALWAYS。

1.3操作持久化对象的方法   

  • save()

    • 保存一条记录。
    • 将瞬时态对象变为持久态对象。
  • update()
    • 更新一条记录。
    • 将脱管态对象变为持久态对象。
  • saveOrUpdate()
    • 根据对象的状态的不同执行save()或update()方法。

      • 如果对象是一个瞬时态对象,执行save()方法。
      • 如果对象是一个脱管态对象,执行update()方法。
  • delete()
    • 将持久态对象变为瞬时态对象。
  • get()/load()
    • 获取一个持久化对象。

1.4Hibernate关联关系的映射            

 1.4.1实体之间的关系

  • 一对多:

    • 一个用户,生成多个订单,每一个订单只能属于一个用户。
    • 建表的原则:
      • 在多的一方创建一个字段,作为外键,指向一的一方的主键。  
  • 多对多:
    • 一个学生,可以选择多门课程,一门课程,可以被多个学生选择。
    • 建表的原则:
      • 创建第三张表,中间表至少有2个字段,分别作为外键指向多对多双方的主键。  
  • 一对一:(特殊,应用最少)
    • 一个公司只能有一个注册的地址,一个注册地址只能被一个公司所使用。
    • 建表的原则:
      • 唯一外键:

        • 一对一的双方,假设一方是多的关系,需要在多的一方创建一个字段作为外键,指向一的一方的主键。但是,在外键上添加一个unique。  
      • 主键对应: 
        • 一对一的双方,通过主键进行关联。

1.4.2Hibernate中一对多的配置

  • 创建实体

    • 创建客户实体
  1. package cn.hibernate3.demo2;
  2.  
  3. import java.io.Serializable;
  4. import java.util.HashSet;
  5. /**
  6. * 客户实体
  7. */
  8. import java.util.Set;
  9. public class Customer implements Serializable{
  10. private Integer cid;
  11. private String cname;
  12. //一个客户有多个订单
  13. private Set<Order> orders = new HashSet<Order>();
  14. public Integer getCid() {
  15. return cid;
  16. }
  17. public void setCid(Integer cid) {
  18. this.cid = cid;
  19. }
  20. public String getCname() {
  21. return cname;
  22. }
  23. public void setCname(String cname) {
  24. this.cname = cname;
  25. }
  26. public Set<Order> getOrders() {
  27. return orders;
  28. }
  29. public void setOrders(Set<Order> orders) {
  30. this.orders = orders;
  31. }
  32.  
  33. }
    • 订单实体
  1. package cn.hibernate3.demo2;
  2.  
  3. import java.io.Serializable;
  4. /**
  5. * 订单实体
  6. */
  7. public class Order implements Serializable{
  8. private Integer oid;
  9. private String addr;
  10. //订单属于某一个客户
  11. private Customer customer ;
  12.  
  13. public Integer getOid() {
  14. return oid;
  15. }
  16. public void setOid(Integer oid) {
  17. this.oid = oid;
  18. }
  19. public String getAddr() {
  20. return addr;
  21. }
  22. public void setAddr(String addr) {
  23. this.addr = addr;
  24. }
  25. public Customer getCustomer() {
  26. return customer;
  27. }
  28. public void setCustomer(Customer customer) {
  29. this.customer = customer;
  30. }
  31.  
  32. }
  • 配置映射文件

    • Customer.hbm.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Customer" table="customer">
  8. <!-- 配置唯一标识 -->
  9. <id name="cid" column="cid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="cname" column="cname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!-- 配置集合 -->
  16. <!--
  17. set标签中的name表示关联对象的属性名称
  18.  
  19. -->
  20. <set name="orders" >
  21. <!-- key标签中的column用来一对多的多的一方的外键 -->
  22. <key column="cno"/>
  23. <!-- 配置一个one-to-many -->
  24. <one-to-many class="cn.hibernate3.demo2.Order"/>
  25. </set>
  26. </class>
  27. </hibernate-mapping>
    • Order.hbm.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Order" table="orders">
  8. <!-- 配置唯一标识 -->
  9. <id name="oid" column="oid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="addr" column="addr" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!--
  16. many-to-one标签
  17. 属性:
  18. name:关联对象的属性名称。
  19. column:表中外键的名称。
  20. class:关联对象的全路径。
  21. -->
  22. <many-to-one name="customer" column="cno" class="cn.hibernate3.demo2.Customer"></many-to-one>
  23. </class>
  24. </hibernate-mapping>
  • 将映射文件放到核心配置文件中
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC
  3. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4. "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
  5. <hibernate-configuration>
  6. <session-factory>
  7. <!-- 配置数据库的基本信息 -->
  8. <!-- 驱动的名称 -->
  9. <property name="hibernate.connection.driver_class">
  10. com.mysql.jdbc.Driver
  11. </property>
  12. <!-- 访问数据库的url -->
  13. <property name="hibernate.connection.url">
  14. jdbc:mysql:///hibernate_day02
  15. </property>
  16. <!-- 用户名 -->
  17. <property name="hibernate.connection.username">root</property>
  18. <!-- 密码 -->
  19. <property name="hibernate.connection.password">root</property>
  20. <!-- 方言 -->
  21. <property name="hibernate.dialect">
  22. org.hibernate.dialect.MySQLDialect
  23. </property>
  24. <!-- C3P0连接池设定-->
  25. <!-- 使用c3po连接池 配置连接池提供的供应商-->
  26. <property name="connection.provider_class">
  27. org.hibernate.connection.C3P0ConnectionProvider
  28. </property>
  29. <!--在连接池中可用的数据库连接的最少数目 -->
  30. <property name="c3p0.min_size">5</property>
  31. <!--在连接池中所有数据库连接的最大数目 -->
  32. <property name="c3p0.max_size">20</property>
  33. <!--设定数据库连接的过期时间,以秒为单位,
  34. 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
  35. <property name="c3p0.timeout">120</property>
  36. <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
  37. <property name="c3p0.idle_test_period">3000</property>
  38. <!-- 可选配置 -->
  39. <!-- 显示SQL -->
  40. <property name="hibernate.show_sql">true</property>
  41. <!-- 格式化SQL -->
  42. <property name="hibernate.format_sql">true</property>
  43. <!-- hbm:映射 2:to ddl:create drop alter -->
  44. <property name="hibernate.hbm2ddl.auto">update</property>
  45. <mapping resource="cn/hibernate3/demo2/Customer.hbm.xml" />
  46. <mapping resource="cn/hibernate3/demo2/Order.hbm2.xml" />
  47.  
  48. </session-factory>
  49. </hibernate-configuration>
  • 运行HibernateUtils.java类

1.4.3Hibernate中一对多级联保存

  1. @Test
  2. //向客户表插入一个客户,在订单表中插入两个订单
  3. public void demo1(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6. //定义客户
  7. Customer customer = new Customer();
  8. customer.setCname("郭浩");
  9. //定义订单
  10. Order order1 = new Order();
  11. order1.setAddr("新疆");
  12. Order order2 = new Order();
  13. order2.setAddr("江苏");
  14. //建立关系
  15. customer.getOrders().add(order1);
  16. customer.getOrders().add(order2);
  17. order1.setCustomer(customer);
  18. order2.setCustomer(customer);
  19.  
  20. session.save(customer);
  21. session.save(order2);
  22. session.save(order1);
  23.  
  24. tx.commit();
  25. session.close();
  26. }

1.4.4Hibernate中一对多的级联保存

  • 从1.4.3我们让一方和多方对象产生关联关系,并保存一方和多方对象,那么我们是否只保存一方呢?
  1.   @Test
  2. //向客户表插入一个客户,在订单表中插入两个订单
  3. public void demo2(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6. //定义客户
  7. Customer customer = new Customer();
  8. customer.setCname("郭浩");
  9. //定义订单
  10. Order order1 = new Order();
  11. order1.setAddr("新疆");
  12. Order order2 = new Order();
  13. order2.setAddr("江苏");
  14. //建立关系
  15. customer.getOrders().add(order1);
  16. customer.getOrders().add(order2);
  17. //保存的时候只保存一方
  18. session.save(customer);
  19.  
  20. tx.commit();
  21. session.close();
  22. }

此时,会出现异常。

上面的异常的意思就是对象引用了一个没有保存的瞬时态的对象,换句话说,就是customer对象是持久态的,而order1和order2是瞬时态的对象,Hibernate不允许持久态对象关联瞬时态对象。

  • 没有办法了吗?不是,我们需要使用Hibernate提供的级联保存。

    • 级联:操作当前对象的时候,关联的对象如何处理。
    • 级联的方向性:
      • 保存客户的时候,选择级联订单。
      • 保存订单的时候,选择级联客户。
    • cascade="save-update"。
  1.   @Test
  2. //级联保存 保存客户的时候,级联订单
  3. //<set>标签上是客户的关联订单对象的集合,所以在<set>上配置一个属性:cascade
  4. public void demo3(){
  5. Session session = HibernateUtils.openSession();
  6. Transaction tx = session.beginTransaction();
  7. //定义客户
  8. Customer customer = new Customer();
  9. customer.setCname("郭浩");
  10. //定义订单
  11. Order order1 = new Order();
  12. order1.setAddr("新疆");
  13. Order order2 = new Order();
  14. order2.setAddr("江苏");
  15. //建立关系
  16. customer.getOrders().add(order1);
  17. customer.getOrders().add(order2);
  18. //保存的时候只保存一方
  19. session.save(customer);
  20.  
  21. tx.commit();
  22. session.close();
  23. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Customer" table="customer">
  8. <!-- 配置唯一标识 -->
  9. <id name="cid" column="cid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="cname" column="cname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!-- 配置集合 -->
  16. <!--
  17. set标签中的name表示关联对象的属性名称
  18.  
  19. -->
  20. <set name="orders" cascade="save-update">
  21. <!-- key标签中的column用来一对多的多的一方的外键 -->
  22. <key column="cno"/>
  23. <!-- 配置一个one-to-many -->
  24. <one-to-many class="cn.hibernate3.demo2.Order"/>
  25. </set>
  26. </class>
  27. </hibernate-mapping>

  • 如何我从多的一方呢?

    • 在<many-to-one>上配置cascade="save-update"
  1.   @Test
  2. public void demo4(){
  3. Session session = HibernateUtils.openSession();
  4. Transaction tx = session.beginTransaction();
  5. //定义客户
  6. Customer customer = new Customer();
  7. customer.setCname("郭浩");
  8. //定义订单
  9. Order order1 = new Order();
  10. order1.setAddr("新疆");
  11. Order order2 = new Order();
  12. order2.setAddr("江苏");
  13. //建立关系
  14. customer.getOrders().add(order1);
  15. customer.getOrders().add(order2);
  16. order1.setCustomer(customer);
  17. order2.setCustomer(customer);
  18.  
  19. session.save(order1);
  20. session.save(order2);
  21.  
  22. tx.commit();
  23. session.close();
  24. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Order" table="orders">
  8. <!-- 配置唯一标识 -->
  9. <id name="oid" column="oid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="addr" column="addr" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!--
  16. many-to-one标签
  17. 属性:
  18. name:关联对象的属性名称。
  19. column:表中外键的名称。
  20. class:关联对象的全路径。
  21. -->
  22. <many-to-one cascade="save-update" name="customer" column="cno" class="cn.hibernate3.demo2.Customer"></many-to-one>
  23. </class>
  24. </hibernate-mapping>

1.4.5Hibernate中一对多级联删除 

  • 默认情况下,将外键设置为null,删除数据记录。

  1.   @Test
  2. //默认情况下,将外键设置为null,然后删除记录
  3. public void demo5(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. Customer customer = (Customer) session.get(Customer.class, 1);
  8. session.delete(customer);
  9.  
  10. tx.commit();
  11. session.close();
  12. }

  • 添加cascade="delete"。
  1.   @Test
  2. //级联删除
  3. public void demo5(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. Customer customer = (Customer) session.get(Customer.class, 1);
  8. session.delete(customer);
  9.  
  10. tx.commit();
  11. session.close();
  12. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Customer" table="customer">
  8. <!-- 配置唯一标识 -->
  9. <id name="cid" column="cid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="cname" column="cname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!-- 配置集合 -->
  16. <!--
  17. set标签中的name表示关联对象的属性名称
  18.  
  19. -->
  20. <set name="orders" cascade="delete">
  21. <!-- key标签中的column用来一对多的多的一方的外键 -->
  22. <key column="cno"/>
  23. <!-- 配置一个one-to-many -->
  24. <one-to-many class="cn.hibernate3.demo2.Order"/>
  25. </set>
  26. </class>
  27. </hibernate-mapping>

1.4.6Hibernate中级联的取值

  • none:不使用级联。
  • save-update:保存或更新的时候使用级联。
  • delete:删除的时候使用级联。
  • all:除了孤儿删除以外的所有级联。
  • delete-orphan:孤儿删除。
    • 仅限于一对多的情况,只有一对多时候,才有父子表(主从表),认为一的一方是父表,多的一方是子表。
    • 当一个客户与某个订单解除了关系,将外键设置为null。订单没有了所属的客户,相当于一个孩子没有父亲,就相当于一个孤儿,那么Hibernate就会将这类没有外键的记录删除。
  • all-delete-orphan:包含了孤儿删除的所有的级联。  

演示:孤儿删除的情况,默认情况下。

  1.   @Test
  2. //孤儿删除,默认情况下,是将外键设置为null。
  3. public void demo6(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. Customer customer = (Customer) session.get(Customer.class, 1);
  8.  
  9. Order order = (Order) session.get(Order.class, 1);
  10.  
  11. customer.getOrders().remove(order);
  12.  
  13. tx.commit();
  14. session.close();
  15. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Customer" table="customer">
  8. <!-- 配置唯一标识 -->
  9. <id name="cid" column="cid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="cname" column="cname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!-- 配置集合 -->
  16. <!--
  17. set标签中的name表示关联对象的属性名称
  18.  
  19. -->
  20. <set name="orders" >
  21. <!-- key标签中的column用来一对多的多的一方的外键 -->
  22. <key column="cno"/>
  23. <!-- 配置一个one-to-many -->
  24. <one-to-many class="cn.hibernate3.demo2.Order"/>
  25. </set>
  26. </class>
  27. </hibernate-mapping>

  • 配置孤儿删除。

  1.   @Test
  2. //孤儿删除
  3. public void demo6(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. Customer customer = (Customer) session.get(Customer.class, 1);
  8.  
  9. Order order = (Order) session.get(Order.class, 1);
  10.  
  11. customer.getOrders().remove(order);
  12.  
  13. tx.commit();
  14. session.close();
  15. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Customer" table="customer">
  8. <!-- 配置唯一标识 -->
  9. <id name="cid" column="cid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="cname" column="cname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!-- 配置集合 -->
  16. <!--
  17. set标签中的name表示关联对象的属性名称
  18.  
  19. -->
  20. <set name="orders" cascade="delete-orphan">
  21. <!-- key标签中的column用来一对多的多的一方的外键 -->
  22. <key column="cno"/>
  23. <!-- 配置一个one-to-many -->
  24. <one-to-many class="cn.hibernate3.demo2.Order"/>
  25. </set>
  26. </class>
  27. </hibernate-mapping>

1.4.7双向维护产生多余SQL及inverse配置

  1.   @Test
  2. //双向关联,产生多余的SQL
  3. public void demo7(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. Customer customer = (Customer) session.get(Customer.class, 1);
  8.  
  9. Order order = (Order) session.get(Order.class, 2);
  10.  
  11. customer.getOrders().add(order);
  12. order.setCustomer(customer);
  13.  
  14. tx.commit();
  15. session.close();
  16. }

  • 分析

  • 所以,双向维护,意味着双方都有外键的维护能力,那怎么办呢?必须让其中的一方放弃外键的维护权。

    • 添加属性inverse="true"。
    • inverse:是反转的意思,即我不维护,就是我放弃外键的维护权。
    • 一般情况下,是一方放弃的,多方维护的。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo2.Customer" table="customer">
  8. <!-- 配置唯一标识 -->
  9. <id name="cid" column="cid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="cname" column="cname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!-- 配置集合 -->
  16. <!--
  17. set标签中的name表示关联对象的属性名称
  18.  
  19. -->
  20. <set name="orders" inverse="true">
  21. <!-- key标签中的column用来一对多的多的一方的外键 -->
  22. <key column="cno"/>
  23. <!-- 配置一个one-to-many -->
  24. <one-to-many class="cn.hibernate3.demo2.Order"/>
  25. </set>
  26. </class>
  27. </hibernate-mapping>

【注意】

  • cascade:操作关联对象。
  • inverse:控制外键的维护。

    

1.4.8Hibernate中多对多的配置

  • 建立实体类

    • Student.java
  1. package cn.hibernate3.demo3;
  2.  
  3. import java.io.Serializable;
  4. import java.util.HashSet;
  5. import java.util.Set;
  6.  
  7. public class Student implements Serializable{
  8. private Integer sid;
  9. private String sname;
  10. private Set<Course> courses = new HashSet<Course>();
  11. public Integer getSid() {
  12. return sid;
  13. }
  14. public void setSid(Integer sid) {
  15. this.sid = sid;
  16. }
  17. public String getSname() {
  18. return sname;
  19. }
  20. public void setSname(String sname) {
  21. this.sname = sname;
  22. }
  23. public Set<Course> getCourses() {
  24. return courses;
  25. }
  26. public void setCourses(Set<Course> courses) {
  27. this.courses = courses;
  28. }
  29.  
  30. }
    • Course.java
  1. package cn.hibernate3.demo3;
  2.  
  3. import java.io.Serializable;
  4. import java.util.HashSet;
  5. import java.util.Set;
  6.  
  7. public class Course implements Serializable{
  8. private Integer cid;
  9. private String cname;
  10. private Set<Student> students = new HashSet<Student>();
  11. public Integer getCid() {
  12. return cid;
  13. }
  14. public void setCid(Integer cid) {
  15. this.cid = cid;
  16. }
  17. public String getCname() {
  18. return cname;
  19. }
  20. public void setCname(String cname) {
  21. this.cname = cname;
  22. }
  23. public Set<Student> getStudents() {
  24. return students;
  25. }
  26. public void setStudents(Set<Student> students) {
  27. this.students = students;
  28. }
  29.  
  30. }
  • 建立映射

    • Student.hbm.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo3.Student" table="student">
  8. <!-- 配置唯一标识 -->
  9. <id name="sid" column="sid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="sname" column="sname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!--
  16. <set>标签中的name:对应学生中课程集合的名称 table对应的是中间表的名称
  17. -->
  18. <set name="courses" table="student_course">
  19. <!--
  20. <key>标签对应的是中间表中的外键
  21. -->
  22. <key column="sid"/>
  23. <!--
  24. <many-to-many>对应的是另一方的类的全路径,column:另一方在中间表中外键的名称
  25. -->
  26. <many-to-many class="cn.hibernate3.demo3.Course" column="cid" />
  27. </set>
  28. </class>
  29. </hibernate-mapping>
    • Course.hbm.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo3.Course" table="course">
  8. <!-- 配置唯一标识 -->
  9. <id name="cid" column="cid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="cname" column="cname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <set name="students" table="student_course">
  16. <key column="cid"/>
  17. <many-to-many class="cn.hibernate3.demo3.Student" column="sid"/>
  18. </set>
  19. </class>
  20. </hibernate-mapping>
  • 将映射文件加载到核心配置文件中
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC
  3. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4. "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
  5. <hibernate-configuration>
  6. <session-factory>
  7. <!-- 配置数据库的基本信息 -->
  8. <!-- 驱动的名称 -->
  9. <property name="hibernate.connection.driver_class">
  10. com.mysql.jdbc.Driver
  11. </property>
  12. <!-- 访问数据库的url -->
  13. <property name="hibernate.connection.url">
  14. jdbc:mysql:///hibernate_day02
  15. </property>
  16. <!-- 用户名 -->
  17. <property name="hibernate.connection.username">root</property>
  18. <!-- 密码 -->
  19. <property name="hibernate.connection.password">root</property>
  20. <!-- 方言 -->
  21. <property name="hibernate.dialect">
  22. org.hibernate.dialect.MySQLDialect
  23. </property>
  24. <!-- C3P0连接池设定-->
  25. <!-- 使用c3po连接池 配置连接池提供的供应商-->
  26. <property name="connection.provider_class">
  27. org.hibernate.connection.C3P0ConnectionProvider
  28. </property>
  29. <!--在连接池中可用的数据库连接的最少数目 -->
  30. <property name="c3p0.min_size">5</property>
  31. <!--在连接池中所有数据库连接的最大数目 -->
  32. <property name="c3p0.max_size">20</property>
  33. <!--设定数据库连接的过期时间,以秒为单位,
  34. 如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
  35. <property name="c3p0.timeout">120</property>
  36. <!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
  37. <property name="c3p0.idle_test_period">3000</property>
  38. <!-- 可选配置 -->
  39. <!-- 显示SQL -->
  40. <property name="hibernate.show_sql">true</property>
  41. <!-- 格式化SQL -->
  42. <property name="hibernate.format_sql">true</property>
  43. <!-- hbm:映射 2:to ddl:create drop alter -->
  44. <property name="hibernate.hbm2ddl.auto">update</property>
  45. <mapping resource="cn/hibernate3/demo3/Student.hbm.xml" />
  46. <mapping resource="cn/hibernate3/demo3/Course.hbm.xml" />
  47.  
  48. </session-factory>
  49. </hibernate-configuration>

【注意】:映射文件的理解

1.4.9Hibernate中多对多的保存

  • 测试类
  1.   @Test
  2. //保存学生和课程,为学生选择一些课程
  3. public void demo1(){
  4. Session session = HibernateUtils.openSession();
  5. Transaction tx = session.beginTransaction();
  6.  
  7. //创建学生
  8. Student student1 = new Student();
  9. student1.setSname("张三");
  10. Student student2 = new Student();
  11. student2.setSname("李四");
  12. //创建课程
  13. Course course1 = new Course();
  14. course1.setCname("java语言");
  15. Course course2 = new Course();
  16. course2.setCname("Android语言");
  17.  
  18. //张三选择1号和2号课程
  19. student1.getCourses().add(course1);
  20. student1.getCourses().add(course2);
  21. course1.getStudents().add(student1);
  22. course2.getStudents().add(student1);
  23.  
  24. //李四选择1号课程
  25. student2.getCourses().add(course1);
  26. course1.getStudents().add(student2);
  27.  
  28. //保存记录
  29. session.save(student1);
  30. session.save(student2);
  31. session.save(course1);
  32. session.save(course2);
  33.  
  34. tx.commit();
  35. session.close();
  36. }

但是,这样会抛出异常。

所以,多对多的配置中,必须有一方放弃主键维护。比如学生放弃主键维护的权利。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- 引入约束 -->
  3. <!DOCTYPE hibernate-mapping PUBLIC
  4. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  5. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  6. <hibernate-mapping>
  7. <class name="cn.hibernate3.demo3.Student" table="student">
  8. <!-- 配置唯一标识 -->
  9. <id name="sid" column="sid">
  10. <generator class="native"/>
  11. </id>
  12. <!-- 配置普通属性 -->
  13. <property name="sname" column="sname" type="java.lang.String"/>
  14. <!-- 建立映射 -->
  15. <!--
  16. <set>标签中的name:对应学生中课程集合的名称 table对应的是中间表的名称
  17. -->
  18. <set name="courses" table="student_course" inverse="true">
  19. <!--
  20. <key>标签对应的是中间表中的外键
  21. -->
  22. <key column="sid"/>
  23. <!--
  24. <many-to-many>对应的是另一方的类的全路径,column:另一方在中间表中外键的名称
  25. -->
  26. <many-to-many class="cn.hibernate3.demo3.Course" column="cid" />
  27. </set>
  28. </class>
  29. </hibernate-mapping>

  

Hibernate(二)的更多相关文章

  1. Hibernate二次学习一----------Hibernate简单搭建

    因为博客园自带的markdown不太好用,因此所有markdown笔记都使用cmd_markdown发布 Hibernate二次学习一----------Hibernate简单搭建: https:// ...

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

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

  3. Hibernate(二)——POJO对象的操作

    POJO对象其实就是我们的实体,这篇博客总结一下框架对POJO对象对应数据库主键的生成策略,和一些对POJO对象的简单增删改查的操作.  一,Hibernate框架中主键的生成策略有三种方式: 1,数 ...

  4. Spring整合Hibernate 二 - 声明式的事务管理

    Spring大战Hibernate之声明式的事务管理 Spring配置文件: 添加事务管理类的bean: <bean id="txManager" class="o ...

  5. Hibernate(二)

    性能分析 抓取策略 研究对象 研究怎么样提取集合的,该策略应该作用与set元素上 研究从一的一方加载多的一方 案例 查询cid为1的班级的所有的学生 明:通过一条sql语句:左外链接,把classes ...

  6. Hibernate(二)__简单实例入门

    首先我们进一步理解什么是对象关系映射模型? 它将对数据库中数据的处理转化为对对象的处理.如下图所示: 入门简单实例: hiberante 可以用在 j2se 项目,也可以用在 j2ee (web项目中 ...

  7. Hibernate二 映射 注解 一级缓存

    Hibernate映射1.@Entity 被该注解修饰的POJO类是一个实体,可以用name属性指定该实体类的名称,系统默认以该类的类名作为实体类的名称.2.@Table 指定持久化类所映射的表,它的 ...

  8. Hibernate 二(一级缓存,多表设计之一对多)

    1       对象状态与一级缓存 1.1   状态介绍 l  hibernate 规定三种状态:瞬时态.持久态.脱管态 l  状态 瞬时态:transient,session没有缓存对象,数据库也没 ...

  9. ssh架构之hibernate(二)进阶学习

    1.JPA入门 JPA的认识:JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中Java持久层AP ...

  10. Hibernate(二)持久化对象的状态

    简介 以前学习Hibernate的笔记,整理一下便发出来了,防止弄丢.有错误的话麻烦各位留言评论,感激不尽. 持久化类 Hibernate完成了从面向对象模型表示的对象至关系模型表示的数据结构的映射, ...

随机推荐

  1. Spring MVC 项目搭建 -6- spring security 使用自定义Filter实现验证扩展资源验证,使用数据库进行配置

    Spring MVC 项目搭建 -6- spring security使用自定义Filter实现验证扩展url验证,使用数据库进行配置 实现的主要流程 1.创建一个Filter 继承 Abstract ...

  2. Sublime Text 3 注册码

    最近觉得Sublime Text3比Notepad++好使,可惜需要购买,于是网上搜了一下,屌丝的福音啊: Sublime Text Build 3065 License key复制如下三个任意一个正 ...

  3. NavigationView的头部的事件监听

    现在App的UI设计中Drawerlayout+NavigationView是一个比较常用的设计了,而以前我一般只是在Navigation中的menu(即下部的item中)添加事件监听,而今天碰到一个 ...

  4. VBS连接远程Oracle

    原文链接:http://hi.baidu.com/coo_boi/item/5a2e1860ded285136995e6a7 连接方式还是用的ADO,驱动是MSDAORA. 使用oracle前,ora ...

  5. Android性能优化:ViewStub

    在开发应用程序的时候,经常会遇到这样的情况,会在运行时动态根据条件来决定显示哪个View或某个布局.那么最通常的想法就是把可能用到的View都写在上面,先把它们的可见性都设为View.GONE,然后在 ...

  6. Week 1 # A A + B Problem II

    原题描述: A - A + B Problem II I have a very simple problem for you. Given two integers A and B, your jo ...

  7. Python爬虫从入门到放弃(十九)之 Scrapy爬取所有知乎用户信息(下)

    在上一篇文章中主要写了关于爬虫过程的分析,下面是代码的实现,完整代码在:https://github.com/pythonsite/spider items中的代码主要是我们要爬取的字段的定义 cla ...

  8. 如何在Shell中快速切换目录

    1.回到上一次进入的路经cd -2.回到Homecd ~3.自动补齐实例,cd /usr/src/redhat,可以用cd /u[TAB]s[TAB]r[TAB]4.!$ 表示上一个命令的最后一个参数 ...

  9. FTP publisher plugin插件

    说明:这个插件可以将构建的产物(例如:Jar)发布到FTP中去. 官方说明:FTP publisher plugin 安装步骤: 系统管理→管理插件→可选插件→Artifact Uploaders→F ...

  10. tensorflow dropout函数应用

    1.dropout dropout 是指在深度学习网络的训练过程中,按照一定的概率将一部分神经网络单元暂时从网络中丢弃,相当于从原始的网络中找到一个更瘦的网络,这篇博客中讲的非常详细   2.tens ...