员工与角色案例:

一个员工可以是多种角色(总监,经理),一种角色可以是多个员工(保洁)

这里发现无法使用外键表达关系,多对多总是创建第三张表来维护关系

这张表至少两列,都是外键,分别引用两张表的主键

员工(用户)实体类:

  1. package domain;
  2. //用户实体
  3. import java.util.HashSet;
  4. import java.util.Set;
  5.  
  6. public class User {
  7. private Long user_id;
  8. private String user_code;
  9. private String user_name;
  10. private String user_password;
  11. private Character user_state;
  12. //表达多对多
  13. private Set<Role> roles = new HashSet<Role>();
  14. public Long getUser_id() {
  15. return user_id;
  16. }
  17. public void setUser_id(Long user_id) {
  18. this.user_id = user_id;
  19. }
  20. public String getUser_code() {
  21. return user_code;
  22. }
  23. public void setUser_code(String user_code) {
  24. this.user_code = user_code;
  25. }
  26. public String getUser_name() {
  27. return user_name;
  28. }
  29. public void setUser_name(String user_name) {
  30. this.user_name = user_name;
  31. }
  32. public String getUser_password() {
  33. return user_password;
  34. }
  35. public void setUser_password(String user_password) {
  36. this.user_password = user_password;
  37. }
  38. public Character getUser_state() {
  39. return user_state;
  40. }
  41. public void setUser_state(Character user_state) {
  42. this.user_state = user_state;
  43. }
  44. public Set<Role> getRoles() {
  45. return roles;
  46. }
  47. public void setRoles(Set<Role> roles) {
  48. this.roles = roles;
  49. }
  50.  
  51. }

角色实体类:

  1. package domain;
  2. //角色实体
  3. import java.util.HashSet;
  4. import java.util.Set;
  5.  
  6. public class Role {
  7. private Long role_id;
  8. private String role_name;
  9. private String role_memo;
  10. //表达多对多
  11. private Set<User> users = new HashSet<User>();
  12. public Long getRole_id() {
  13. return role_id;
  14. }
  15. public void setRole_id(Long role_id) {
  16. this.role_id = role_id;
  17. }
  18. public String getRole_name() {
  19. return role_name;
  20. }
  21. public void setRole_name(String role_name) {
  22. this.role_name = role_name;
  23. }
  24. public String getRole_memo() {
  25. return role_memo;
  26. }
  27. public void setRole_memo(String role_memo) {
  28. this.role_memo = role_memo;
  29. }
  30. public Set<User> getUsers() {
  31. return users;
  32. }
  33. public void setUsers(Set<User> users) {
  34. this.users = users;
  35. }
  36.  
  37. }

User.hbm.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC
  3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  4. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  5. <hibernate-mapping package="domain" >
  6. <class name="User" table="sys_user" >
  7. <id name="user_id" >
  8. <generator class="native"></generator>
  9. </id>
  10. <property name="user_code" ></property>
  11. <property name="user_name" ></property>
  12. <property name="user_password" ></property>
  13. <property name="user_state" ></property>
  14.  
  15. <!-- 多对多关系表达 -->
  16. <!--
  17. name: 集合属性名
  18. table: 配置中间表名
  19. key
  20. |-column:外键,别人引用"我"的外键列名
  21. class: 我与哪个类是多对多关系
  22. column:外键.我引用别人的外键列名
  23. -->
  24. <set name="roles" table="sys_user_role">
  25. <key column="user_id" ></key>
  26. <many-to-many class="Role" column="role_id" ></many-to-many>
  27. </set>
  28.  
  29. </class>
  30. </hibernate-mapping>

Role.hbm.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC
  3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  4. "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  5. <hibernate-mapping package="domain" >
  6. <class name="Role" table="sys_role" >
  7. <id name="role_id" >
  8. <generator class="native"></generator>
  9. </id>
  10. <property name="role_name" ></property>
  11. <property name="role_memo" ></property>
  12. <set name="users" table="sys_user_role">
  13. <key column="role_id" ></key>
  14. <many-to-many class="User" column="user_id" ></many-to-many>
  15. </set>
  16. </class>
  17. </hibernate-mapping>

