[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用

内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。

本人互联网技术爱好者,互联网技术发烧友

微博:伊直都在0221

QQ:951226918

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1.双向 1-n

  1)域模型:从 Order 到 Customer 的多对一双向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性

    [原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

  2)关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键

     [原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

   

2.单向 n-1 关键点解释

  1)当 Session 从数据库中加载 Java 集合时, 创建的是 Hibernate 内置集合类的实例, 因此在持久化类中定义集合属性时必须把属性声明为 Java 接口类型

      > Hibernate 的内置集合类具有集合代理功能, 支持延迟检索策略

      > 事实上, Hibernate 的内置集合类封装了 JDK 中的集合类, 这使得 Hibernate 能够对缓存中的集合对象进行脏检查, 按照集合对象的状态来同步更新数据库。

  2)在定义集合属性时, 通常把它初始化为集合实现类的一个实例. 这样可以提高程序的健壮性, 避免应用程序访问取值为 null 的集合的方法抛出 NullPointerException

[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

  3)Hibernate 使用 <set> 元素来映射 set 类型的属性        

  <!-- 在 1 端 -->
<!-- 映射 1对 n 的那个集合属性 -->
<!-- set:映射set类型的属性,
table:set 中的元素中的记录放在哪一个数据表中,该值 需要 n 端的表的名字一致
key:指定n 端 表中的外键列的名字
-->
<set name="orders" table="ORDERS">
<key column="CUSTOMER_ID"></key>
<!-- 指定映射类型 1 - n -->
<one-to-many class="Order"/>
</set>

3.代码

