目录
1. 数据库表与表之间的关系 1.1 一对多关系1.2 多对多关系1.3 一对一关系【了解】2. Hibernate的一对多关联映射 2.1 创建一个项目,引入相关jar包2.2. 创建数据库和表2.3 创建实体2.4 创建映射文件2.5 创建核心配置文件2.6 引入工具类和日志2.7 编写测试2.8 一对多的级联操作 2.8.1 级联保存或级联删除2.8.2 级联删除2.8.3 inverse的配置3. Hibernate的多对多关联映射 3.1 HIbernate多对多的关系的配置 3.1.1 创建表3.1.2 创建实体3.1.3 创建映射3.1.4 编写测试类3.2 Hibernate的多对多的操作 3.2.1 只保存一边是否可以3.2.2 级联保存或更新3.2.3 级联删除【基本不用】3.2.4 其他操作什么样的关系属于一对多?
一个部门对应多个员工,一个员工只能属于某一个部门一个客户对应多个联系人,一个联系人只能属于某一个客户一对多的建表原则:在多的一方创建外键指向一的一方的主键
什么样的关系属于多对多?
一个学生可以选择多门课程,一门课程可以被多个学生选择一个用户可以选择多个角色,一个角色可以被多个用户选择多对多的建表原则:多对多建原则:创建一个中间表,中间表至少有两个字段分别作为外键指向多对多双方的主键。
创建数据库,新建两张表
customer表crm_cst_customer.sql
CREATE TABLE `cst_customer` ( `cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)', `cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)', `cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源', `cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业', `cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别', `cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话', `cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话', PRIMARY KEY (`cust_id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;LinkMan表crm_cst_linkman.sql
CREATE TABLE `cst_linkman` ( `lkm_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)', `lkm_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名', `lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id', `lkm_gender` char(1) DEFAULT NULL COMMENT '联系人性别', `lkm_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话', `lkm_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机', `lkm_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱', `lkm_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq', `lkm_position` varchar(16) DEFAULT NULL COMMENT '联系人职位', `lkm_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注', PRIMARY KEY (`lkm_id`), KEY `FK_cst_linkman_lkm_cust_id` (`lkm_cust_id`), CONSTRAINT `FK_cst_linkman_lkm_cust_id` FOREIGN KEY (`lkm_cust_id`) REFERENCES `cst_customer` (`cust_id`) ON DELETE NO ACTION ON UPDATE NO ACTION ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;两个表之间的关系
有几个实体就需要几个映射文件
Customer.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.itzhouq.hibernate.domain.Customer" table="cst_customer"> <!-- 建立OID与主键映射 --> <id name="cust_id" column="cust_id"> <generator class="native"></generator> </id> <!-- 建立普通属性和数据库字段映射 --> <property name="cust_name" column="cust_name"></property> <property name="cust_source" column="cust_source"></property> <property name="cust_industry" column="cust_industry"></property> <property name="cust_level" column="cust_level"></property> <property name="cust_phone" column="cust_phone"></property> <property name="cust_mobile" column="cust_mobile"></property> <!-- 配置一对多的映射:放置的多的一方的集合 --> <!-- set标签: * name:多的一方的对象集合的属性名称 --> <set name="linkMans"> <!-- column多的一方的外键的名称 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的类的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set> </class> </hibernate-mapping>LinkMan.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.itzhouq.hibernate.domain.LinkMan" table="cst_linkman"> <!-- 建立OID与主键映射 --> <id name="lkm_id" column="lkm_id"> <generator class="native"></generator> </id> <!-- 建立普通属性与表字段映射 --> <property name="lkm_name"/> <property name="lkm_gender"/> <property name="lkm_phone"/> <property name="lkm_mobile"/> <property name="lkm_email"/> <property name="lkm_qq"/> <property name="lkm_position"/> <property name="lkm_memo"/> <!-- 配置多对一的关系:放置的是一的一方的对象 --> <!-- many-to-one标签 * name:一的一方的对象的属性名称 *class:一的一方的类的全限定名 column:在多的一方的表的外键的名称 --> <many-to-one name="customer" class="com.itzhouq.hibernate.domain.Customer" column="lkm_cust_id"/> </class> </hibernate-mapping>保存客户,级联联系人
操作的主体是客户对象,需要在Customer.hbm.xml中进行配置<!-- set标签: * name:多的一方的对象集合的属性名称 * cascade:级联 --> <set name="linkMans" cascade="save-update"> <!-- column多的一方的外键的名称 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的类的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set> @Test /** * 级联保存或更新操作 * 保存客户级联联系人,操作的主体是客户对象,需要在Customer.hbm.xml中进行配置 */ public void test2() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("赵红"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("如花"); customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); session.save(customer); transaction.commit(); }保存联系人,级联客户
操作的主体是联系人对象,需要在LinkMan.hbm.xml中进行配置
<many-to-one name="customer" cascade="save-update" class="com.itzhouq.hibernate.domain.Customer" column="lkm_cust_id"/> @Test /** * 级联保存或更新操作 * 保存客户级联联系人,操作的主体是客户对象,需要在LinkMan.hbm.xml中进行配置 */ public void test2() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("赵斌"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("思域"); customer.getLinkMans().add(linkMan); linkMan.setCustomer(customer); session.save(linkMan); transaction.commit(); }测试对象导航
@Test /** * 测试对象的导航 * 前提:一对多的双方都设置cascade="save-update" */ public void test3() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("赵斌"); LinkMan linkMan1 = new LinkMan(); linkMan1.setLkm_name("凤姐"); LinkMan linkMan2 = new LinkMan(); linkMan2.setLkm_name("如花"); LinkMan linkMan3 = new LinkMan(); linkMan3.setLkm_name("芙蓉"); linkMan1.setCustomer(customer); customer.getLinkMans().add(linkMan2); customer.getLinkMans().add(linkMan3); // 双方都设置了cascade //session.save(linkMan1); // 发送几条insert语句 4条 //session.save(customer); // 发送几条insert语句 3条 session.save(linkMan2); // 发送几条insert语句 1条 transaction.commit(); }级联删除:级联删除一遍的时候,同时将另一方的数据也一并删除
删除客户的时候级联删除联系人
删除的主体是客户,需要在Custoemr.hbm.xml中配置
<set name="linkMans" cascade="save-update,delete"> <!-- column多的一方的外键的名称 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的类的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set> @Test /** * 级联删除 * 删除客户级联删除联系人,删除的主体是客户,需要在Custoemr.hbm.xml中配置 */ public void test4() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 没有设置级联,默认情况:修改联系人的外键,删除客户 //Customer customer = session.get(Customer.class, 1L); //session.delete(customer); // 删除客户,同时删除联系人 <set name="linkMans" cascade="save-update,delete"> Customer customer = session.get(Customer.class, 1L); session.delete(customer); transaction.commit(); }删除联系人级联删除客户(基本不用)
一对多设置了双向关联会产生多余的SQL语句
@Test /** * 将2号联系人原来归1号联系人,现在改为2号客户 */ public void test5() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 查询2号联系人 LinkMan linkMan = session.get(LinkMan.class, 2L); //查询2号客户 Customer customer = session.get(Customer.class, 2L); //双向的关联 linkMan.setCustomer(customer); customer.getLinkMans().add(linkMan); //发送了两次update语句,对外键修改了两次 //持久态对象自动更新 transaction.commit(); }分析
解决多余的SQL语句
单向维护使一方放弃外键维护权:一的一方放弃。在配置文件Customer.hbm.xml中的set上配置inverse="true"区分cascade和inverse
cascade是操作关联对象的,比如客户存到数据库了,客户关联的联系人也会存到数据库
但是有没有外键是由inverse控制的
@Test /** * 区分cascade和inverse的区别 */ public void test6() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setCust_name("李斌"); LinkMan linkMan = new LinkMan(); linkMan.setLkm_name("凤姐"); customer.getLinkMans().add(linkMan); //条件在Customer.hbm.xml上的set中配置了cascade="save-update" inverse="true" session.save(customer); // 客户回插入到数据库,联系人也会插入到数据库,但是外键为null transaction.commit(); }Customer.hbm.xml相关配置
<!-- set标签: * name:多的一方的对象集合的属性名称 * cascade:级联 * inverse: 是否放弃外键约束,true表示放弃外键约束 --> <set name="linkMans" cascade="save-update,delete" inverse="true"> <!-- column多的一方的外键的名称 --> <key column="lkm_cust_id"></key> <!-- class:多的一方的类的全限定名 --> <one-to-many class="com.itzhouq.hibernate.domain.LinkMan"/> </set>在主配置文件中引入User.hbm.xml和Role.hbm.xml
<!-- 配置映射文件 --> <mapping resource="com/itzhouq/hibernate/domain/User.hbm.xml"/> <mapping resource="com/itzhouq/hibernate/domain/Role.hbm.xml"/>测试类
package com.itzhouq.hibernate.demo2; import org.hibernate.Session; import org.hibernate.Transaction; import org.junit.Test; import com.itzhouq.hibernate.domain.Role; import com.itzhouq.hibernate.domain.User; import com.itzhouq.hibernate.utils.HibernateUtils; /** * Hibernate的多对多的映射 * @author itzhouq * */ public class Demo2 { @Test /* * 保存多条记录:保存多个用户和角色 */ public void test() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 创建2个用户 User user1 = new User(); user1.setUser_name("赵洪"); User user2 = new User(); user2.setUser_name("李兵"); // 2. 创建3个角色 Role role1 = new Role(); role1.setRole_name("研发部"); Role role2 = new Role(); role2.setRole_name("市场部"); Role role3 = new Role(); role3.setRole_name("公关部"); // 3. 设置双向的关联关系 user1.getRoles().add(role1); user1.getRoles().add(role2); user2.getRoles().add(role2); user2.getRoles().add(role3); role1.getUsers().add(user1); role2.getUsers().add(user1); role2.getUsers().add(user2); role3.getUsers().add(user2); // 4. 保存操作:多对多建立了双向的关系必须有一方放弃外键维护 // 5. 一般是被动方放弃外键维护 角色是被动方 ,需要在Role.hbm.xml文件中配置inverse=true // 比如,学生选课,课程是被选择的,所以课程一方放弃外键维护,需要在课程的映射文件中配置inverse=true session.save(user1); session.save(user2); session.save(role1); session.save(role2); session.save(role3); transaction.commit(); } }Role.hbm.xml文件中配置
<!--inverse="true",Role一方放弃了外键的维护权 --> <set name="users" table="sys_user_role" inverse="true"> <key column="role_id"/> <many-to-many class="com.itzhouq.hibernate.domain.User" column="user_id"/> </set>给用户选择角色
@Test /* * 给用户选择角色 */ public void test4() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 给1号用户多选3号角色 // 2. 查询1号用户 User user = session.get(User.class, 1L); // 3. 查询3号角色 Role role = session.get(Role.class, 3L); // 4. 选择角色 user.getRoles().add(role); transaction.commit(); } 注意修改前需要设置主配置文件的<property name="hibernate.hbm2ddl.auto">update</property>给用户改选角色
@Test /* * 给用户改选角色 */ public void test5() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 将2号用户原有的3号角色改为2号角色 // 2. 查询2号用户 User user = session.get(User.class, 2L); // 3. 查询3号角色 Role role3 = session.get(Role.class, 3L); // 4. 查询2号角色 Role role2 = session.get(Role.class, 2L); // 5. 改选角色 user.getRoles().remove(role3); user.getRoles().add(role2); transaction.commit(); }给用户删除角色
@Test /* * 给用户删除角色 */ public void test6() { Session session = HibernateUtils.getCurrentSession(); Transaction transaction = session.beginTransaction(); // 1. 将2号用户的1号角色删除 // 2. 查询2号用户 User user = session.get(User.class, 2L); // 3. 查询1号角色 Role role = session.get(Role.class, 1L); // 4. 删除角色 user.getRoles().remove(role); transaction.commit(); }转载于:https://www.cnblogs.com/itzhouq/p/hibernate3.html