核心配置文件:hibernate.cfg.xml:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC
  3. "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
  4. "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
  5. <hibernate-configuration>
  6. <session-factory>
  7. <!-- 数据库驱动 -->
  8. <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
  9. <!-- 数据库url -->
  10. <property name="hibernate.connection.url">jdbc:mysql:///hibernate</property>
  11. <!-- 数据库连接用户名 -->
  12. <property name="hibernate.connection.username">root</property>
  13. <!-- 数据库连接密码 -->
  14. <property name="hibernate.connection.password">xuyiqing</property>
  15.  
  16. <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  17. <!-- 将hibernate生成的sql语句打印到控制台 -->
  18. <property name="hibernate.show_sql">true</property>
  19. <!-- 将hibernate生成的sql语句格式化(语法缩进) -->
  20. <property name="hibernate.format_sql">true</property>
  21.  
  22. <property name="hibernate.hbm2ddl.auto">update</property>
  23. <!-- 引入orm元数据 路径书写: 填写src下的路径 -->
  24.  
  25. <property name="hibernate.connection.isolation">4</property>
  26.  
  27. <!-- 指定session与当前线程绑定 -->
  28. <property name="hibernate.current_session_context_class">thread</property>
  29. <mapping resource="domain/User.hbm.xml" />
  30. <mapping resource="domain/Role.hbm.xml" />
  31.  
  32. </session-factory>
  33. </hibernate-configuration>

自定义工具类:

  1. package utils;
  2.  
  3. import org.hibernate.Session;
  4. import org.hibernate.SessionFactory;
  5. import org.hibernate.cfg.Configuration;
  6.  
  7. public class HibernateUtils {
  8. private static SessionFactory sf;
  9.  
  10. static{
  11. //1 创建,调用空参构造
  12. Configuration conf = new Configuration().configure();
  13. //2 根据配置信息,创建 SessionFactory对象
  14. sf = conf.buildSessionFactory();
  15. }
  16.  
  17. //获得session => 获得全新session
  18. public static Session openSession(){
  19. //3 获得session
  20. Session session = sf.openSession();
  21.  
  22. return session;
  23.  
  24. }
  25. //获得session => 获得与线程绑定的session
  26. public static Session getCurrentSession(){
  27. //3 获得session
  28. Session session = sf.getCurrentSession();
  29.  
  30. return session;
  31. }
  32. }

这里先写一段测试代码:

  1. public void fun1(){
  2. //1 获得session
  3. Session session = HibernateUtils.openSession();
  4. //2 开启事务
  5. Transaction tx = session.beginTransaction();
  6. //-------------------------------------------------
  7. //3操作
  8. //1> 创建两个 User
  9. User u1 = new User();
  10. u1.setUser_name("张三");
  11.  
  12. User u2 = new User();
  13. u2.setUser_name("李四");
  14.  
  15. //2> 创建两个 Role
  16. Role r1 = new Role();
  17. r1.setRole_name("保洁");
  18.  
  19. Role r2 = new Role();
  20. r2.setRole_name("保安");
  21. //3> 用户表达关系
  22. u1.getRoles().add(r1);
  23. u1.getRoles().add(r2);
  24.  
  25. u2.getRoles().add(r1);
  26. u2.getRoles().add(r2);
  27.  
  28. //4> 角色表达关系
  29. r1.getUsers().add(u1);
  30. r1.getUsers().add(u2);
  31.  
  32. r2.getUsers().add(u1);
  33. r2.getUsers().add(u2);
  34.  
  35. //5> 调用Save方法一次保存
  36. session.save(u1);
  37. session.save(u2);
  38. session.save(r1);
  39. session.save(r2);
  40. //-------------------------------------------------
  41. //4提交事务
  42. tx.commit();
  43. //5关闭资源
  44. session.close();
  45. }

看似很标准,不过运行会报错

原因:默认的inverse属性是维护的,两方关系都要维护,造成主键重复

解决办法:

