网站转化率分析工具,做网站选择什么相机,server 2008 iis 部署网站,wordpress 屏蔽升级Hibernate 的一对多关联映射 之前在学习 Hibernate 的时候#xff0c;其实都是单表的操作。在实际的开发当中#xff0c;比如做一个商城#xff0c;就需要好多张数据库表#xff0c;表与表之间是有关系的。之前些做一些关联查询或者是一些基本的查询操作的时候#xff0c;…Hibernate 的一对多关联映射 之前在学习 Hibernate 的时候其实都是单表的操作。在实际的开发当中比如做一个商城就需要好多张数据库表表与表之间是有关系的。之前些做一些关联查询或者是一些基本的查询操作的时候都是写 SQL 语句去关联两张表这样子稍微有一点麻烦。那么有了 Hibernate 之后它就可以解决这类问题了。在这之前先了解一些数据库 表之间的关系它是有三种关系的。 1、数据库表与表之间的关系 也就是说我们的一个系统抽取出来的那些实体因为表是根据实体来的 那么它会根据实体分成 这三类的关系。也就是说你所有的系统里边所有抽取出来的实体也只有这三种关系。 ① 一对多的关系 什么关系属于一对多 一个部门对于多个员工一个员工只能属于一个部门。 一个客户可以对应多个联系人一个联系人只能属于某一个客户个人认为是错误的。 一对多的创表原则 ② 多对多的关系 什么样的关系属于多对多 一个学生可以选择多门课程一门课程也可以被多个学生选择。 一个用户可以选择多个角色一个角色也可以被多个用户选择。 多对多建表原则 ③ 一对一的关系了解实际开发过程中应用很少 在实际开发过程中一对一的关系可以建成一张表除非 是有特殊的需求需要将表分开。 唯一外键对应 在一张表添加外键字段并作唯一约束。 主键对应 需要将两张表关联。 一对多怎么表示一个客户应该有多个联系人一个联系人只能属于一个客户。 现在要通过 ORM 的方式表示一个联系人只能属于某一个客户。开发语言是面向对象的 怎么表示一个联系人属于一个客户呢放置一个客户的对象所有以后创表的时候会创建外键但是创建实体的时候要放的是“一”的一方的一个对象。所以以后碰到外键的时候不要写外键的名称了把外键改成“一”的一个对象并生成相应的get set。 还是通过 ORM 的方式表示 一个客户对应多个联系人。放置的是“多”的一方的集合。需要注意的是hibernate 默认使用的是 set 集合不是 list 集合。当然它里面也可以配置 list/maplist 集合应为在 hibernate 中需要对 list 数据进行有序排列。如果配置 list 集合hibernate 需要在数据库表中多建一列这一列就是用于 hibernate 排序的它会用0、1、2、3、4、5...列这个顺序那么表会多出来一列。所以一般是使用的都是 set 集合。 现在做的是双向关联就是从客户这边查联系人可以查从联系人这边查客户也可以查。如果只做了单向关联只在联系人那边放客户对象了客户这边没有放联系人的集合那你在查询的时候只能从联系人查到客户就不能从客户查联系人了。当然两边都做好了想从那边去查都没问题也可以做出单项的。 Hibernate 的一对多关联映射 一、Hibernate 的一对多关联映射 1、创建一个项目引入相应 jar 包 2、创建数据库和表 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)
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8;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) DEFAULT 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
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8; 在 MySQL 数据库中将两张表拖拽到“架构设计器”选项卡就可以看到两张表之间的关系。 3、创建实体 ① “一”的一方的实体 ② “多的一方的实体” 4、创建映射文件 ① 多的一方的映射的创建联系人表的 hibernate 配置文件 LinkMan.hbm.xml ?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-mapping PUBLIC -//Hibernate/Hibernate Mapping DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd
hibernate-mappingclass namecom.itheima.hibernate.domain.LinkMan tablecst_linkman!-- 建立OID与主键映射 --id namelkm_id columnlkm_idgenerator classnative//id!-- 建立普通属性与表字段映射 --property namelkm_name/property namelkm_gender/property namelkm_phone/property namelkm_mobile/property namelkm_email/property namelkm_qq/property namelkm_position/property namelkm_memo/!-- 配置多对一的关系放置的是一的一方的对象 --!-- many-to-one标签* name :一的一方的对象的属性名称。* class :一的一方的类的全路径。* column :在多的一方的表的外键的名称。 操作 column 就相当与操作数据库中表的外键--many-to-one namecustomer classcom.itheima.hibernate.domain.Customer columnlkm_cust_id//class
/hibernate-mapping ② “一”的一方的映射的创建客户表的 hibernate 配置文件 Customer.hbm.xml ?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-mapping PUBLIC -//Hibernate/Hibernate Mapping DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd
hibernate-mappingclass namecom.itheima.hibernate.domain.Customer tablecst_customer!-- 建立OID与主键映射 --id namecust_id columncust_idgenerator classnative//id!-- 建立普通属性与数据库表字段映射 --property namecust_name columncust_name /property namecust_source columncust_source/property namecust_industry columncust_industry/property namecust_level columncust_level/property namecust_phone columncust_phone/property namecust_mobile columncust_mobile/!-- 配置一对多的映射放置的多的一方的集合 --!-- set标签 * name 多的一方的对象集合的属性名称。* cascade级联* inverse放弃外键维护权。--set namelinkMans!--key标签* column多的一方的外键的名称。--key columnlkm_cust_id/!-- one-to-many标签* class :多的一方的类的全路径--one-to-many classcom.itheima.hibernate.domain.LinkMan//set/class
/hibernate-mapping 5、创建核心配置文件hibernate.cfg.xml 将要连接的数据库名称改一下还有要引入的映射文件这里要引入两个映射文件。 ?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-configuration PUBLIC-//Hibernate/Hibernate Configuration DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd
hibernate-configurationsession-factory!-- 连接数据库的基本参数 --property namehibernate.connection.driver_classcom.mysql.jdbc.Driver/propertyproperty namehibernate.connection.urljdbc:mysql:///hibernate_day03/propertyproperty namehibernate.connection.usernameroot/propertyproperty namehibernate.connection.passwordabc/property!-- 配置Hibernate的方言 --property namehibernate.dialectorg.hibernate.dialect.MySQLDialect/property!-- 可选配置 --!-- 打印SQL --property namehibernate.show_sqltrue/property!-- 格式化SQL --property namehibernate.format_sqltrue/property!-- 自动创建表 --property namehibernate.hbm2ddl.autoupdate/property!-- 配置C3P0连接池 --property nameconnection.provider_classorg.hibernate.connection.C3P0ConnectionProvider/property!--在连接池中可用的数据库连接的最少数目 --property namec3p0.min_size5/property!--在连接池中所有数据库连接的最大数目 --property namec3p0.max_size20/property!--设定数据库连接的过期时间,以秒为单位,如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 --property namec3p0.timeout120/property!--每3000秒检查所有连接池中的空闲连接 以秒为单位--property namec3p0.idle_test_period3000/property!-- 设置事务隔离级别 --property namehibernate.connection.isolation4/property!-- 配置当前线程绑定的Session --property namehibernate.current_session_context_classthread/property!-- 引入映射 --!-- mapping resourcecom/itheima/hibernate/domain/Customer.hbm.xml/mapping resourcecom/itheima/hibernate/domain/LinkMan.hbm.xml/ --mapping resourcecom/itheima/hibernate/domain/User.hbm.xml/mapping resourcecom/itheima/hibernate/domain/Role.hbm.xml//session-factory
/hibernate-configuration 7、创建测试类 package com.itheima.hibernate.demo1;import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;import com.itheima.hibernate.domain.Customer;
import com.itheima.hibernate.domain.LinkMan;
import com.itheima.hibernate.utils.HibernateUtils;/*** 一对多的测试类* author jt**/
public class HibernateDemo1 {Test// 保存2个客户 和 3个联系人 并且建立好关系public void demo1(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 创建两个客户Customer customer1 new Customer();customer1.setCust_name(王东);Customer customer2 new Customer();customer2.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(customer1);linkMan2.setCustomer(customer1);linkMan3.setCustomer(customer2);customer1.getLinkMans().add(linkMan1);customer1.getLinkMans().add(linkMan2);customer2.getLinkMans().add(linkMan3);// 保存数据:session.save(linkMan1);session.save(linkMan2);session.save(linkMan3);session.save(customer1);session.save(customer2);tx.commit();}
Test/*** 区分cascade和inverse的区别*/public void demo9(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();Customer customer new Customer();customer.setCust_name(李兵);LinkMan linkMan new LinkMan();linkMan.setLkm_name(凤姐);customer.getLinkMans().add(linkMan);// 条件在Customer.hbm.xml上的set中配置了cascadesave-update inversetruesession.save(customer); // 客户会插入到数据库联系人也会插入到数据库但是外键为nulltx.commit();}
} 二、Hibernate 的一对多相关操作 1、一对多关系只保存一边是否可行 将数据做了双向关连以后是否可以 只保存一边的 数据呢不可以回报一个瞬时对象异常的错误。什么是瞬时对象异常啊就是说持久态的对象关联了一个瞬时态的对象。客户对象本来是瞬时态的对象 一保存就变成持久态的对象了之前和联系人对象做了关联但联系人对象 还是瞬时态的对象所以会报错。 Test// 一对多关系只保存一边是否可以public void demo2(){Session session HibernateUtils.getCurrentSession();Transaction tx 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);session.save(linkMan);tx.commit();} 2、一对多的级联操作 如果想只保存一边那么要通过一个配置叫做级联操作。 级联操作包含有常用的两种级联操作一种叫级联保存或更新一种叫级联删除。 什么叫做级联 级联指的是操作一个对象的时候是否会同时操作其关联的对象。 级联是有方向性 操作一的一方的时候是否操作到多的一方 操作多的一方的时候是否操作到一的一方 之前保存一边是会报异常的报的是瞬时对象异常。现在要通过配置完成一个级联操作要看你操作的主体是什么我们现在操作的主体是 客户对象需要在客户实体的映射文件中进行配置 。 ① 级联保存或更新 保存客户级联联系人保存“一”的一方级联“多”的一方 映射文件的配置 !-- set标签 * name 多的一方的对象集合的属性名称。* cascade级联* inverse放弃外键维护权。--set namelinkMans cascadesave-update 测试类 Test/*** 级联保存或更新操作* * 保存客户级联联系人操作的主体是客户对象需要在Customer.hbm.xml中进行配置* * set namelinkMans cascadesave-update*/public void demo3(){Session session HibernateUtils.getCurrentSession();Transaction tx 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);tx.commit();} 保存联系人级联客户保存“多”的一方级联“一”的一方 映射文件的配置 !-- many-to-one标签* name :一的一方的对象的属性名称。* class :一的一方的类的全路径。* column :在多的一方的表的外键的名称。操作 column 就相当与操作数据库中表的外键--many-to-one namecustomer cascadesave-update classcom.itheima.hibernate.domain.Customer columnlkm_cust_id/ 测试类 Test/*** 级联保存或更新操作* * 保存联系人级联客户操作的主体是联系人对象需要在LinkMan.hbm.xml中进行配置* * many-to-one namecustomer cascadesave-update classcom.itheima.hibernate.domain.Customer columnlkm_cust_id/*/public void demo4(){Session session HibernateUtils.getCurrentSession();Transaction tx 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);tx.commit();} 3、测试对象的导航 我们需要注意的是现在做的属于双向关联就是客户关联联系人联系人也关联了客户其实这种也叫作对象的导航。对象导航是怎么去设置的怎么往数据库中保存或更新的。 没有关联外键默认是 none。 对象的导航一定要搞清楚关联关系的设置那边配置了 cascade 对另一半的影响。 Test/*** 测试对象的导航* * 前提一对多的双方都设置cascadesave-update*/public void demo5(){Session session HibernateUtils.getCurrentSession();Transaction tx 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条 linkMAn1 custome linkMan2 linkMan2// session.save(customer); // 发送几条insert语句 3条 customer linkMan2 linkman3session.save(linkMan2); // 发送几条insert语句 1条 linkMan1tx.commit();} 5、级联删除 什么是级联删除 删除一边的同时将另一方的数据也一并删除。 在 JDBC 情况要想做级联删除除非先把要删除的那个客户“一”所关联的联系人“多”删除干净才能继续删除客户。但是 Hibernate 是可以直接级联你删除的。 Hibernate 情况将要删除的外键设置为空再删除数据只删除了一方。 Hibernate 删除数据需要先查询再删除。如果创建对象后直接删除这是对象所对应的集合还是空的先查询数据将自动添加到对象所对应的集合再删除。 删除客户级联删除联系人 Test/*** 级联删除* * 删除客户级联删除联系人删除的主体是客户需要在Customer.hbm.xml中配置 * * 多个操作之间用逗号隔开* * set namelinkMans cascadesave-update,delete*/public void demo6(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 没有设置级联删除默认情况:修改了联系人的外键删除客户/*Customer customer session.get(Customer.class, 1l);session.delete(customer);*/// 删除客户同时删除联系人Customer customer session.get(Customer.class, 1l);session.delete(customer);tx.commit();} 删除联系人级联删除客户基本不用 Test/*** 级联删除* * 删除联系人级联删除客户删除的主体是联系人需要在LinkMan.hbm.xml中配置* * many-to-one namecustomer cascadedelete*/public void demo7(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 删除客户同时删除联系人LinkMan linkMan session.get(LinkMan.class, 3l);session.delete(linkMan);tx.commit();} 6、一对多设置了双向关联产生多余的 SQL 语句 在一对多 的操作中如果设置了双向关联会产生一些多余的 SQL 语句。 怎么避免掉这个问题呢在这里举一个例子。 首先先让它重新建一下数据库表 接下来运行 demo1 的程序往数据表中插入两个客户和三个联系人让它重新建议下表。建好以后再将配置给位 update。 public void demo1(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 创建两个客户Customer customer1 new Customer();customer1.setCust_name(王东);Customer customer2 new Customer();customer2.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(customer1);linkMan2.setCustomer(customer1);linkMan3.setCustomer(customer2);customer1.getLinkMans().add(linkMan1);customer1.getLinkMans().add(linkMan2);customer2.getLinkMans().add(linkMan3);// 保存数据:session.save(linkMan1);session.save(linkMan2);session.save(linkMan3);session.save(customer1);session.save(customer2);tx.commit();} 现在可以在数据库中看到两个客户和三个联系人。 原来2号联系人属于1号客户现在要把它改成属于2号客户没有用 update 方法因为两个对象都是持久态对象发生改变会自动更新数据可库。 Test/*** 将2号联系人原来归1号客户现在改为2号客户*/public void demo8(){Session session HibernateUtils.getCurrentSession();Transaction tx 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);tx.commit();} 看发送的数据库语句数据库中已经修改成功发了两条update语句两次都修改了外键为什么会改两回呢 当你进行执行的时候Hibernate 会有一级缓存区有一块是缓存区有一块是快照区。当你执行 get 查询的时候它会将数据放到缓存区一份并对这份数据进行快照。当事务提交的时候Hibernate 会比对一级缓存区域和快照区的数据如果不一致会更新数据库。 都会进行更新外键其实只要更新一次外键就可以了所以在这里会产生多余的 SQL 语句 解决多余的 SQL语句 单向维护就用一边去做比如只让客户关联联系人或是只让联系人关联客户这么做是可以的。但是这种方法在当前条件下做是可以的但是有的地方还是不行还是会出现一些问题。 还有一种方法是使一方放弃外键维护权为什么会产生多余的 SQL就是因为现在两边都可以维护这个外键。 因为我们之需要更改一次外键就行了所以必须让一方放弃外键维护权。那么让哪一方放弃呢 一的一方放弃为什么一的一方放弃呢。因为关系的维护应当由多的一方发起让一个国家主席记住所有人的名字和所有人记住国家主席的名字。 那怎么让一的一方放弃呢就需要在一的一方的配置那在 set 集合那加上一个配置 inverse值设置为 true。 那么放弃外键的维护权在哪个地方还会用到呢一对多的查询的修改的时候现在还没有做带页面的做带页面的时候既有商品又有分类。能查出分类当你查出分类的时候点击修改分类时候会跳到一个界面有分类的名称。。然后就提交了当你提交过去以后这个集合是空的因为页面没有去提交集合当你一修改它会把这个分类下原来所有的商品的外键全都改空。这个时候就必须放弃一的一方的外键维护权。 减轻了服务器的压力少发一些 SQL 语句。 区分cascade和inverse Test/*** 区分cascade和inverse的区别*/public void demo9(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();Customer customer new Customer();customer.setCust_name(李兵);LinkMan linkMan new LinkMan();linkMan.setLkm_name(凤姐);customer.getLinkMans().add(linkMan);// 条件在Customer.hbm.xml上的set中配置了cascadesave-update inversetruesession.save(customer); // 客户会插入到数据库联系人也会插入到数据库但是外键为nulltx.commit();} 执行程序客户会插入到数据库联系人也会插入到数据库 但是外键为空。注意cascade是操作关联对象的也就是客户进去了关联对象联系热人也会进去这是由cascade控制的但是具体有没有外键是靠inverse去控制的。 Hibernate 的多对多关联映射 一、Hibernate 多对多关系的配置 多对多和一对多还有一点点的渊源为什么这么说呢其实就是因为如果你不会多对多其实你也可以建两个一对多也是可以的。 1、创建表 角色表 CREATE TABLE sys_user (user_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT 用户id,user_code varchar(32) NOT NULL COMMENT 用户账号,user_name varchar(64) NOT NULL COMMENT 用户名称,user_password varchar(32) NOT NULL COMMENT 用户密码,user_state char(1) NOT NULL COMMENT 1:正常,0:暂停,PRIMARY KEY (user_id)
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8; 用户表 CREATE TABLE sys_role (role_id bigint(32) NOT NULL AUTO_INCREMENT,role_name varchar(32) NOT NULL COMMENT 角色名称,role_memo varchar(128) DEFAULT NULL COMMENT 备注,PRIMARY KEY (role_id)
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8; 现在有了用户表和角色表一个客户可以选择多个角色多对多关系所以还需要有一张中间表。中间表就两个字段一个是角色 id一个是用户 id分别创建两个外键分别去指向角色表的主键和用户表的主键。 中间表 CREATE TABLE sys_user_role (role_id bigint(32) NOT NULL COMMENT 角色id,user_id bigint(32) NOT NULL COMMENT 用户id,PRIMARY KEY (role_id,user_id),KEY FK_user_role_user_id (user_id),CONSTRAINT FK_user_role_role_id FOREIGN KEY (role_id) REFERENCES sys_role (role_id) ON DELETE NO ACTION ON UPDATE NO ACTION,CONSTRAINT FK_user_role_user_id FOREIGN KEY (user_id) REFERENCES sys_user (user_id) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINEInnoDB DEFAULT CHARSETutf8; 2、创建实体 用户的实体 package com.itheima.hibernate.domain;import java.util.HashSet;
import java.util.Set;/*** 用户的实体* author jt*CREATE TABLE sys_user (user_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT 用户id,user_code varchar(32) NOT NULL COMMENT 用户账号,user_name varchar(64) NOT NULL COMMENT 用户名称,user_password varchar(32) NOT NULL COMMENT 用户密码,user_state char(1) NOT NULL COMMENT 1:正常,0:暂停,PRIMARY KEY (user_id)
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8;*/
public class User {private Long user_id;private String user_code;private String user_name;private String user_password;private String user_state;// 设置多对多关系表示一个用户选择多个角色// 放置的是角色的集合private SetRole roles new HashSetRole();// 生成相应的get、setpublic Long getUser_id() {return user_id;}public void setUser_id(Long user_id) {this.user_id user_id;}public String getUser_code() {return user_code;}public void setUser_code(String user_code) {this.user_code user_code;}public String getUser_name() {return user_name;}public void setUser_name(String user_name) {this.user_name user_name;}public String getUser_password() {return user_password;}public void setUser_password(String user_password) {this.user_password user_password;}public String getUser_state() {return user_state;}public void setUser_state(String user_state) {this.user_state user_state;}public SetRole getRoles() {return roles;}public void setRoles(SetRole roles) {this.roles roles;}} 角色的实体 package com.itheima.hibernate.domain;import java.util.HashSet;
import java.util.Set;/*** 角色的实体* author jt*CREATE TABLE sys_role (role_id bigint(32) NOT NULL AUTO_INCREMENT,role_name varchar(32) NOT NULL COMMENT 角色名称,role_memo varchar(128) DEFAULT NULL COMMENT 备注,PRIMARY KEY (role_id)
) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8;*/
public class Role {private Long role_id;private String role_name;private String role_memo;// 一个角色被多个用户选择// 放置的是用户的集合private SetUser users new HashSetUser();public Long getRole_id() {return role_id;}public void setRole_id(Long role_id) {this.role_id role_id;}public String getRole_name() {return role_name;}public void setRole_name(String role_name) {this.role_name role_name;}public String getRole_memo() {return role_memo;}public void setRole_memo(String role_memo) {this.role_memo role_memo;}public SetUser getUsers() {return users;}public void setUsers(SetUser users) {this.users users;}} 现在实体的一些基本的属性已经建好了但是现在我们要创建的是一个多对多关系的实体。也就是一个用户可以选择多个角色那么如何去设置多对多的关系呢多对多关系设置的时候要想表示之间的关系放置的都是对方的集合。 3、创建映射 用户的映射 ?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-mapping PUBLIC -//Hibernate/Hibernate Mapping DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd
hibernate-mappingclass namecom.itheima.hibernate.domain.User tablesys_user!-- 建立OID与主键的映射 --id nameuser_id columnuser_idgenerator classnative//id!-- 建立普通属性与字段映射 --property nameuser_code columnuser_code/property nameuser_name columnuser_name/property nameuser_password columnuser_password/property nameuser_state columnuser_state/!-- 建立与角色的多对多的映射关系 --!-- set标签* name 对方的集合的属性名称。* table 多对多的关系需要使用中间表放的是中间表的名称。--set nameroles tablesys_user_role cascadesave-update,delete !-- key标签* column 当前的对象对应中间表的外键的名称。--key columnuser_id/!-- many-to-many标签* class 对方的类的全路径* column 对方的对象在中间表中的外键的名称。--many-to-many classcom.itheima.hibernate.domain.Role columnrole_id//set/class
/hibernate-mapping 角色的映射 ?xml version1.0 encodingUTF-8?
!DOCTYPE hibernate-mapping PUBLIC -//Hibernate/Hibernate Mapping DTD 3.0//ENhttp://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd
hibernate-mappingclass namecom.itheima.hibernate.domain.Role tablesys_role!-- 建立OID与主键的映射 --id namerole_id columnrole_idgenerator classnative//id!-- 建立普通属性与字段的映射 --property namerole_name columnrole_name/property namerole_memo columnrole_memo/!-- 与用户的多对多的映射关系 --!-- set标签* name 对方的集合的属性名称。* table 多对多的关系需要使用中间表放的是中间表的名称。--set nameusers tablesys_user_role cascadesave-update,delete inversetrue!-- key标签* column 当前的对象对应中间表的外键的名称。--key columnrole_id/!-- many-to-many标签* class 对方的类的全路径* column 对方的对象在中间表中的外键的名称。--many-to-many classcom.itheima.hibernate.domain.User columnuser_id//set/class
/hibernate-mapping 映射配置好以后别忘了需要把映射文件添加到核心配置里面去 。 mapping resourcecom/itheima/hibernate/domain/User.hbm.xml/mapping resourcecom/itheima/hibernate/domain/Role.hbm.xml/ 4、编写测package com.itheima.hibernate.demo2;import org.hibernate.Session;import org.hibernate.Transaction;import org.junit.Test; import com.itheima.hibernate.domain.Role;
import com.itheima.hibernate.domain.User;
import com.itheima.hibernate.utils.HibernateUtils;/*** Hibernate的多对多的映射* author jt**/
public class HibernateDemo2 {Test/*** 保存多条记录保存多个用户和角色*/public void demo1(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 创建2个用户User user1 new User();user1.setUser_name(赵洪);User user2 new User();user2.setUser_name(李兵);// 创建3个角色Role role1 new Role();role1.setRole_name(研发部);Role role2 new Role();role2.setRole_name(市场部);Role role3 new Role();role3.setRole_name(公关部);// 设置双向的关联关系: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);// 保存操作:多对多建立了双向的关系必须有一方放弃外键维护。// 一般是被动方放弃外键维护权。session.save(user1);session.save(user2);// 角色也要保存因为没有配置级联session.save(role1);session.save(role2);session.save(role3);// 这样一执行就会出错一对多也是这样设置的不会出错// 设置了双向的关联关系在一对多的时候是做了两次修改关系维护是靠多的一方的外键修改外键就可以了修改几次都没关系// 但是多对多的关系想要去维护靠的是中间表中间表关系的维护是往里面插入// 两个字段共同决定一条记录共同作为主键两个字段不能同时重复。必须有一方放弃外键维护权-// 一般是被动方放弃外键维护权像我们用户选角色角色一般是被动的所以我们需要在角色这边的配置里在set这需要添加inversetrue// 如果单向关联这种是可以的但有的时候需要双向关联双向关联的时候让一方放弃就可以了。tx.commit();}
} 多对多的操作只保存一边是否可以不可以瞬时对象异常 如果想要执行需要设置级联 Test/*** 多对多的操作* * 只保存一边是否可以不可以瞬时对象异常*/public void demo2(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 创建2个用户User user1 new User();user1.setUser_name(赵洪);// 创建3个角色Role role1 new Role();role1.setRole_name(研发部);// 设置双向的关联关系:user1.getRoles().add(role1);role1.getUsers().add(user1);// 只保存用户// session.save(user1);session.save(role1);tx.commit();} 多对多的级联保存或更新 保存那个对象外键也需要交给它来维护 Test/*** 多对多的级联保存* * 保存用户级联保存角色。在用户的映射文件中配置。* * 在User.hbm.xml中的set上配置 cascadesave-update*/public void demo3(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 创建2个用户User user1 new User();user1.setUser_name(赵洪);// 创建3个角色Role role1 new Role();role1.setRole_name(研发部);// 设置双向的关联关系:user1.getRoles().add(role1);role1.getUsers().add(user1);// 只保存用户session.save(user1);tx.commit();}/*** 多对多的级联保存* * 保存角色级联保存用户。在角色的映射文件中配置。* * 在Role.hbm.xml中的set上配置 cascadesave-update*/Testpublic void demo4(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 创建2个用户User user1 new User();user1.setUser_name(李兵);// 创建3个角色Role role1 new Role();role1.setRole_name(公关部);// 设置双向的关联关系:user1.getRoles().add(role1);role1.getUsers().add(user1);// 只保存用户session.save(role1);tx.commit();} 多对多的级联删除基本用不上 /*** 多对多的级联删除* * 删除用户级联删除角色* * 在User.hbm.xml中的set上配置 cascadedelete*/Testpublic void demo5(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 查询1号用户:User user session.get(User.class, 1l);session.delete(user);tx.commit();}/*** 多对多的级联删除* * 删除角色级联删除用户* * 在Role.hbm.xml中的set上配置 cascadedelete*/Testpublic void demo6(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 查询2号角色:Role role session.get(Role.class, 2l);session.delete(role);tx.commit();} 给用户选择角色或给用户改选角色或是给用户删除角色。 Test/*** 给用户选择角色*/public void demo7(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 给1号用户多选2号角色// 查询1号用户User user session.get(User.class, 1l);// 查询2号角色Role role session.get(Role.class, 2l);user.getRoles().add(role);tx.commit();}Test/*** 给用户改选角色*/public void demo8(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 给2号用户将原有的2号角色改为3号角色// 查询2号用户User user session.get(User.class, 2l);// 查询2号角色Role role2 session.get(Role.class, 2l);Role role3 session.get(Role.class, 3l);user.getRoles().remove(role2);user.getRoles().add(role3);tx.commit();}Test/*** 给用户改选角色*/public void demo9(){Session session HibernateUtils.getCurrentSession();Transaction tx session.beginTransaction();// 给2号用户删除1号角色// 查询2号用户User user session.get(User.class, 2l);// 查询2号角色Role role session.get(Role.class, 1l);user.getRoles().remove(role);tx.commit();} 两者之间关系的维护主要靠的是集合。操作集合就可以操作他们之间的关系所以说多对多一般进行操作的时候都操作的是集合。 转载于:https://www.cnblogs.com/xifengbuqi/p/9546276.html