关联
什么是关联(association)
关联指的是类之间的引用关系。如果类A与类B关联,那么被引用的类B将被定义为类A的属性。
public class A{
private B b = new B;
public A(){}
}
关联的分类:
关联可以分为一对一、一对多/多对一、多对多关联
没有固定对象
关联有方向
-
一对一:比如一对一家教
-
一对多: 比如平常学校里的教学老师与学生的关系
-
多对一:比如一个人有很多种角色,但本质上还是这个人
-
多对多:可以理解为多个人对多种事物的看法
一对多实例
代码
首先看需要哪些类/包
数据库脚本
-- 订单表(主表)
create table t_order_hb
(
order_id int primary key auto_increment,
order_no varchar(50) not null
);
-- 订单项表(从表)
create table t_order_item_hb
(
order_item_id int primary key auto_increment,
product_id int not null,
quantity int not null,
oid int not null,
foreign key(oid) references t_order_hb(order_id)
);
第一步
配置需要的jar包依赖
以及工具类
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.solar</groupId>
<artifactId>hibernate</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>maven Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<servlet.version>4.0.1</servlet.version>
<junit.version>3.8.1</junit.version>
<mysql.version>5.1.44</mysql.version>
<jstl.version>1.2</jstl.version>
<standard.version>1.1.2</standard.version>
<tomcat.version>8.5.38</tomcat.version>
<hibernate.version>5.2.12.Final</hibernate.version>
</properties>
<dependencies>
<!-- hibernate -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- tomcat-jsp-api -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jsp-api</artifactId>
<version>${tomcat.version}</version>
</dependency>
<!-- standard -->
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>${standard.version}</version>
</dependency>
<!-- jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
<!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>provided</scope>
</dependency>
<!-- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
<build>
<finalName>maven</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
SessionFactoryUtils工具类
package com.solar.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class SessionFactoryUtils {
private static final String
HIBERNATE_CONFIG_FILE="hibernate.cfg.xml";
private static ThreadLocal<Session> threadLocal=
new ThreadLocal<Session>();
//创建数据库的会话工厂
private static SessionFactory sessionFactory;
//读取hibernate核心配置
private static Configuration configuration;
static {
try {
configuration=new Configuration();
configuration.configure(HIBERNATE_CONFIG_FILE);
//创建Session会话工厂
sessionFactory=configuration.buildSessionFactory();
} catch (Exception e) {
e.printStackTrace();
}
}
public static Session openSession() {
Session session = threadLocal.get();
if(null==session) {
session=sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
public static void closeSession() {
Session session = threadLocal.get();
if(null!=session) {
if(session.isOpen())
session.close();
threadLocal.set(null);
}
}
public static void main(String[] args) {
Session session = SessionFactoryUtils.openSession();
System.out.println("Session状态:"+session.isOpen());
System.out.println("Session会话已打开");
SessionFactoryUtils.closeSession();
System.out.println("Session会话已关闭");
}
}
第二步
两个实体类
Order
package com.solar.entity;
import java.io.Serializable;
import java.util.HashSet;
/**
* 数据库订单表的实体类
* @author SOLAR
*2020年8月14日08:39:18
*/
import java.util.Set;
public class Order implements Serializable{
private Integer orderId;
private String orderNo;
//建立实体类之间的关联关系(一对多所以使用集合来存储)
private Set<OrderItem> items=new HashSet<OrderItem>();
public Set<OrderItem> getItems() {
return items;
}
public void setItems(Set<OrderItem> items) {
this.items = items;
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public Order() {}
public Order(Integer orderId, String orderNo) {
super();
this.orderId = orderId;
this.orderNo = orderNo;
}
public Order(Integer orderId, String orderNo, Set<OrderItem> items) {
super();
this.orderId = orderId;
this.orderNo = orderNo;
this.items = items;
}
@Override
public String toString() {
return "Order [orderId=" + orderId + ", orderNo=" + orderNo + ", items=" + items + "]";
}
}
OrderItem
package com.solar.entity;
import java.io.Serializable;
public class OrderItem implements Serializable {
private Integer orderItemId;
private Integer productId;
private Integer quantity;
private Integer oid;
private Order order;
public Integer getOrderItemId() {
return orderItemId;
}
public void setOrderItemId(Integer orderItemId) {
this.orderItemId = orderItemId;
}
public Integer getProductId() {
return productId;
}
public void setProductId(Integer productId) {
this.productId = productId;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
public Integer getOid() {
return oid;
}
public void setOid(Integer oid) {
this.oid = oid;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
@Override
public String toString() {
return "OrderItem [orderItemId=" + orderItemId + ", productId=" + productId + ", quantity=" + quantity
+ ", oid=" + oid + ", order=" + order + "]";
}
}
第三步
配置hibernate核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- 数据库相关配置 -->
<!-- 连接账户名称 -->
<property name="connection.username">root</property>
<!-- 连接密码 -->
<property name="connection.password"></property>
<!-- 连接的绝对路径 -->
<property name="connection.url">
jdbc:mysql://localhost/peach?useUnicode=true&characterEncoding=UTF-8&userSSL=false
</property>
<!-- 驱动的绝对路径 -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- 数据库方言-->
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<!-- 调试相关配置 -->
<!-- hibernate运行过程是否展示自动生成的代码 -->
<property name="show_sql">true</property>
<!-- 是否规范化输出sql代码 -->
<property name="format">true</property>
<!-- 实体映射相关配置 -->
<mapping resource="com/solar/entity/Order.hbm.xml"/>
<mapping resource="com/solar/entity/OrderItem.hbm.xml"/>
</session-factory>
</hibernate-configuration>
第四步
配置两个实体类相对的映射文件
Order.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--
name:实体类的全路径名
table:实体类对应的数据库表名称
-->
<class name="com.solar.entity.Order" table="t_order_hb">
<!-- id:用于设置数据库结构中主键列的生成方式
name:实体类中属性名称
type:java中的数据类型
colunm:数据库表字段名称
-->
<id name="orderId" type="java.lang.Integer" column="order_id">
<generator class="increment"></generator>
</id>
<property name="orderNo" type="java.lang.String" column="order_no"></property>
<!-- 建立映射的关联关系 (尽量不用)-->
<!-- name:当前映射文件实体类的集合属性名
cascade:标明级联操作
inverse:是否执行级联操作
-->
<set name="items" cascade="save-update" inverse="true" >
<!-- colnum:指向用什么字段关联从表 -->
<key column="oid"></key>
<!-- class:从表的实体类全路径名 -->
<one-to-many class="com.solar.entity.OrderItem"/>
</set>
</class>
</hibernate-mapping>
OrderItem.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--
name:实体类的全路径名
table:实体类对应的数据库表名称
-->
<class name="com.solar.entity.OrderItem" table="t_order_item_hb">
<!-- id:用于设置数据库结构中主键列的生成方式
name:实体类中属性名称
type:java中的数据类型
colunm:数据库表字段名称
-->
<id name="orderItemId" type="java.lang.Integer" column="order_item_id">
<generator class="increment"></generator>
</id>
<property name="productId" type="java.lang.Integer" column="product_id"></property>
<property name="quantity" type="java.lang.Integer" column="quantity"></property>
<property insert="false" update="false" name="oid" type="java.lang.Integer" column="oid"></property>
<!-- 建立关联关系 -->
<many-to-one name="order"
cascade="save-update"
column="oid"
class="com.solar.entity.Order">
</many-to-one>
</class>
</hibernate-mapping>
第五步
测试dao方法是否成功运行
package com.solar.dao;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.solar.entity.Order;
import com.solar.entity.OrderItem;
public class OrderDaoTest {
Order order=null;
OrderItem orderItem=null;
OrderDao od=new OrderDao();
@Before
public void setUp() throws Exception {
order=new Order();
}
@Test
public void testAddOrder() {
order.setOrderNo("p20200724");
for (int i = 0; i < 3; i++) {
orderItem=new OrderItem();
orderItem.setProductId(i+1);
orderItem.setQuantity(i+2);
orderItem.setOrder(order);
order.getItems().add(orderItem);
}
od.addOrder(order);
}
}
效果展示
控制台显示
数据库
根据上面填的数据可以看到数据库被增加了数据
订单表(t_order_hb)
订单项表(t_order_item_hb)
订单的id是2
所有这里订单项对应的三条数据的oid都是2
一般级联项目在真实项目中是不用的
多对多实例
映射多对多关联关系(看作两个一对多)
多对多关系一定要定义一个主控方
多对多删除需要主控方直接删除
然后被控方先通过主控方解除多对多关系
,再删除被控方
禁用级联删除
下面的案例是一本书对应多个类别,一个类别对应多本书的之间的映射关系
首先
使用到的数据库脚本
-- 书本类别表
create table t_category_hb
(
category_id int primary key auto_increment,
category_name varchar(50) not null
);
-- 书本表
create table t_book_hb
(
book_id int primary key auto_increment,
book_name varchar(50) not null,
price float not null
);
-- 桥接表
-- 定义三个列,其实只要两个列
-- 一个类别对应多本书,一本书对应多个类别
CREATE TABLE t_book_category_hb
(
bcid INT PRIMARY KEY AUTO_INCREMENT,
bid INT NOT NULL,
cid INT NOT NULL,
FOREIGN KEY(bid) REFERENCES t_book_hb(book_id),
FOREIGN KEY(cid) REFERENCES t_category_hb(category_id)
);
插入数据
insert into t_book_hb(book_id, book_name, price) values(1,'西游记',50);
insert into t_book_hb(book_id, book_name, price) values(2,'红楼梦',50);
insert into t_book_hb(book_id, book_name, price) values(3,'水浒',50);
insert into t_book_hb(book_id, book_name, price) values(4,'三国演义',50);
insert into t_category_hb(category_id, category_name) values(1,'古典');
insert into t_category_hb(category_id, category_name) values(2,'神话');
insert into t_category_hb(category_id, category_name) values(3,'历史');
insert into t_book_category_hb(bid, cid) values(1,1);
insert into t_book_category_hb(bid, cid) values(1,2);
insert into t_book_category_hb(bid, cid) values(2,1);
insert into t_book_category_hb(bid, cid) values(3,1);
insert into t_book_category_hb(bid, cid) values(3,3);
insert into t_book_category_hb(bid, cid) values(4,1);
insert into t_book_category_hb(bid, cid) values(4,3);
数据库表效果
实体类
Book
package com.solar.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Book implements Serializable{
private Integer bookId;
private String bookName;
private Float price;
Set<Category> categories=new HashSet<Category>();
public Set<Category> getCategories() {
return categories;
}
public void setCategories(Set<Category> categories) {
this.categories = categories;
}
public Integer getBookId() {
return bookId;
}
public void setBookId(Integer bookId) {
this.bookId = bookId;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public Book() {
}
public Book(Integer bookId, String bookName, Float price) {
this.bookId = bookId;
this.bookName = bookName;
this.price = price;
}
@Override
public String toString() {
return "Book [bookId=" + bookId + ", bookName=" + bookName + ", price=" + price + ", categories=" + categories
+ "]";
}
}
Category
package com.solar.entity;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Category implements Serializable {
private Integer categoryId;
private String categoryName;
Set<Book> books=new HashSet<Book>();
public Set<Book> getBooks() {
return books;
}
public void setBooks(Set<Book> books) {
this.books = books;
}
public Integer getCategoryId() {
return categoryId;
}
public void setCategoryId(Integer categoryId) {
this.categoryId = categoryId;
}
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
public Category() {
}
public Category(Integer categoryId, String categoryName) {
this.categoryId = categoryId;
this.categoryName = categoryName;
}
@Override
public String toString() {
return "Category [categoryId=" + categoryId + ", categoryName=" + categoryName + ", books=" + books + "]";
}
}
对应的映射文件
Book.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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.solar.entity.Book" table="t_book_hb">
<id name="bookId" type="java.lang.Integer" column="book_id">
<generator class="increment"></generator>
</id>
<property name="bookName" type="java.lang.String" column="book_name"></property>
<property name="price" type="java.lang.Float" column="price"></property>
<!-- 多对多映射关系 -->
<!--
name:一方包含多方的属性对象名称 指向多方
cascade:级联操作 save-update/none/all=delete+save-update
inverse:是否是主控方 false表示对方不是主控方
true表示对方是主控方 由对方来维护中间表
table:表示中间表的名称
-->
<set name="categories"
cascade="save-update"
inverse="false"
table="t_book_category_hb"
>
<!--column:指向己方在中间表的外键字段 -->
<key column="bid"></key>
<!-- class:对方实例的完整路径
column:对方在中间表中的外键字段
-->
<many-to-many
class="com.solar.entity.Category"
column="cid">
</many-to-many>
</set>
</class>
</hibernate-mapping>
Category.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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.solar.entity.Category" table="t_category_hb">
<id name="categoryId" type="java.lang.Integer" column="category_id">
<generator class="increment"></generator>
</id>
<property name="categoryName" type="java.lang.String" column="category_name"></property>
<set name="books"
cascade="save-update"
inverse="true"
table="t_book_category_hb">
<key column="cid"></key>
<many-to-many
class="com.solar.entity.Book"
column="bid">
</many-to-many>
</set>
</class>
</hibernate-mapping>
dao方法
BookDao
package com.solar.dao;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.solar.entity.Book;
import com.solar.util.SessionFactoryUtils;
/**
* 书籍的dao方法
* @author Administrator
*
*/
public class BookDao {
public void addBook(Book book) {
Session session = SessionFactoryUtils.openSession();
Transaction ts = session.beginTransaction();
session.save(book);
ts.commit();
SessionFactoryUtils.closeSession();
}
}
CategoryDao
package com.solar.dao;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.solar.entity.Category;
import com.solar.util.SessionFactoryUtils;
/**
* Category的dao方法
* @author solar
*
*/
public class CategoryDao {
public Category getCategoryById(Category category) {
Session session = SessionFactoryUtils.openSession();
Transaction ts = session.beginTransaction();
//根据对象和id获取
Category c = session.get(Category.class,category.getCategoryId());
ts.commit();
SessionFactoryUtils.closeSession();
return c;//返回查询后的结果集
}
}
测试dao方法
BookDao测试
package com.solar.dao;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import com.solar.entity.Book;
import com.solar.entity.Category;
public class BookDaoTest {
BookDao bookDao=new BookDao();
Book book=null;
@Before
public void setUp() throws Exception {
book=new Book();
}
@Test
public void testAddBook() {
book.setBookName("格林童话");
book.setPrice(100f);
Category category=new Category();
category.setCategoryName("童话");
Category category1=new Category();
category1.setCategoryName("散文");
book.getCategories().add(category);
book.getCategories().add(category1);
category.getBooks().add(book);
category1.getBooks().add(book);
bookDao.addBook(book);
}
}
CategoryDao测试
package com.solar.dao;
import com.solar.entity.Book;
import com.solar.entity.Category;
import junit.framework.TestCase;
public class CategoryDaoTest extends TestCase {
CategoryDao categoryDao=null;
BookDao bookDao=new BookDao();
protected void setUp() throws Exception {
categoryDao=new CategoryDao();
}
public void testGetCategoryById() {
Book book=new Book();
book.setBookName("猫和老鼠");
book.setPrice(100f);
Category category=new Category();
category.setCategoryId(2);
Category c = categoryDao.getCategoryById(category);
book.getCategories().add(c);
bookDao.addBook(book);
}
}