1.改变代码:

  1. @Test
  2. //保存员工以及角色
  3. public void fun1(){
  4. //1 获得session
  5. Session session = HibernateUtils.openSession();
  6. //2 开启事务
  7. Transaction tx = session.beginTransaction();
  8. //-------------------------------------------------
  9. //3操作
  10. //1> 创建两个 User
  11. User u1 = new User();
  12. u1.setUser_name("张三");
  13.  
  14. User u2 = new User();
  15. u2.setUser_name("李四");
  16.  
  17. Role r1 = new Role();
  18. r1.setRole_name("保洁");
  19.  
  20. Role r2 = new Role();
  21. r2.setRole_name("保安");
  22. u1.getRoles().add(r1);
  23. u1.getRoles().add(r2);
  24. u2.getRoles().add(r1);
  25. u2.getRoles().add(r2);
  26. session.save(u1);
  27. session.save(u2);
  28. session.save(r1);
  29. session.save(r2);
  30. //-------------------------------------------------
  31. //4提交事务
  32. tx.commit();
  33. //5关闭资源
  34. session.close();
  35. }

2.配置文件修改:

Role的配置文件:

  1. <set name="users" table="sys_user_role" inverse="true">
  2. <key column="role_id" ></key>
  3. <many-to-many class="User" column="user_id" ></many-to-many>
  4. </set>

这时候运行那一段代码就不会出错

结论: 将来在开发中,如果遇到多对多关系.一定要选择一方放弃维护关系.
一般谁来放弃要看业务方向. 例如录入员工时,需要为员工指定所属角色.
那么业务方向就是由员工维护角色. 角色不需要维护与员工关系.角色放弃维护

多对多同样有cascade属性:

cascade级联操作:
save-update: 级联保存更新
delete:级联删除
all:级联保存更新+级联删除

结论: cascade简化代码书写.该属性使不使用无所谓. 建议要用只用save-update.
如果使用delete操作太过危险.尤其在多对多中.不建议使用.

多对多的其他操作:

  1.  
  2. @Test
  3. //为张三新增一个角色
  4. public void fun3(){
  5. //1 获得session
  6. Session session = HibernateUtils.openSession();
  7. //2 开启事务
  8. Transaction tx = session.beginTransaction();
  9. //-------------------------------------------------
  10. //3操作
  11. //1> 获得张三用户
  12. User user = session.get(User.class, 3l);
  13. //2> 创建总经理角色
  14. Role r = new Role();
  15. r.setRole_name("总经理");
  16. //3> 将角色添加到用户中
  17. user.getRoles().add(r);
  18. //4> 将角色转换为持久化
  19. session.save(r);
  20. //-------------------------------------------------
  21. //4提交事务
  22. tx.commit();
  23. //5关闭资源
  24. session.close();
  25. }
  26.  
  27. @Test
  28. //为张三解除一个角色
  29. public void fun4(){
  30. //1 获得session
  31. Session session = HibernateUtils.openSession();
  32. //2 开启事务
  33. Transaction tx = session.beginTransaction();
  34. //-------------------------------------------------
  35. //3操作
  36. //1> 获得郝强勇用户
  37. User user = session.get(User.class, 3l);
  38. //2> 获得要操作的角色对象(保洁,保安)
  39. Role r1 = session.get(Role.class, 1l);
  40. Role r2 = session.get(Role.class, 2l);
  41. //3> 将角色从用户的角色集合中移除
  42. user.getRoles().remove(r1);
  43. user.getRoles().remove(r2);
  44.  
  45. //-------------------------------------------------
  46. //4提交事务
  47. tx.commit();
  48. //5关闭资源
  49. session.close();
  50. }

这里是一对多的文章,对比后更有收获

http://www.cnblogs.com/xuyiqing/p/8453165.html

