一、一对多|多对一
1.1、关系表达(多的一方存在外键)
【图1-1 表中的表达】
【图 1-2 实体中的表达】
说明:其中Set集合避免了数据的重复
1.2、hibernate基本操作
重点:ORM元数据中的表达
【实体类:Customer.java】
//使用Set集合表示多的一方 private Set<LinkMan> linkMan = new HashSet<>(); |
package hibernate.hnu.domain;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_linkman;
private String cust_phone;
private String cust_mobile;
private Set<LinkMan> linkMan = new HashSet<>();
public Set<LinkMan> getLinkMan() {
return linkMan;
}
public void setLinkMan(Set<LinkMan> linkMan) {
this.linkMan = linkMan;
}
public Long getCust_id() {
return cust_id;
}
public void setCust_id(Long cust_id) {
this.cust_id = cust_id;
}
public String getCust_name() {
return cust_name;
}
public void setCust_name(String cust_name) {
this.cust_name = cust_name;
}
public String getCust_source() {
return cust_source;
}
public void setCust_source(String cust_source) {
this.cust_source = cust_source;
}
public String getCust_industry() {
return cust_industry;
}
public void setCust_industry(String cust_industry) {
this.cust_industry = cust_industry;
}
public String getCust_level() {
return cust_level;
}
public void setCust_level(String cust_level) {
this.cust_level = cust_level;
}
public String getCust_linkman() {
return cust_linkman;
}
public void setCust_linkman(String cust_linkman) {
this.cust_linkman = cust_linkman;
}
public String getCust_phone() {
return cust_phone;
}
public void setCust_phone(String cust_phone) {
this.cust_phone = cust_phone;
}
public String getCust_mobile() {
return cust_mobile;
}
public void setCust_mobile(String cust_mobile) {
this.cust_mobile = cust_mobile;
}
@Override
public String toString() {
return "Customer [cust_id=" + cust_id + ", cust_name=" + cust_name + "]";
}
}
【实体类:LinkMan.java】
准备数据库:
其中外键: `lkm_cust_id` bigint(32) NOT NULL COMMENT '客户id',
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=3 DEFAULT CHARSET=utf8;
数据库对应的实体类;
注意:在实体类中不维护外键的属性,在配置文件中体现外键
//在多的一方维护 一的一方的属性 private Customer customer; public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } |
package hibernate.hnu.domain;
public class LinkMan {
private Long lkm_id;
private String lkm_name;
//外键,我们在配置文件中维护
//private Long lkm_cust_id;
private String lkm_gender;
private String lkm_phone;
private String lkm_mobile;
private String lkm_email;
private String lkm_qq;
private String lkm_position;
//在多的一方维护 一的一方的属性
private Customer customer;
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Long getLkm_id() {
return lkm_id;
}
public void setLkm_id(Long lkm_id) {
this.lkm_id = lkm_id;
}
public String getLkm_name() {
return lkm_name;
}
public void setLkm_name(String lkm_name) {
this.lkm_name = lkm_name;
}
public String getLkm_gender() {
return lkm_gender;
}
public void setLkm_gender(String lkm_gender) {
this.lkm_gender = lkm_gender;
}
public String getLkm_phone() {
return lkm_phone;
}
public void setLkm_phone(String lkm_phone) {
this.lkm_phone = lkm_phone;
}
public String getLkm_mobile() {
return lkm_mobile;
}
public void setLkm_mobile(String lkm_mobile) {
this.lkm_mobile = lkm_mobile;
}
public String getLkm_email() {
return lkm_email;
}
public void setLkm_email(String lkm_email) {
this.lkm_email = lkm_email;
}
public String getLkm_qq() {
return lkm_qq;
}
public void setLkm_qq(String lkm_qq) {
this.lkm_qq = lkm_qq;
}
public String getLkm_position() {
return lkm_position;
}
public void setLkm_position(String lkm_position) {
this.lkm_position = lkm_position;
}
@Override
public String toString() {
return "LinkMan [lkm_id=" + lkm_id + ", lkm_name=" + lkm_name + "]";
}
}
【ORM元数据配置:Customer.hbm.xml】
<!-- 集合,一对多,在配置文件中的配置 --> <!-- name属性:实体类中多的一方的属性名 column:外键列名 class:与我关联的对象的完整类名 --> <set name="linkMan"> <key column="lkm_cust_id"></key> <one-to-many class="LinkMan"/> </set> |
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="hibernate.hnu.domain.Customer" table="cst_customer">
<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_linkman" column="cust_linkman"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
<!-- 集合,一对多,在配置文件中的配置 -->
<!--
name属性:实体类中多的一方的属性名
column:外键列名
class:与我关联的对象的完整类名
-->
<set name="linkMan">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
</class>
</hibernate-mapping>
【ORM元数据配置:LinkMan.hbm.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="hibernate.hnu.domain.LinkMan" table="cst_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<property name="lkm_mobile" column="lkm_mobile"></property>
<property name="lkm_email" column="lkm_email"></property>
<property name="lkm_qq" column="lkm_qq"></property>
<property name="lkm_position" column="lkm_position"></property>
<!-- 多对一 -->
<!--
name属性:实体类中一的一方的属性名
column:外键列名
class:与我关联的对象的完整类名
-->
<many-to-one name="customer" column="lkm_cust_id" class="Customer"></many-to-one>
</class>
</hibernate-mapping>
【hibernate主配置文件:hibernate.cfg.xml】
主配置文件别忘记导入linkMan.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd" >
<hibernate-configuration>
<!-- hibernate.properties文件中搜索配置信息 -->
<!-- 5个必选配置 -->
<session-factory>
<!-- 数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 数据库url -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<!-- 数据库链接用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库链接密码 -->
<property name="hibernate.connection.password">123456</property>
<!-- 数据库方言-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 3个可选配置 -->
<!-- 将hibernate生成sql语句打印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成sql语句进行格式化,即语法缩进 -->
<property name="hibernate.format_sql">true</property>
<!--自动生成表,如果已经存在则不会再生成,如果表有变动,自动更新表(不会删除任何数据)-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 根据业务调整配置 -->
<!-- 指定hibernate的隔离级别;-->
<property name="hibernate.connection.isolation">4</property>
<!-- 指定session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 引入orm元数据-->
<mapping resource="hibernate/hnu/domain/Customer.hbm.xml"/>
<mapping resource="hibernate/hnu/domain/LinkMan.hbm.xml"/>
</session-factory>
</hibernate-configuration>
【测试:OneManyTest.java】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;
public class OneManyTest {
@Test
public void function(){
//获得session
Session session = HibernateUtils.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//创建对象
Customer c = new Customer();
c.setCust_name("蜀国");
LinkMan m1 = new LinkMan();
m1.setLkm_name("刘备");
LinkMan m2 = new LinkMan();
m2.setLkm_name("关羽");
//表达一对多,客户下有多个联系人
c.getLinkMan().add(m1);
c.getLinkMan().add(m2);
//表达多对一,多个联系人指向同一个客户
m1.setCustomer(c);
m2.setCustomer(c);
session.save(c);
session.save(m1);
session.save(m2);
transaction.commit();
session.close();
}
}
【查看数据库】
【为客户添加联系人】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;
public class OneManyTest {
@Test
public void function(){
//获得session
Session session = HibernateUtils.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//----------------------------------------------------
//获取数据库中的客户
Customer customer = session.get(Customer.class, 1L);
//创建联系人
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("张飞");
//将联系人添加到客户
customer.getLinkMan().add(linkMan);
//将客户添加到联系人
linkMan.setCustomer(customer);
session.save(linkMan);
//---------------------------------------------------
transaction.commit();
session.close();
}
}
【查看数据库】
【为客户删除联系人】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;
public class OneManyTest {
@Test
public void function(){
//获得session
Session session = HibernateUtils.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//----------------------------------------------------
//获取数据库中的客户
Customer customer = session.get(Customer.class, 1L);
//获取联系人
LinkMan linkMan = session.get(LinkMan.class, 2L);
//将联系人从客户中移除
customer.getLinkMan().remove(linkMan);
//将删除的联系人的客户置空
linkMan.setCustomer(null);
/************************************************
注意:这里的customer和linkMan都是持久化状态,无需进一步操作
*************************************************/
//---------------------------------------------------
//提交事务
transaction.commit();
//关闭资源
session.close();
}
}
【查看数据库】
1.3、hibernate进阶操作之级联操作
【一的一方.hbm.xml文件下】
【Customer.hbm.xml】
【级联保存】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="hibernate.hnu.domain.Customer" table="cst_customer">
<id name="cust_id" column="cust_id">
<!--generator;主键生成策略
就是每条记录录入时,主键的生成规则
identity:主键自增,由数据库维护主键值,录入时不需要指定主键
sequence:Oracre中的主键生成策略
increment(了解):主键自增,由hibernate来维护,每次插入时会先查询表中id最大值,+1作为主键
hilo(了解):高级应用算法,主键自增,由hibernate来维护,开发时不使用
native:hilo+sequence+identity 自动三选一策略
uuid:产生随机字符串作为主键,组件类型必须是String类型
assigned:自然主键生成策略。hibernate不会管理主键值,由开发人员手动录入主键
-->
<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_linkman" column="cust_linkman"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
<!-- 级联操作:cascade
save-update : 级联保存更新
delete : 级联删除
all: save-update+delete
级联操作:简化操作,简化代码,目的就是少写两行代码
-->
<set name="linkMan" cascade="save-update">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
</class>
</hibernate-mapping>
【测试代码】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;
public class OneManyTest {
@Test
public void function(){
//获得session
Session session = HibernateUtils.openSession();
//开启事务
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("夏侯惇");
customer.getLinkMan().add(linkMan1);
customer.getLinkMan().add(linkMan2);
//多个联系人对应同一个客户
linkMan1.setCustomer(customer);
linkMan2.setCustomer(customer);
//由于在一的一方设置了级联
//所以只需要将一的一方变成持久化状态即可
session.save(customer);
//下面两行代码就可以省略了
// session.save(linkMan1);
// session.save(linkMan2);
//---------------------------------------------------
//提交事务
transaction.commit();
//关闭资源
session.close();
}
}
【数据库结果】
【级联删除】
就是将cascade对应的属性由原来的save-update 改成 delete
<set name="linkMan" cascade="delete">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
【测试代码】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;
public class OneManyTest {
@Test
public void function(){
//获得session
Session session = HibernateUtils.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//----------------------------------------------------
//获得要操作的客户的对象
Customer customer = session.get(Customer.class, 1L);
//调用delete方法删除客户
session.delete(customer);
//---------------------------------------------------
//提交事务
transaction.commit();
//关闭资源
session.close();
}
}
【数据库】
【多的一方.hbm.xml文件下】
【LinkMan.hbm.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="hibernate.hnu.domain.LinkMan" table="cst_linkman">
<id name="lkm_id" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkm_name" column="lkm_name"></property>
<property name="lkm_gender" column="lkm_gender"></property>
<property name="lkm_phone" column="lkm_phone"></property>
<property name="lkm_mobile" column="lkm_mobile"></property>
<property name="lkm_email" column="lkm_email"></property>
<property name="lkm_qq" column="lkm_qq"></property>
<property name="lkm_position" column="lkm_position"></property>
<!--多的一方:
级联操作:cascade
save-update : 级联保存更新
delete : 级联删除
all:save-update+delete
级联操作:简化操作,简化代码,目的就是少写两行代码
-->
<many-to-one name="customer" column="lkm_cust_id"
cascade="save-update" class="Customer"></many-to-one>
</class>
</hibernate-mapping>
【测试代码】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;
public class OneManyTest {
@Test
public void function(){
//获得session
Session session = HibernateUtils.openSession();
//开启事务
Transaction transaction = session.beginTransaction();
//----------------------------------------------------
//创建客户
Customer customer = new Customer();
customer.setCust_name("京东");
//创建联系人
LinkMan linkMan = new LinkMan();
linkMan.setLkm_name("刘强东");
//为客户设置联系人
customer.getLinkMan().add(linkMan);
//联系人属于哪个客户
linkMan.setCustomer(customer);
session.save(linkMan);
//---------------------------------------------------
//提交事务
transaction.commit();
//关闭资源
session.close();
}
}
【数据库】
结论:级联就是少写两行代码,只要持久化一方,与之关联的另一方也会被同步到数据库中。
建议cascade属性设置成save-update,不推荐使用delete
1.4、hibernate进阶操作之关系维护
删除Customer.hbm.xml和LinkMan.hbm.xml两个文件中的级联操作属性;
【执行代码】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Customer;
import hibernate.hnu.domain.LinkMan;
import hibernate.hnu.utils.HibernateUtils;
public class OneManyTest {
@Test
public void function(){
//获得session
Session session = HibernateUtils.openSession();
//开启事务
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("李勇");
//为客户设置联系人
customer.getLinkMan().add(linkMan1);
customer.getLinkMan().add(linkMan2);
//联系人属于哪个客户
linkMan1.setCustomer(customer);
linkMan2.setCustomer(customer);
session.save(customer);
session.save(linkMan1);
session.save(linkMan2);
//---------------------------------------------------
//提交事务
transaction.commit();
//关闭资源
session.close();
}
}
【控制台】
Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
Hibernate:
update
cst_linkman
set
lkm_cust_id=?
where
lkm_id=?
在保存时,两方都会维护外键关系,关系维护两次,冗余了,多余的维护关系语句,显然是客户这一端在维护关系。
【让一的一方放弃关系维护】
【Customer.hbm.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="hibernate.hnu.domain.Customer" table="cst_customer">
<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_linkman" column="cust_linkman"></property>
<property name="cust_phone" column="cust_phone"></property>
<property name="cust_mobile" column="cust_mobile"></property>
<!-- inverse属性:配置关系不维护
true:Customer不维护关系
false(默认):Customer维护关系
inverse属性:性能优化,提高关系维护的性能
-->
<!--
多的一方,LinkMan,不能放弃维护关系,外键字段在多的一方
-->
<!--
原则:无论怎么放弃,总有一方必须维护关系,
一对多的关系中:一的一方放弃,也只能一方放弃,多的一方不能放弃
-->
<set name="linkMan" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
</class>
</hibernate-mapping>
控制台就干净了,一的一方不再维护外键,让多的一方去维护关系
为了节省数据库资源,省却不必要的update语句,我们一般建议在一对多双向关联关系中,将一方的inverse属性设置为true,即将主外键的关系交由多方来维护。
打个比方:在一个公司中,是老板认识所有的员工容易,还是所有员工认识老板容易?
二、多对多
2.1、关系表达
【图 2-1 表中的表达】
【图 2-2 实体中的表达】
2.2、多对多hibernate基本操作
ORM元数据
【数据库:sys_user】
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`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
【实体类:User.java】
package hibernate.hnu.domain;
import java.util.HashSet;
import java.util.Set;
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private Character user_state;
//表达多对多
private Set<Role> roles = new HashSet<>();
public 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 Character getUser_state() {
return user_state;
}
public void setUser_state(Character user_state) {
this.user_state = user_state;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
@Override
public String toString() {
return "User [user_id=" + user_id + ", user_name=" + user_name + "]";
}
}
【数据库sys_role】
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`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
【实体类:Role.java】
package hibernate.hnu.domain;
import java.util.HashSet;
import java.util.Set;
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
//表达多对多
private Set<User> users = new HashSet<>();
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 Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
@Override
public String toString() {
return "Role [role_id=" + role_id + ", role_name=" + role_name + "]";
}
}
【User.hbm.xml和Role.hbm.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="User" table="sys_user">
<id name="user_id" column="user_id">
<generator class="native"></generator>
</id>
<property name="user_code" column="user_code"></property>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<property name="user_state" column="user_state"></property>
<!-- 多对多关系表达 -->
<!--
name:对应实体类中多对多属性名
table:配置中间表名
key
|-column:外键,别人引用“我”的外键,就是本实体类的主键
many-to-many
|-class:我与哪个类是多对多关系
|-column:外键,我引用别人的外键列名
-->
<set name="roles" table="user_role_id">
<key column="user_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="Role" table="sys_role">
<id name="role_id" column="role_id">
<generator class="native"></generator>
</id>
<property name="role_name" column="role_name"></property>
<property name="role_memo" column="role_memo"></property>
<!-- 多对多关系表达 -->
<!--
name:对应实体类中多对多属性名
table:配置中间表名
key
|-column:外键,别人引用“我”的外键,就是本实体类的主键
many-to-many
|-class:我与哪个类是多对多关系
|-column:外键,我引用别人的外键列名
-->
<set name="users" table="user_role_id">
<key column="role_id"></key>
<many-to-many class="User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
【hibernate配置文件:hibernate.cfg.xml】
引入刚刚的ORM元数据
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd" >
<hibernate-configuration>
<!-- hibernate.properties文件中搜索配置信息 -->
<!-- 5个必选配置 -->
<session-factory>
<!-- 数据库驱动 -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 数据库url -->
<property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
<!-- 数据库链接用户名 -->
<property name="hibernate.connection.username">root</property>
<!-- 数据库链接密码 -->
<property name="hibernate.connection.password">123456</property>
<!-- 数据库方言-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 3个可选配置 -->
<!-- 将hibernate生成sql语句打印到控制台 -->
<property name="hibernate.show_sql">true</property>
<!-- 将hibernate生成sql语句进行格式化,即语法缩进 -->
<property name="hibernate.format_sql">true</property>
<!--自动生成表,如果已经存在则不会再生成,如果表有变动,自动更新表(不会删除任何数据)-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 根据业务调整配置 -->
<!-- 指定hibernate的隔离级别;-->
<property name="hibernate.connection.isolation">4</property>
<!-- 指定session与当前线程绑定 -->
<property name="hibernate.current_session_context_class">thread</property>
<!-- 引入orm元数据-->
<mapping resource="hibernate/hnu/domain/Customer.hbm.xml"/>
<mapping resource="hibernate/hnu/domain/LinkMan.hbm.xml"/>
<mapping resource="hibernate/hnu/domain/User.hbm.xml"/>
<mapping resource="hibernate/hnu/domain/Role.hbm.xml"/>
</session-factory>
</hibernate-configuration>
2.3、多对多hibernate操作之关系维护操作
根据业务方向,选择哪一方放弃关系维护,这里角色放弃关系维护
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="Role" table="sys_role">
<id name="role_id" column="role_id">
<generator class=""></generator>
</id>
<property name="role_name" column="role_name"></property>
<property name="role_memo" column="role_memo"></property>
<!-- 多对多关系表达 -->
<!-- 使用inverse属性:不维护关系
true: 放弃维护关系
false(默认):维护关系
结论:将来开发中,如果遇到多对多关系时,一定要选择一方放弃维护关系
一般谁来放弃要看业务方向,例如录入员工时,需要为员工指定所属角色
那么业务方向就是由员工来维护角色,角色不需要维护与员工关系,角色放弃维护
就是问自己:员工没了,要角色也就没用了
-->
<set name="users" table="user_role_id" inverse="true">
<key column="role_id"></key>
<many-to-many class="User" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
【测试代码】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Role;
import hibernate.hnu.domain.User;
import hibernate.hnu.utils.HibernateUtils;
public class ManyToManyTest {
@Test
public void function(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-----------------------------------------
//创建两个User
User user1 = new User();
User user2 = new User();
user1.setUser_name("商鞅");
user2.setUser_name("司马错");
Role role1 = new Role();
Role role2 = new Role();
role1.setRole_name("大良造");
role2.setRole_name("上将军");
//用户表达角色
user1.getRoles().add(role1);
user1.getRoles().add(role2);
user2.getRoles().add(role2);
//角色表达用户
//(在不对xxx.hbm.xml修改时。两边都维护关系会造成主键重复的错误)
//方法一:注释一方的关系维护代码,比如以下三行
//方法二:在某一方主体配置表中设置inverse属性为true即可
role1.getUsers().add(user1);
role2.getUsers().add(user1);
role2.getUsers().add(user2);
//调用Save方法
session.save(user1);
session.save(user2);
session.save(role1);
session.save(role2);
//--------------------------------------------
//4 提交事务
tx.commit();
//5 关闭资源
session.close();
}
}
【数据库中的表】
2.4、多对多hibernate操作之级联操作
【User.hbm.xml】
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping SYSTEM "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd" >
<hibernate-mapping package="hibernate.hnu.domain">
<class name="User" table="sys_user">
<id name="user_id" column="user_id">
<generator class="native"></generator>
</id>
<property name="user_code" column="user_code"></property>
<property name="user_name" column="user_name"></property>
<property name="user_password" column="user_password"></property>
<property name="user_state" column="user_state"></property>
<!-- 多对多关系表达 -->
<!-- cascade级联操作:
save-update : 级联保存
delete :级联删除
all : save-update+delete
结论:cascade简化代码书写,该属性不使用无所谓,建议用只用save-update
如果使用delete操作太过危险,尤其多对多中,不建议使用
-->
<set name="roles" table="sys_user_role" cascade="save-update">
<key column="user_id"></key>
<many-to-many class="Role" column="role_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
【测试代码】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Role;
import hibernate.hnu.domain.User;
import hibernate.hnu.utils.HibernateUtils;
public class ManyToManyTest {
@Test
public void function(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-----------------------------------------
//1> 获得司马错用户,user已经持久化
User user = session.get(User.class, 2L);
//2> 创建"上卿"角色
Role role = new Role();
role.setRole_name("上卿");
//3> 将角色添加到用户中
user.getRoles().add(role);
//--------------------------------------------
//4 提交事务
tx.commit();
//5 关闭资源
session.close();
}
}
【数据库】
改变成:
【级联删除】
package hibernate.hnu.test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import hibernate.hnu.domain.Role;
import hibernate.hnu.domain.User;
import hibernate.hnu.utils.HibernateUtils;
public class ManyToManyTest {
@Test
public void function(){
//1 获得session
Session session = HibernateUtils.openSession();
//2 开启事务
Transaction tx = session.beginTransaction();
//-----------------------------------------
//获得司马错用户,user已经持久化
User user = session.get(User.class, 2L);
//获得 上将军 这个角色
Role role = session.get(Role.class, 2L);
//将角色从用户的角色集合中移除
user.getRoles().remove(role);
//--------------------------------------------
//4 提交事务
tx.commit();
//5 关闭资源
session.close();
}
}
【数据库】