2.0、Hibernate-级联关系
级联关系 中 最为常见的就是 ->
1、一对多关系 :一个消费者可以购买多个商品 -> 生成多个订单; 消费者是1,订单是多
那么在数据库中,1 的一方是主表,多的一方是从表,通过主外键关系去维护;
在Java的面向对象中就是用pojo实体类属性去表示;
2、多对多关系:大学生选课,一个学生可以选择多门课程,一门课程也可以被多个学生选择;
数据库中是通过两个一对多关系来维护的,学生和课程都是主表,额外增加一张中间表作为从表,两张主表和中间表都是一对多的关系;
Java 和 数据库 对于这两种关系的体现完全是两种不同的方式,Hibernate 框架的作用就是将这两种方式进行转换和映射;
接下来看看一对多代码演示【环境配置在 1.0、Hibernate-快速入门初体验中介绍过了】:
第一步:数据库中创建两张表 customer 和 orders,如下所示 ->
第二步:在 com.hkl.pojo 文件夹下创建两个 pojo 实体类 Java 文件,customer.java 和 order.java,如下所示->
package com.hkl.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Set;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
private Integer id;
private String name;
// 一个消费者对应多个订单
private Set<Order> orders;
}
package com.hkl.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private Integer id;
private String name;
//一个订单对应一个消费者
private Customer customer;
}
第三步:在 com.hkl.pojo 文件夹下创建两个xml配置文件,Customer.hbm.xml 和 Order.hbm.xml,如下所示->
Customer.hbm.xml ->
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.hkl.pojo.Customer" table="customer">
<!-- 主键映射,数据库表中的主键字段用 id 配置,而 name = "id" 这个 id 指的是 Customer 实体类中的 id 属性名-->
<id name="id" type="java.lang.Integer">
<!-- 数据库表 id 主键字段配置-->
<column name="id"></column>
<!-- 设置主键自增方式 -> identity-->
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<!-- orders是实体类Customer中的属性名,该属性是一个Order类的集合,所以对应表 order-->
<set name="orders" table="orders">
<!-- 这里配置一下主外键 cid -->
<key column="cid"></key>
<!-- 消费者和订单的关系是一对多,所以这里是 one-to-many,然后给set类型加一个对象,对象类型是Order-->
<one-to-many class="com.hkl.pojo.Order"></one-to-many>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml ->
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.hkl.pojo.Order" table="orders">
<!-- 主键映射,数据库表中的主键字段用 id 配置,而 name = "id" 这个 id 指的是 Customer 实体类中的 id 属性名-->
<id name="id" type="java.lang.Integer">
<!-- 数据库表 id 主键字段配置-->
<column name="id"></column>
<!-- 设置主键自增方式 -> identity-->
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<!-- 这里订单和消费者是多对一的关系,所以 order 是从表,外键依旧是 cid-->
<many-to-one name="customer" class="com.hkl.pojo.Customer" column="cid"></many-to-one>
</class>
</hibernate-mapping>
说明一下 标签 含义 ->
set 标签来配置实体类中的集合属性orders;
name 实体类属性名;
table 表名;
key 外键
one-to-many 与集合泛型的实体类对应;
many-to-one 配置实体类对应的对象属性;
name 属性名;
class 属性对应的类;
column 外键;
到这里其实就可以看出来 hibernate 和 mybatis 的区别了,首先 mybatis 是一个半自动的 ORM 框架,而 hibernate 是一个全自动的 ORM 框架;
hibernate 是将 数据库表 和 pojo实体类 直接映射,而 mybatis 是将 sql结果集 和 pojo实体类 映射起来;
第四步:将这两个映射配置文件 注册 到 hibernate 配置文件中去,代码如下 ->
<!--注册实体关系映射文件-->
<mapping resource="com/hkl/pojo/Customer.hbm.xml"></mapping>
<mapping resource="com/hkl/pojo/Order.hbm.xml"></mapping>
第五步:用 hibernate API 去调用,在 test 文件夹下创建 Test2.java 文件,如下所示->
import com.hkl.pojo.Customer;
import com.hkl.pojo.Order;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Test2 {
public static void main(String[] args) {
// 创建configuration
Configuration configuration = new Configuration().configure();
// 获取sessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
// 获取Session
Session session = sessionFactory.openSession();
// 创建Customer
Customer customer = new Customer();
customer.setName("小澜");
// 创建 order
Order order = new Order();
order.setName("订单1");
// 建立关联关系
order.setCustomer(customer);
// 保存
session.save(customer);
session.save(order);
// 提交事务
session.beginTransaction().commit();
// 关闭session
session.close();
}
}
运行后可以看到数据添加成功->
记录一下这里我遇到的一个问题,一直报错说我的 sql 语句有问题,找了很久才发现数据库的表名是 order,而这个名字是一个sql关键字,所以不能使用,如下所示->
多对多代码演示->
第一步:创建数据库表 account 和 course 和 account_course 三张表,如下所示->
第二步:在 com.hkl.pojo 文件夹下创建对应的 pojo 实体类文件,Account.java 和 Course.java 文件,如下所示->
Account.java
package com.hkl.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Set;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Account {
private Integer id;
private String name;
private Set<Course> courses;
}
Course.java
package com.hkl.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Set;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Course {
private Integer id;
private String name;
private Set<Account> accounts;
}
第三步:在 com.hkl.pojo文件夹下创建两个对应的映射文件,Account.hbm.xml 和 Course.hbm.xml ,如下所示->
Account.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.hkl.pojo.Account" table="t_account">
<!-- 主键映射,数据库表中的主键字段用 id 配置,而 name = "id" 这个 id 指的是 Course 实体类中的 id 属性名-->
<id name="id" type="java.lang.Integer">
<!-- 数据库表 id 主键字段配置-->
<column name="id"></column>
<!-- 设置主键自增方式 -> identity-->
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<!--courses是实体类Course中的属性名,该属性是一个 Course 类的集合,所以对应表 account_course-->
<set name="courses" table="account_course">
<!--这里配置一下主外键 cid -->
<key column="aid"></key>
<!--学生和选课的关系是多对多,所以这里是 many-to-many,然后给set类型加一个对象,对象类型是Account , column是account在这个中间表中的外键aid-->
<many-to-many class="com.hkl.pojo.Course" column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
Course.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.hkl.pojo.Course" table="t_course">
<!-- 主键映射,数据库表中的主键字段用 id 配置,而 name = "id" 这个 id 指的是 Account 实体类中的 id 属性名-->
<id name="id" type="java.lang.Integer">
<!-- 数据库表 id 主键字段配置-->
<column name="id"></column>
<!-- 设置主键自增方式 -> identity-->
<generator class="identity"></generator>
</id>
<property name="name" type="java.lang.String">
<column name="name"></column>
</property>
<!--courses是实体类Course中的属性名,该属性是一个 Course 类的集合,所以对应表 account_course-->
<set name="accounts" table="account_course">
<!--这里配置一下主外键 aid -->
<key column="cid"></key>
<!--学生和选课的关系是多对多,所以这里是 many-to-many,然后给set类型加一个对象,对象类型是Course , column是course在这个中间表中的外键cid-->
<many-to-many class="com.hkl.pojo.Account" column="aid"></many-to-many>
</set>
</class>
</hibernate-mapping>
第四步:将映射文件注册到 hibernate.cfg.xml 配置文件中,如下所示->
<mapping resource="com/hkl/pojo/Account.hbm.xml"></mapping>
<mapping resource="com/hkl/pojo/Course.hbm.xml"></mapping>
第五步:在test文件夹下创建 test3.java 文件,调用 Hibernate API 去测试一下,如下所示->
import com.hkl.pojo.Account;
import com.hkl.pojo.Course;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import java.util.HashSet;
import java.util.Set;
public class Test3 {
public static void main(String[] args) {
// 创建configuration
Configuration configuration = new Configuration().configure();
// 获取sessionFactory
SessionFactory sessionFactory = configuration.buildSessionFactory();
// 获取Session
Session session = sessionFactory.openSession();
//创建course
Course course = new Course();
course.setName("Java编程与设计");
//创建account
Account account = new Account();
account.setName("小澜");
//将封装好的course放到set集合中去
Set<Course> courses = new HashSet<Course>();
courses.add(course);
//将封装好的set集合与account建立联系
account.setCourses(courses);
//提交事务
session.save(course);
session.save(account);
//提交事务
session.beginTransaction().commit();
//关闭session
session.close();
}
}
可以看到我这里运行了三次都成功的添加了数据~