hibernate框架学习笔记9:多对多关系案例的更多相关文章

  1. Hibernate学习笔记(五) — 多对多关系映射

    多对多关系映射 多对多建立关系相当于在第三张表中插入一行数据 多对多解除关系相当于在第三张表中删除一行数据 多对多改动关系相当于在第三张表中先删除后添加 多对多谁维护效率都一样.看需求 在实际开发过程 ...

  2. hibernate框架学习笔记8:一对多关系案例

    两个实体类:客户与联系人,一个客户可以有多个联系人 客户类: package domain; import java.util.HashSet; import java.util.Set; //客户实 ...

  3. j2ee开发之hibernate框架学习笔记

    hibernate框架技术重点学习笔记 1.针对不同的数据库,有不同的数据库实现类,使其符号对应的数据库? mysqlDaoImpl oracleDaoImpl ... ... 2.对象和表记录的转换 ...

  4. hibernate框架学习笔记10:HQL查询详解

    HQL语句中不可以出现与表有关的内容,而是对象的属性 实体类(注意配置文件): package domain; import java.util.HashSet; import java.util.S ...

  5. Hibernate框架学习笔记

      Hibernate 是一个 JDO( Java Data Objects)工具.它的工作原理是通过文件把值对象(Java对象)和 数据库表之间建立起一个映射关系,还提供数据查询和获取数据的方法. ...

  6. hibernate框架学习笔记6:事务

    MySQL的事务.JDBC事务操作: 详细见这篇文章:比较详细 http://www.cnblogs.com/xuyiqing/p/8430214.html 如何在hibernate中配置隔离级别: ...

  7. hibernate框架学习笔记3:API详解

    Configuration对象: package api; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configur ...

  8. hibernate框架学习笔记2:配置文件详解

    实体类: package domain; public class Customer { private Long cust_id; private String cust_name; private ...

  9. hibernate框架学习笔记1:搭建与测试

    hibernate框架属于dao层,类似dbutils的作用,是一款ORM(对象关系映射)操作 使用hibernate框架好处是:操作数据库不需要写SQL语句,使用面向对象的方式完成 这里使用ecli ...

随机推荐

  1. faultString = "java.lang.NullPointerException : null"

    1.错误描述 (mx.messaging.messages::ErrorMessage)#0 body = (null) clientId = "E75F6AF8-5E0E-4184-3AF ...

  2. Django学习-22-Form

    Form是Django的功能较强的验证组件,负责各种表单验证 input中的name属性值要和form中的字段名相同 from django import forms from django.form ...

  3. pat1051-1060

    1051 自己写的非常麻烦 http://blog.csdn.net/biaobiaoqi/article/details/9338397 的算法比较好,我的就贴下吧,主要对入栈出栈不够理解 #inc ...

  4. 从零一起学Spring Boot之LayIM项目长成记(六)单聊群聊的实现

    文章传送门: https://my.oschina.net/panzi1/blog/1577007 并没有放弃博客园,只是 t-io 在 oschina发展.用了人家的框架,也得帮人家做做宣传是吧~~

  5. 【BZOJ2337】Xor和路径(高斯消元)

    [BZOJ2337]Xor和路径(高斯消元) 题面 BZOJ 题解 我应该多学点套路: 对于xor之类的位运算,要想到每一位拆开算贡献 所以,对于每一位拆开来看 好了,既然是按位来算 我们就只需要计算 ...

  6. 3分钟anaconda安装Python框架Tensorflow,1行语句测试是否成功?

    Anaconda是一个用于科学计算的ython发行版,支持 Linux, Mac, Windows系统,提供了包管理与环境管理的功能,可以很方便地解决多版本python并存.切换以及各种第三方包安装问 ...

  7. ------ 开源软件 Tor(洋葱路由器,构建匿名网络的方案之一)源码分析——主程序入口点(二)------

    ---------------------------------------------------------- 第二部分仅考察下图所示的代码片段--configure_backtrace_han ...

  8. linux & mac环境python多版本切换与选择

    linux和mac很多地方是相似的,只不过在切换python版本时权限有差异. ====图已补上,O(∩_∩)O~ 1.linux 首先linux内核自带版本是python2.6,但是一般linux ...

  9. Java对于特殊字符做间隔读入的处理(1.3.4)

    先读进字符串,然后再用split分割,注意当默认间隔符有其他意义时,要用\转义字符转义 这道题是pat的一道题,主要读入方法看前面就行了 import java.util.Scanner; publi ...

  10. Apache中限制和允许特定IP访问

    Apache中限制和允许特定IP访问<Directory "/var/www">Options AllAllowOverride NoneOrder Deny,Allo ...