java hibernate 多对多_hibernate的多对多关联映射

在我们实际项目中,多对多的情况也时长存在,比如最常见的就是系统管理的五张表,如下面的一个结构:

23281ab6a99d4df9ed9c00f4a157dc9d.png

在本文学习hibernate多对多关联映射的实验中我简单的写几个字段,达到学习目的即可。

1.多对多的关系表达

1.关系型数据库(RDB)中的表达:

e0e1daa0b6e6fb05bd6b5e18c440a0e2.png

2.Java实体中的表达

f8dbaecd66df3a944c26eba20ce5f0f6.png

747eb2cd80fefe7e88a4bbe6f7636079.png

3.orm配置文件中的表达:(注意每次添加了ORM映射文件都要加到主配置文件中)

User.hbm.xml

/p>

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

Role.hbm.xml

/p>

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

4.测试建表结果:

随便执行一个hibernate测试,会加载主配置文件并进行建表。

mysql> descsys_user;+------------+-------------+------+-----+---------+----------------+

| Field | Type | Null | Key | Default | Extra |

+------------+-------------+------+-----+---------+----------------+

| user_id | bigint(20) | NO | PRI | NULL | auto_increment |

| User_name | varchar(20) | YES | | NULL | |

| user_state | char(1) | YES | | NULL | |

+------------+-------------+------+-----+---------+----------------+

3 rows in set (0.00sec)

mysql> descsys_role;+------------+--------------+------+-----+---------+----------------+

| Field | Type | Null | Key | Default | Extra |

+------------+--------------+------+-----+---------+----------------+

| role_id | bigint(20) | NO | PRI | NULL | auto_increment |

| role_name | varchar(20) | YES | | NULL | |

| role_state | varchar(255) | YES | | NULL | |

+------------+--------------+------+-----+---------+----------------+

3 rows in set (0.00sec)

mysql> descsys_user_role;+---------+------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+---------+------------+------+-----+---------+-------+

| user_id | bigint(20) | NO | PRI | NULL | |

| role_id | bigint(20) | NO | PRI | NULL | |

+---------+------------+------+-----+---------+-------+

2 rows in set (0.00 sec)

5.修改ORM配置中set元素配置对set元素的进一步解释

User.hbm.xml

302aba743149098222fac40a270325f3.png

Role.hbm.xml

a2d98314a21a391abc337a577df5489d.png

修改之后查看建表语句:

mysql> show create tablesys_user_role\G*************************** 1. row ***************************

