[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用
内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。
本人互联网技术爱好者,互联网技术发烧友
微博:伊直都在0221
QQ:951226918
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.双向 1-n
1)域模型:从 Order 到 Customer 的多对一双向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性
2)关系数据模型:ORDERS 表中的 CUSTOMER_ID 参照 CUSTOMER 表的主键
2.单向 n-1 关键点解释
1)当 Session 从数据库中加载 Java 集合时, 创建的是 Hibernate 内置集合类的实例, 因此在持久化类中定义集合属性时必须把属性声明为 Java 接口类型
> Hibernate 的内置集合类具有集合代理功能, 支持延迟检索策略
> 事实上, Hibernate 的内置集合类封装了 JDK 中的集合类, 这使得 Hibernate 能够对缓存中的集合对象进行脏检查, 按照集合对象的状态来同步更新数据库。
2)在定义集合属性时, 通常把它初始化为集合实现类的一个实例. 这样可以提高程序的健壮性, 避免应用程序访问取值为 null 的集合的方法抛出 NullPointerException
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.代码
<?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标签
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 属性, 它用于指定如何操纵与当前对象关联的其他对象.
6)order-by 属性
① <set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序。设置的是表的字段名,而不是持久化类的属性名
② order-by 属性中还可以加入 SQL 函数
说明:
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>
[原创]java WEB学习笔记83:Hibernate学习之路---双向 1-n介绍,关键点解释,代码实现,set属性介绍(inverse,cascade ,order-by )的更多相关文章
- [原创]java WEB学习笔记95:Hibernate 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- [原创]java WEB学习笔记75:Struts2 学习之路-- 总结 和 目录
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- [原创]java WEB学习笔记66:Struts2 学习之路--Struts的CRUD操作( 查看 / 删除/ 添加) 使用 paramsPrepareParamsStack 重构代码 ,PrepareInterceptor拦截器,paramsPrepareParamsStack 拦截器栈
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁
guava 学习笔记 使用瓜娃(guava)的选择和预判断使代码变得简洁 1,本文翻译自 http://eclipsesource.com/blogs/2012/06/06/cleaner-code- ...
- 学习笔记:CentOS7学习之二十:shell脚本的基础
目录 学习笔记:CentOS7学习之二十:shell脚本的基础 20.1 shell 基本语法 20.1.1 什么是shell? 20.1.2 编程语言分类 20.1.3 什么是shell脚本 20. ...
- 学习笔记:CentOS7学习之十九:Linux网络管理技术
目录 学习笔记:CentOS7学习之十九:Linux网络管理技术 本文用于记录学习体会.心得,兼做笔记使用,方便以后复习总结.内容基本完全参考学神教育教材,图片大多取材自学神教育资料,在此非常感谢MK ...
- 学习笔记:CentOS7学习之十六:LVM管理和ssm存储管理器使用
目录 学习笔记:CentOS7学习之十六:LVM管理和ssm存储管理器使用 16.1 LVM的工作原理 16.1.1 LVM常用术语 16.1.2 LVM优点 16.2 创建LVM的基本步骤 16.2 ...
- 学习笔记:APP切图那点事儿–详细介绍android和ios平台
学习笔记:APP切图那点事儿–详细介绍android和ios平台 转载自:http://www.woofeng.cn/articles/168.html 版权归原作者所有 作者:亚茹有李 原文地址 ...
- HTML+CSS学习笔记 (6) - 开始学习CSS
HTML+CSS学习笔记 (6) - 开始学习CSS 认识CSS样式 CSS全称为"层叠样式表 (Cascading Style Sheets)",它主要是用于定义HTML内容在浏 ...
- 在Java Web程序中使用Hibernate
在Java Web程序中使用Hibernate与普通Java程序一样.本文中将使用Servlet和JSP结合Hibernate实现数据库表的增删改查操作. Web程序中,hibernate.cfg.x ...
随机推荐
- JS初学者必备的几个经典案例(一)!!!
一:选中复选框按钮可用 和 倒计时10秒后按钮可用 这是倒计时10秒后按钮可用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...
- SQL 编辑
局部变量: DECLARE @variable_name Datatype Variable_naem为局部变量的名称,Datatype为数据名称. 例如: DECLARE @name varchar ...
- FastMM、FastCode、FastMove的使用(图文并茂)
FastMM是一个替换Embarcadero Delphi Win32应用程序的快速内存管理器,以及可以在多线程下使用,不容易产生内存碎片,并且无需使用外部DLL文件就可以支持共享内存. 使用方法:1 ...
- SIP学习(实例详解)
本文摘自:http://blog.chinaunix.net/uid-20655530-id-1589483.html 学习 SIP 协议最快捷的方法是通过范例来学习, 找到了一个完整的呼叫流程,le ...
- 在zendstudio中添加注释
/** * * * @access public * @param string $cat_id 分类查询字符串 * @return string */ 然后在function之前的一行打上/**然后 ...
- ios copy/strong/weak..使用总结
总结 关于属性的这些选项的学习,做一下总结: 所有的属性,都尽可能使用nonatomic,以提高效率,除非真的有必要考虑线程安全. NSString:通常都使用copy,以得到新的内存分配,而不只是原 ...
- The Simplified Project Management Process
One of the challenges of explaining project management to people who are unfamiliar with the approac ...
- 替换SearchBar 键盘上的 搜索 按钮
for (UIView *searchBarSubview in [searchBar subviews]) { if ([searchBarSubview conformsToProt ...
- JavaScript:复选框事件的处理
复选框事件的处理 复选框本身也是多个组件的名字相同.所以在定义复选框的同事依然要使用document.all()取得全部的内容. 范例:操作复选框,要求是可以一个个去选择选项,也可以直接全选,全选按钮 ...
- Linux和Windows路由配置
Linux和Windows路由配置 一.配置路由 1- 原则上一台主机只能有一条缺省路由.如果一台主机上有多个网段的话,请配置能够上网的那个网段的网关为缺省路由 Linux配置缺省路由: ...