[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- hibernate 连接数据库的基本信息 -->
<property name="connection.username">root</property>
<property name="connection.password">zhangzhen</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql:///hibernate</property> <!-- 配置hibernate 的节本信息 -->
<!-- hibernate 所使用的数据库方言 -->
<!--<property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>-->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 执行操作时是否在控制台打印SQL -->
<property name="show_sql">true</property> <!-- 是否都SQL 进行格式化 -->
<property name="format_sql">true</property> <!-- 指定自动生成数据表的策略 -->
<property name="hbm2ddl.auto">update</property> <!-- 设置hibernate 的事务隔离级别 -->
<property name="connection.isolation">2</property> <!-- 配置c3p0 -->
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="c3p0.acquire_increment">2</property>
<property name="c3p0.idle_test_period">2000</property>
<property name="c3p0.timeout">2000</property>
<property name="c3p0.max_statements">10</property> <!-- 对于mysql 无效,对于oracle 有效 -->
<!-- 设定JDBC 的Statement 读取数据的时候每次从数据库中取出的记录的条数 -->
<property name="hibernate.jdbc.fetch_size">100</property> <!-- 设置数据库进行批量删除,批量更新和批量插入的时候的大小 -->
<property name="hibernate.jdbc.batch_size">30</property> <!-- 指定关联的 .hbm.xml 文件 -->
<!--
<mapping resource="hibernate/helloworld/News.hbm.xml"/>
<mapping resource="hibernate/helloworld/Worker.hbm.xml"/> <mapping resource="com/jason/hibernate/entities/n21/Customer.hbm.xml"/>
<mapping resource="com/jason/hibernate/entities/n21/Order.hbm.xml"/>
--> <mapping resource="com/jason/hibernate/entities/n21/both/Customer.hbm.xml"/>
<mapping resource="com/jason/hibernate/entities/n21/both/Order.hbm.xml"/> </session-factory> </hibernate-configuration>

hibernate.cfg.xml

Customer.hbm.xml

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-10-5 17:43:02 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="com.jason.hibernate.entities.n21.both"> <class name="Customer" table="CUSTOMERS"> <id name="customerId" type="java.lang.Integer">
<column name="CUSTOMER_ID" />
<generator class="native" />
</id> <property name="customerName" type="java.lang.String">
<column name="CUSTOMER_NAME" />
</property> <!-- 在 1 端 -->
<!-- 映射 1对 n 的那个集合属性 -->
<!-- set:映射set类型的属性,
table:set 中的元素中的记录放在哪一个数据表中,该值 需要 n 端的表的名字一致
key:指定n 端 表中的外键列的名字
-->
<set name="orders" table="ORDERS">
<key column="CUSTOMER_ID"></key>
<!-- 指定映射类型 1 - n -->
<one-to-many class="Order"/>
</set> </class> </hibernate-mapping>

Customer

 package com.jason.hibernate.entities.n21.both;

 import java.util.HashSet;
import java.util.Set; public class Customer { private Integer customerId;
private String customerName; /*
* 1.orders 初始化后,防止发生空指针异常
* 2.声明集合类型时,需使用接口类型,因为hibernate 在获取集合类型时,返回的是hibernate 内置的集合类型,而不是javaSE 的实现
*/
private Set<Order> orders = new HashSet<>();
public Set<Order> getOrders() {
return orders;
} public void setOrders(Set<Order> orders) {
this.orders = orders;
} public Integer getCustomerId() {
return customerId;
} public void setCustomerId(Integer customerId) {
this.customerId = customerId;
} public String getCustomerName() {
return customerName;
} public void setCustomerName(String customerName) {
this.customerName = customerName;
} @Override
public String toString() {
return "Customer [customerId=" + customerId + ", customerName="
+ customerName + "]";
} }

Order.hbm.xml

 <?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-10-5 17:43:02 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="com.jason.hibernate.entities.n21.both">
<class name="Order" table="ORDERS"> <id name="orderId" type="java.lang.Integer">
<column name="ORDER_ID" />
<generator class="native" />
</id> <property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" />
</property> <!-- 映射 多对一 关联关系 -->
<!--
name: 'n'端 关联 '1'端的属性的名字
class: '1'端 属性对应的类名
colum: '1'端 在 'n'端 对应的数据表中的外键的名字
-->
<many-to-one name="customer" class="Customer">
<column name="CUSTOMER_ID" />
</many-to-one> </class> </hibernate-mapping>

Order

 package com.jason.hibernate.entities.n21.both;

 public class Order {

     private Integer orderId;
private String orderName; private Customer customer; public Integer getOrderId() {
return orderId;
} public void setOrderId(Integer orderId) {
this.orderId = orderId;
} public String getOrderName() {
return orderName;
} public void setOrderName(String orderName) {
this.orderName = orderName;
} public Customer getCustomer() {
return customer;
} public void setCustomer(Customer customer) {
this.customer = customer;
} @Override
public String toString() {
return "Order [orderId=" + orderId + ", orderName=" + orderName
+ ", customer=" + customer + "]";
} }

HibernateTest.java

 package com.jason.hibernate.entities.n21.both;

 import hibernate.helloworld.News;
import hibernate.helloworld.Pay;
import hibernate.helloworld.Worker; import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.Date;
import java.sql.SQLException; import org.hibernate.Hibernate;
import org.hibernate.LazyInitializationException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.jdbc.Work;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.omg.CORBA.ORB; public class HibernateTest { private SessionFactory sessionFactory;
private Session session;
private Transaction transaction; @Test
public void test() { // 1. 创建一个SessionFatory 对象
SessionFactory sessionFactory = null; // 1) 创建Configuration 对象:对应hibernate 的基本配置信息 和 对象关系映射信息
Configuration configuration = new Configuration().configure(); // 2) 创建一个ServiceRegistry 对象:hibernate 4.x 新天添加的对象。
// hibernate 的任何配置 和 服务都需要在该对象中注册后才有效
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry(); // sessionFactory = configuration.buildSessionFactory();
sessionFactory = configuration.buildSessionFactory(serviceRegistry); // 2. 创建一个session 对象
Session session = sessionFactory.openSession(); // 3. 开启事物
Transaction transaction = session.beginTransaction(); // 4.执行保存操作
News news = new News("java", "jason", new Date(
new java.util.Date().getTime()));
session.save(news); // 5.提交事物
transaction.commit();
// 6.关闭session
session.close();
// 7.关闭SessionFactory 对象
sessionFactory.close();
} // 创建上述三个对象
@Before
public void init() {
Configuration configuration = new Configuration().configure();
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); session = sessionFactory.openSession(); transaction = session.beginTransaction();
} // 关闭上述三个对象
@After
public void destroy() {
transaction.commit();
session.close();
sessionFactory.close();
} @Test
public void testDelete() {
// 在不设定级联关系的情况下,且 1 端的对象 有 n端的对象在引用,不能直接删除1 端的对象
Customer customer = (Customer) session.get(Customer.class, 1);
session.delete(customer);
} @Test
public void testUpdate2(){
Customer customer = (Customer) session.get(Customer.class, 1);
customer.getOrders().iterator().next().setOrderName("BBBB");
}
@Test
public void testUpdate() {
Order order = (Order) session.get(Order.class, 1);
order.getCustomer().setCustomerName("tom2"); } @Test
public void testOne2ManyGet() { //1.对n 的一端的集合使用延迟加载
Customer customer = (Customer) session.get(Customer.class, 1);
System.out.println(customer.getCustomerName()); //2.返回n端的集合是hibernate 的内置集合类型。该类型具有延迟加载和存放代理对象的功能
System.out.println(customer.getOrders().getClass()); //3.可能抛出 LazyInitializationException 异常 //4.再需要使用集合中元素的时候进行初始化 } @Test
public void testManyToOneGet() {
// 1.若查询n 的一端的对象,则默认情况下,只查询了n 的一端的对象,而没有查询关联的1 端的对象
// 延迟加载
Order order = (Order) session.get(Order.class, 1);
System.out.println(order); // 2.在需要使用到关联的对象,才发送对应的sql 语句
Customer customer = order.getCustomer();
System.out.println(customer); // 3.获取order对象,默认情况,其关联的Customer 对象是一个代理对象
} @Test
public void testManyToOneSave() {
Customer customer = new Customer();
customer.setCustomerName("AA"); Order order1 = new Order();
order1.setOrderName("order-1"); Order order2 = new Order();
order2.setOrderName("order-2"); // 设定关联关系
order1.setCustomer(customer);
order2.setCustomer(customer); customer.getOrders().add(order1);
customer.getOrders().add(order2); // 执行svae操作:先插入 Customer,再插入Order,3条insert,2条update
// 因为1端 和 n端 都维护关联关系,所以多出四条
// 可以在1 端的set节点,指定inverse=true ,来使1端放弃维护关联关系
// 建议先插入1 的一端,后插入 n端
//
session.save(customer);
session.save(order1);
session.save(order2); // 先插入Order,再插入Customer,3条insert,4条update
// session.save(order1);
// session.save(order2);
//
// session.save(customer); } }

关于set标签

[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

  1) <set> 元素来映射持久化类的 set 类型的属性 name: 设定待映射的持久化类的属性的

  2)<key> 元素设定与所关联的持久化类对应的表的外键 column: 指定关联表的外键名

  3)<one-to-many> 元素设定集合属性中所关联的持久化类 class: 指定关联的持久化类的类名

  4)inverse 属性

    ① 在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系. inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责维护关联关系

        ② 在没有设置 inverse=true 的情况下,父子两边都维护父子 关系

    ③ 在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)

    ④ 在 1-N 关系中,若将 1 方设为主控方

      >会额外多出 update 语句。

      >插入数据时无法同时插入外键列,因而无法为外键列添加非空约束

  5)cascade 属性(了解)

    ① 在对象 – 关系映射文件中, 用于映射持久化类之间关联关系的元素, <set>, <many-to-one> 和 <one-to-one> 都有一个 cascade 属性, 它用于指定如何操纵与当前对象关联的其他对象.

[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

  6)order-by 属性  

    ①  <set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序。设置的是表的字段名,而不是持久化类的属性名

    ②  order-by 属性中还可以加入 SQL 函数

  [原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )

说明:
  1.在 n 端的 .hbm.xml 中映射关联关系
 <!-- 映射 多对一 关联关系 -->
<!--
name: 'n'端 关联 '1'端的属性的名字
class: '1'端 属性对应的类名
colum: '1'端 在 'n'端 对应的数据表中的外键的名字
-->
<many-to-one name="customer" class="Customer">
<column name="CUSTOMER_ID" />
</many-to-one>

  
上一篇:Ubuntu 复制 拷贝和自适应屏幕


下一篇:『AngularJS』ngValue