Table: sys_user_roleCreate Table: CREATE TABLE`sys_user_role` (

`user_id1`bigint(20) NOT NULL,

`role_id1`bigint(20) NOT NULL,PRIMARY KEY(`role_id1`,`user_id1`),KEY`FKgxeccay1ha1igqs2myct720lt` (`user_id1`),CONSTRAINT `FKgxeccay1ha1igqs2myct720lt` FOREIGN KEY (`user_id1`) REFERENCES `sys_user` (`user_id`)CONSTRAINT `FKtfvi95hnfedqqxi3rk1qmrwy7` FOREIGN KEY (`role_id1`) REFERENCES`sys_role` (`role_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf81 row in set (0.00 sec)

总结:

个人认为set元素更像是配置我与中间表的关系,key元素可以理解为中间表指向我的外键的名字,

many-to-many中的class指的是与我是多对多的对象类名,column是在中间表中其对应的外键名字。

2.多对多操作

--------------------------第一次测试-----------------

1.测试保存:

/***测试保存(多对多)*/@Testpublic voidfun1() {//1.获取session

Session session =HibernateUtil.openSession();//2.开启事务

Transaction tx =session.beginTransaction();//3.构造数据(张三-总监、经理,李四---总监)

User u1 = newUser();

u1.setUser_name("张三");

User u2= newUser();

u2.setUser_name("李四");

Role r1= newRole();

r1.setRole_name("总监");

Role r2= newRole();

r2.setRole_name("经理");

u1.getRoles().add(r1);

u1.getRoles().add(r2);

u2.getRoles().add(r1);

r1.getUsers().add(u1);

r1.getUsers().add(u2);

r2.getUsers().add(u1);

session.save(u1);

session.save(u2);

session.save(r1);

session.save(r1);//4.提交数据

tx.commit();//5.关闭session

session.close();

}

执行会报错,因为两个表都维护关系,所以会像中间表插入两次记录,导致插入重复。如下错误:

831a982d6d87649799b34edc31f5a140.png

解决办法:

第一钟:将一方维护关系的代码注释掉:(一般开发中多对多的关系中都有一方放弃维护关系)

137ebb430577bb52e1e47fd86da69b8a.png

第二种:配置文件中,设置一方放弃维护关系,例如:设置user放弃维护关系(一般开发中多对多的关系中都有一方放弃维护关系)

6b5ff08553c9b1de704771c6d7adefb1.png

2.测试修改:

/***新增一个角色,并给张三新增加一个角色*/@Testpublic voidfun2() {//1.获取session

Session session =HibernateUtil.openSession();//2.开启事务

Transaction tx =session.beginTransaction();//3.构造数据(张三-总监、经理,李四---总监)

User u1 = session.get(User.class, 1l);

Role r3= newRole();

r3.setRole_name("太监");

session.save(r3);//保存新角色

u1.getRoles().add(r3);//u1处于持久态,因此不用执行更新语句也可以更新//4.提交数据

tx.commit();//5.关闭session

session.close();

}

3.测试给张三删除一个角色

/***为张三删除一个太监角色*/@Testpublic voidfun3() {//1.获取session

Session session =HibernateUtil.openSession();//2.开启事务

Transaction tx =session.beginTransaction();//3.构造数据(张三-总监、经理,李四---总监)

User u1 = session.get(User.class, 1l);

Role r1= session.get(Role.class, 3l);

u1.getRoles().remove(r1);//u1处于持久态,因此不用执行更新语句也可以更新//4.提交数据

tx.commit();//5.关闭session

session.close();

}

查看发出的SQL:

Hibernate:selectuser0_.user_id asuser_id1_3_0_,

user0_.User_name asUser_nam2_3_0_,

user0_.user_stateasuser_sta3_3_0_fromsys_user user0_whereuser0_.user_id=?

Hibernate:selectrole0_.role_idasrole_id1_2_0_,

role0_.role_nameasrole_nam2_2_0_,

role0_.role_stateasrole_sta3_2_0_fromsys_role role0_whererole0_.role_id=?

Hibernate:selectroles0_.user_id asuser_id1_4_0_,

roles0_.role_idasrole_id2_4_0_,

role1_.role_idasrole_id1_2_1_,

role1_.role_nameasrole_nam2_2_1_,

role1_.role_stateasrole_sta3_2_1_fromsys_user_role roles0_inner joinsys_role role1_on roles0_.role_id=role1_.role_idwhereroles0_.user_id=?

Hibernate:delete

fromsys_user_rolewhere

user_id=?and role_id=?

---------------------------第二次测试------------------

1.添加一个张三用户,并给其添加两个角色:经理和总监

/*** 测试1:添加一个张三用户

* 添加两个角色:经理、总监*/@Testpublic voidtest1(){

Session session=HibernateUtils.openSession();

Transaction tx=session.beginTransaction();/******S 开始业务逻辑*************/User u1= newUser();

u1.setUser_name("张三");

Role r1= newRole();

Role r2= newRole();

r1.setRole_name("总监");

r2.setRole_name("经理");

u1.getRoles().add(r1);

u1.getRoles().add(r2);

session.save(u1);

session.save(r1);

session.save(r2);/******E 开始业务逻辑*************/tx.commit();

}

SQL:

Hibernate:insert

intosys_user

(user_name, user_state)values(?, ?)

Hibernate:insert

intosys_role

(role_name, role_state)values(?, ?)

Hibernate:insert

intosys_role

(role_name, role_state)values(?, ?)

Hibernate:insert

intosys_user_role

(user_id, role_id)values(?, ?)

Hibernate:insert

intosys_user_role

(user_id, role_id)values(?, ?)

结果:

mysql> select * fromsys_user;+---------+-----------+------------+

| user_id | user_name | user_state |

+---------+-----------+------------+

| 1 | 张三 | NULL |

+---------+-----------+------------+

1 row in set (0.03sec)

mysql> select * fromsys_role;+---------+-----------+------------+

| role_id | role_name | role_state |

+---------+-----------+------------+

| 1 | 总监 | NULL |

| 2 | 经理 | NULL |

+---------+-----------+------------+

2 rows in set (0.00sec)

mysql> select * fromsys_user_role;+---------+---------+

| user_id | role_id |

+---------+---------+

| 1 | 1 |

| 1 | 2 |

+---------+---------+

2 rows in set (0.00 sec)

2.给上面的张三解除与总监角色的关联关系

/*** 测试2:给上面的张三解除与总监角色的关联关系*/@Testpublic voidtest2(){

Session session=HibernateUtils.openSession();

Transaction tx=session.beginTransaction();/******S 开始业务逻辑*************/

//get方法获取的对象都是持久态

User user = session.get(User.class,1l);

Role role= session.get(Role.class, 1l);

user.getRoles().remove(role);/******E 开始业务逻辑*************/tx.commit();

}

SQL:

Hibernate:selectuser0_.user_id asuser_id1_3_0_,

user0_.user_name asuser_nam2_3_0_,

user0_.user_stateasuser_sta3_3_0_fromsys_user user0_whereuser0_.user_id=?

Hibernate:selectrole0_.role_idasrole_id1_2_0_,

role0_.role_nameasrole_nam2_2_0_,

role0_.role_stateasrole_sta3_2_0_fromsys_role role0_whererole0_.role_id=?

Hibernate:selectroles0_.user_id asuser_id1_4_0_,

roles0_.role_idasrole_id2_4_0_,

role1_.role_idasrole_id1_2_1_,

role1_.role_nameasrole_nam2_2_1_,

role1_.role_stateasrole_sta3_2_1_fromsys_user_role roles0_inner joinsys_role role1_on roles0_.role_id=role1_.role_idwhereroles0_.user_id=?

Hibernate:delete

fromsys_user_rolewhere

user_id=?and role_id=?

结果:

mysql> select * fromsys_user;+---------+-----------+------------+

| user_id | user_name | user_state |

+---------+-----------+------------+

| 1 | 张三 | NULL |

+---------+-----------+------------+

1 row in set (0.00sec)

mysql> select * fromsys_role;+---------+-----------+------------+

| role_id | role_name | role_state |

+---------+-----------+------------+

| 1 | 总监 | NULL |

| 2 | 经理 | NULL |

+---------+-----------+------------+

2 rows in set (0.00sec)

mysql> select * fromsys_user_role;+---------+---------+

| user_id | role_id |

+---------+---------+

| 1 | 2 |

+---------+---------+

1 row in set (0.00 sec)

3.删除经理角色,同时删除与张三的绑定关系

/*** 测试3:删除经理角色,同时删除与张三的绑定关系*/@Testpublic voidtest3(){

Session session=HibernateUtils.openSession();

Transaction tx=session.beginTransaction();/******S 开始业务逻辑*************/

//get方法获取的对象都是持久态

User user = session.get(User.class,1l);

Role role= session.get(Role.class, 2l);

session.delete(role);/******E 开始业务逻辑*************/tx.commit();

}

SQL:

Hibernate:selectuser0_.user_id asuser_id1_3_0_,

user0_.user_name asuser_nam2_3_0_,

user0_.user_stateasuser_sta3_3_0_fromsys_user user0_whereuser0_.user_id=?

Hibernate:selectrole0_.role_idasrole_id1_2_0_,

role0_.role_nameasrole_nam2_2_0_,

role0_.role_stateasrole_sta3_2_0_fromsys_role role0_whererole0_.role_id=?

Hibernate:delete

fromsys_user_rolewhererole_id=?

Hibernate:delete

fromsys_rolewhererole_id=?

结果:

mysql> select * fromsys_role;+---------+-----------+------------+

| role_id | role_name | role_state |

+---------+-----------+------------+

| 1 | 总监 | NULL |

+---------+-----------+------------+

1 row in set (0.00sec)

mysql> select * fromsys_user_role;

Emptyset (0.00 sec)

4.新增一个秘书角色,并赋给张三该角色

/*** 测试4:新增一个秘书角色,并赋给张三该角色*/@Testpublic voidtest4(){

Session session=HibernateUtils.openSession();

Transaction tx=session.beginTransaction();/******S 开始业务逻辑*************/

//get方法获取的对象都是持久态

Role r1 = newRole();

r1.setRole_name("秘书");

User user= session.get(User.class,1l);

user.getRoles().add(r1);

session.save(r1);

session.update(user);/******E 开始业务逻辑*************/tx.commit();

}

SQL:

Hibernate:selectuser0_.user_id asuser_id1_3_0_,

user0_.user_name asuser_nam2_3_0_,

user0_.user_stateasuser_sta3_3_0_fromsys_user user0_whereuser0_.user_id=?

Hibernate:selectroles0_.user_id asuser_id1_4_0_,

roles0_.role_idasrole_id2_4_0_,

role1_.role_idasrole_id1_2_1_,

role1_.role_nameasrole_nam2_2_1_,

role1_.role_stateasrole_sta3_2_1_fromsys_user_role roles0_inner joinsys_role role1_on roles0_.role_id=role1_.role_idwhereroles0_.user_id=?

Hibernate:insert

intosys_role

(role_name, role_state)values(?, ?)

Hibernate:insert

intosys_user_role

(user_id, role_id)values(?, ?)

结果:

mysql> select * fromsys_role;+---------+-----------+------------+

| role_id | role_name | role_state |

+---------+-----------+------------+

| 1 | 总监 | NULL |

| 3 | 秘书 | NULL |

+---------+-----------+------------+

2 rows in set (0.00sec)

mysql> select * fromsys_user_role;+---------+---------+

| user_id | role_id |

+---------+---------+

| 1 | 3 |

+---------+---------+

1 row in set (0.00 sec)

5.修改秘书角色为总监秘书(不影响与用户的关联)

/*** 测试5:修改秘书角色为总监秘书(不影响与用户的关联)*/@Testpublic voidtest5(){

Session session=HibernateUtils.openSession();

Transaction tx=session.beginTransaction();/******S 开始业务逻辑*************/

//get方法获取的对象都是持久态

Role role = session.get(Role.class,3l);

role.setRole_name("总监秘书");

session.update(role);/******E 开始业务逻辑*************/tx.commit();

}

SQL:

Hibernate:selectrole0_.role_idasrole_id1_2_0_,

role0_.role_nameasrole_nam2_2_0_,

role0_.role_stateasrole_sta3_2_0_fromsys_role role0_whererole0_.role_id=?

Hibernate:updatesys_rolesetrole_name=?,

role_state=?whererole_id=?

结果:

mysql> select * fromsys_user_role;+---------+---------+

| user_id | role_id |

+---------+---------+

| 1 | 3 |

+---------+---------+

1 row in set (0.00sec)

mysql> select * fromsys_role;+---------+-----------+------------+

| role_id | role_name | role_state |

+---------+-----------+------------+

| 1 | 总监 | NULL |

| 3 | 总监秘书 | NULL |

+---------+-----------+------------+

2 rows in set (0.00 sec)

6.删除一个用户,会自动删除中间表

mysql> select *from sys_user_role;+---------+---------+

| user_id | role_id |

+---------+---------+

| 1 | 3 |

+---------+---------+

1 row in set (0.00sec)

mysql> select *from sys_role;+---------+-----------+------------+

| role_id | role_name | role_state |

+---------+-----------+------------+

| 1 | 总监 | NULL |

| 3 | 总监秘书 | NULL |

+---------+-----------+------------+

2 rows in set (0.00 sec)

SQL:

Hibernate:selectuser0_.user_id asuser_id1_3_0_,

user0_.user_name asuser_nam2_3_0_,

user0_.user_stateasuser_sta3_3_0_fromsys_user user0_whereuser0_.user_id=?

Hibernate:delete

fromsys_user_rolewhere

user_id=?

Hibernate:delete

fromsys_userwhere

user_id=?

结果:

mysql> select * fromsys_user;

Emptyset (0.00sec)

mysql> select * fromsys_role;+---------+-----------+------------+

| role_id | role_name | role_state |

+---------+-----------+------------+

| 1 | 总监 | NULL |

| 3 | 总监秘书 | NULL |

+---------+-----------+------------+

2 rows in set (0.00sec)

mysql> select * fromsys_user_role;

Emptyset (0.00 sec)

3.进阶操作

1.inverse属性:

一般开发中遇到多对多的关系总有一方放弃维护关系,至于是哪一方要看具体的业务需求。可以在代码中放弃维护,也可以在配置文件中放弃维护。例如录入员工时需要为员工指定所属角色,那么业务方向就是由员工维护角色,角色不需要维护与员工的关系。

代码中放弃维护角色:

/***测试保存(多对多)*/@Testpublic voidfun1() {//1.获取session

Session session =HibernateUtil.openSession();//2.开启事务

Transaction tx =session.beginTransaction();//3.构造数据(张三-总监、经理,李四---总监)

User u1 = newUser();

u1.setUser_name("张三");

User u2= newUser();

u2.setUser_name("李四");

Role r1= newRole();

r1.setRole_name("总监");

Role r2= newRole();

r2.setRole_name("经理");

u1.getRoles().add(r1);

u1.getRoles().add(r2);

u2.getRoles().add(r1);//角色放弃维护与员工的关系//r1.getUsers().add(u1);//r1.getUsers().add(u2);//r2.getUsers().add(u1);

session.save(r1);

session.save(r2);

session.save(u1);

session.save(u2);//4.提交数据

tx.commit();//5.关闭session

session.close();

}

Role.hbm.xml配置文件中放弃维护关系inverse属性为true即是放弃维护关系

83da1fa80b6a3c42646de408b2322100.png

2.级联操作  cascade属性

save-update :级联保存或更新

delete:级联删除

all:等于save-update+delete

1.级联保存或者更新:

例如我们新增一个角色并且给张三赋予新角色的代码如下:

@Testpublic voidfun2() {//1.获取session

Session session =HibernateUtil.openSession();//2.开启事务

Transaction tx =session.beginTransaction();//3.构造数据(张三-总监、经理,李四---总监)

User u1 = session.get(User.class, 1l);

Role r3= newRole();

r3.setRole_name("太监222");

session.save(r3);//保存新角色

u1.getRoles().add(r3);//u1处于持久态,因此不用执行更新语句也可以更新//4.提交数据

tx.commit();//5.关闭session

session.close();

}

我们希望在更新user的时候会级联保存角色,也就是省区一行session.save(r3)对象。

(1)修改User.hbm.xml

6720ec1e811266b76b93878f3102d0ce.png

(2)将代码保存角色的那一行代码注释掉

ce5ec5f0dcf840efc65e7c0e5ddd77b0.png

(3)测试并查看SQL:

Hibernate:selectuser0_.user_id asuser_id1_3_0_,

user0_.User_name asUser_nam2_3_0_,

user0_.user_stateasuser_sta3_3_0_fromsys_user user0_whereuser0_.user_id=?

Hibernate:selectroles0_.user_id asuser_id1_4_0_,

roles0_.role_idasrole_id2_4_0_,

role1_.role_idasrole_id1_2_1_,

role1_.role_nameasrole_nam2_2_1_,

role1_.role_stateasrole_sta3_2_1_fromsys_user_role roles0_inner joinsys_role role1_on roles0_.role_id=role1_.role_idwhereroles0_.user_id=?

Hibernate:insert

intosys_role

(role_name, role_state)values(?, ?)

Hibernate:insert

intosys_user_role

(user_id, role_id)values(?, ?)

2.级联删除:

修改User.hbm.xml,开启级联删除:

c86452eb4aa893d124f524bdebad7380.png

测试代码:(会级联去删除角色表,如果角色表对应记录被其他用户引用会报错)

/***删除张三,查看级联删除角色*/@Testpublic voidfun4() {//1.获取session

Session session =HibernateUtil.openSession();//2.开启事务

Transaction tx =session.beginTransaction();//3.构造数据(张三-总监、经理,李四---总监)

User u1 = session.get(User.class, 5l);

session.delete(u1);//4.提交数据

tx.commit();//5.关闭session

session.close();

}

查看发出的SQL:

Hibernate:selectuser0_.user_id asuser_id1_3_0_,

user0_.User_name asUser_nam2_3_0_,

user0_.user_stateasuser_sta3_3_0_fromsys_user user0_whereuser0_.user_id=?

Hibernate:selectroles0_.user_id asuser_id1_4_0_,

roles0_.role_idasrole_id2_4_0_,

role1_.role_idasrole_id1_2_1_,

role1_.role_nameasrole_nam2_2_1_,

role1_.role_stateasrole_sta3_2_1_fromsys_user_role roles0_inner joinsys_role role1_on roles0_.role_id=role1_.role_idwhereroles0_.user_id=?

Hibernate:delete

fromsys_user_rolewhere

user_id=?

Hibernate:delete

fromsys_rolewhererole_id=?

Hibernate:delete

fromsys_rolewhererole_id=?

Hibernate:delete

fromsys_userwhere

user_id=?

总结:

O 对象 两方都使用集合.

R 关系型数据库 使用中间表.至少两列.作为外键引用两张表的主键.

M 映射文件 多:

操作:操作管理级别属性.

cascade: 级联操作

减少我们书写的操作代码.

none(默认值) 不级联

save-update: 级联保存

delete: 级联删除

all: 级联保存+级联删除

结论: 可以使用save-update.不推荐使用delete. 也可以不用cascade.

inverse: 反转关系维护

属于性能优化.必须选择一方放弃维护主键关系.哪方放弃要看业务方向.

补充:多对多的时候经常用到查询,比如上面查询用户ID为1的用户具有的角色

用HQL判断两个实体间是否存在一对多关系,用的  in elements, 注意in elements 只能用于where 从句中

语法如下:

@Testpublic voidfun5() {//1.获取session

Session session =HibernateUtil.openSession();

String hql= "from Role r where ? in elements(r.users)";

Query query=session.createQuery(hql);

User user= newUser();

user.setUser_id(1L);

query.setParameter(0, user);

List roles =query.list();

System.out.println(roles);

}

查看SQL语句如下:

Hibernate:

select

role0_.role_id as role_id1_0_,

role0_.role_name as role_nam2_0_,

role0_.role_state as role_sta3_0_

from

sys_role role0_

where

? in (

select

users1_.user_id

from

sys_user_role users1_

where

role0_.role_id=users1_.role_id

)

Hibernate:

select

users0_.role_id as role_id2_2_0_,

users0_.user_id as user_id1_2_0_,

user1_.user_id as user_id1_1_1_,

user1_.User_name as User_nam2_1_1_,

user1_.user_state as user_sta3_1_1_

from

sys_user_role users0_

inner join

sys_user user1_

on users0_.user_id=user1_.user_id

where

users0_.role_id=?

Hibernate:

select

users0_.role_id as role_id2_2_0_,

users0_.user_id as user_id1_2_0_,

user1_.user_id as user_id1_1_1_,

user1_.User_name as User_nam2_1_1_,

user1_.user_state as user_sta3_1_1_

from

sys_user_role users0_

inner join

sys_user user1_

on users0_.user_id=user1_.user_id

where

users0_.role_id=?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值