文章目录
1. Hibernate多对多的关联映射案例
1.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`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
角色表的建表语句:
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;
用户角色表的建表语句:
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
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1.2 创建实体
用户的JavaBean代码如下:
public class User {
private Long user_id;
private String user_code;
private String user_name;
private String user_password;
private String user_state;
private Set<Role> roles = new HashSet<Role>();
//省略getter和setter方法
}
角色的JavaBean代码如下:
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
private Set<User> users = new HashSet<User>();
//省略getter和setter方法
}
1.3 创建映射
用户的映射配置文件如下:
<hibernate-mapping>
<class name="com.joker.domain.User" table="sys_user">
<id name="user_id" column="user_id">
<generator class="native"/>
</id>
<property name="user_code" column="user_code"/>
<property name="user_name" column="user_name"/>
<property name="user_password" column="user_password"/>
<property name="user_state" column="user_state"/>
<!-- 关联对象的映射的配置 -->
<!--
set标签:
* name:关联的另一方的集合的属性名称
* table:中间表的名称
key标签:
* column:当前对象在中间表中的外键的名称
many-to-many标签:
* class:关联的另一方的类的全路径
* column:关联的另一方在中间表中的外键名称
-->
<set name="roles" table="sys_user_role">
<key column="user_id"/>
<many-to-many class="com.joker.domain.Role" column="role_id"/>
</set>
</class>
</hibernate-mapping>
角色的映射配置文件如下:
<hibernate-mapping>
<class name="com.joker.domain.Role" table="sys_role">
<id name="role_id" column="role_id">
<generator class="native"/>
</id>
<property name="role_name" column="role_name"/>
<property name="role_memo" column="role_memo"/>
<!-- 关联对象的映射的配置 -->
<!--
set标签:
* name:关联的另一方的集合的属性名称
* table:中间表的名称
key标签:
* column:当前对象在中间表中的外键的名称
many-to-many标签:
* class:关联的另一方的类的全路径
* column:关联的另一方在中间表中的外键名称
-->
<set name="users" table="sys_user_role" inverse="true">
<key column="role_id"/>
<many-to-many class="com.joker.domain.User" column="user_id"/>
</set>
</class>
</hibernate-mapping>
1.4 将映射添加到配置文件
<mapping resource="com/joker/domain/User.hbm.xml"/>
<mapping resource="com/joker/domain/Role.hbm.xml"/>
1.5 编写测试类
public void test1(){
Configuration configuration = new Configuration().configure();
SessionFactory sessionFactory = configuration.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
User user1 = new User();
user1.setUser_name("张三");
User user2 = new User();
user2.setUser_name("李四");
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(role3);
user2.getRoles().add(role2);
user2.getRoles().add(role3);
role1.getUsers().add(user1);
role2.getUsers().add(user3);
role3.getUsers().add(user1);
role3.getUsers().add(user2);
session.save(user1);
session.save(user2);
session.save(rolel);
session.save(role2);
session.save(role3);
transaction.commit();
session.close();
sessionFactory.close();
}
在多对多的保存操作中,如果进行了双向维护关系,就必须有一方放弃外键维护权。一般由被动方放弃,用户主动选择角色,角色是被选择的,所以一般角色要放弃外键维护权。
将数据保存到数据库了以后,那么多对多会有哪些相关的操作呢?下面将详细介绍多对多的相关的操作。
2. Hibernate多对多的相关操作
2.1 级联保存或更新
之前的博文已经介绍过一对多的级联保存了,那么多对多也是一样的。如果只保存单独的一方是不可以的,还是需要保存双方的。如果就想保存一方就需要设置级联操作了。同样要看保存的主控方是哪一端,就需要在那一端进行配置。
- 保存用户级联角色
保存的主控方是用户,需要在用户一端配置:
然后编写测试代码,代码如下:<set name="roles" table="sys_user_role" cascade="save-update"> <key column="user_id"/> <many-to-many class="com.joker.domain.Role" column="role_id"/> </set>
public void test2(){ Configuration configuration = new Configuration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); User user1 = new User(); user1.setUser_name("张三"); User user2 = new User(); user2.setUser_name("李四"); 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(role3); user2.getRoles().add(role2); user2.getRoles().add(role3); role1.getUsers().add(user1); role2.getUsers().add(user3); role3.getUsers().add(user1); role3.getUsers().add(user2); session.save(user1); session.save(user2); //session.save(rolel); //session.save(role2); //session.save(role3); transaction.commit(); session.close(); sessionFactory.close(); }
- 保存角色级联用户
保存的主控方是角色,需要在角色一端配置:
然后编写测试代码,代码如下:<set name="users" table="sys_user_role" cascade="save-update" inverse="true"> <key column="role_id"/> <many-to-many class="com.joker.domain.User" column="user_id"/> </set>
public void test3(){ Configuration configuration = new Configuration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); User user1 = new User(); user1.setUser_name("张三"); User user2 = new User(); user2.setUser_name("李四"); 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(role3); user2.getRoles().add(role2); user2.getRoles().add(role3); role1.getUsers().add(user1); role2.getUsers().add(user3); role3.getUsers().add(user1); role3.getUsers().add(user2); //session.save(user1); //session.save(user2); session.save(rolel); session.save(role2); session.save(role3); transaction.commit(); session.close(); sessionFactory.close(); }
级联保存说完了,那么我们来看下级联删除的操作,但是在多对多中级联删除是不会使用的,因为我们不会有这类的需求,比如删除用户,将用户关联的角色一起删除,或者删除角色的时候将用户删除掉。这是不合理的。但是级联删除的功能Hibernate已经提供了该功能。所以我们只需要了解即可。
2.2 级联删除
- 删除用户级联角色
主控方是用户,所以需要在用户一端配置:
然后编写测试代码,代码如下:<set name="roles" table="sys_user_role" cascade="delete"> <key column="user_id"/> <many-to-many class="com.joker.domain.Role" column="role_id"/> </set>
public void test4(){ Configuration configuration = new Configuration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); User user = session.get(User.class, 1l); session.delete(user); transaction.commit(); session.close(); sessionFactory.close(); }
- 删除角色级联用户
主控方是角色,所以需要在角色一端配置:
然后编写测试代码,代码如下:<set name="users" table="sys_user_role" cascade="delete" inverse="true"> <key column="role_id"/> <many-to-many class="com.joker.domain.User" column="user_id"/> </set>
public void test5(){ Configuration configuration = new Configuration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); Role role = session.get(Role.class, 1l); session.delete(role); transaction.commit(); session.close(); sessionFactory.close(); }
多对多的级联老王就介绍到这了,但是级联并不是主要的操作,我们其实更多的会去使用多对多的一些其他的操作,比如给某个用户选择一个新的角色,或者为某个用户改选已经选好的新角色,或者为某个用户移除某个角色。这些操作是我们以后开发中经常使用的。所以老王就来介绍下如何完成类似的相关的操作。
2.3 多对多的其他操作
其实多对多的关系主要是靠中间表来维护的,那么在Hibernate中多对多主要是靠关联的集合来维护的,所以我们只需要关心如何操作关联的集合即可。那么我们来看下面的几个示例:
- 删除某个用户的角色
public void test6(){ Configuration configuration = new Configuration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); User user = session.get(User.class, 2l); Role role = session.get(Role.class, 1l); // 操作集合,相当于操作中间表 user.getRoles().remove(role); transaction.commit(); session.close(); sessionFactory.close(); }
- 将某个用户的角色改选
public void test6(){ Configuration configuration = new Configuration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); User user = session.get(User.class, 2l); Role role1 = session.get(Role.class, 1l); Role role3 = session.get(Role.class, 3l); user.getRoles().remove(role1); user.getRoles().add(role3); transaction.commit(); session.close(); sessionFactory.close(); }
- 给某个用户添加新角色
public void test6(){ Configuration configuration = new Configuration().configure(); SessionFactory sessionFactory = configuration.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); User user = session.get(User.class, 1l); Role role = session.get(Role.class, 2l); user.getRoles().add(role); transaction.commit(); session.close(); sessionFactory.close(); }