hibernate 一对一 一对多 多对多

打印 上一主题 下一主题

主题 868|帖子 868|积分 2614

依赖导入
  1. <dependency>
  2.     <groupId>org.hibernate.orm</groupId>
  3.     <artifactId>hibernate-core</artifactId>
  4.     <version>6.2.7.Final</version>
  5. </dependency>
  6. <dependency>
  7.     <groupId>com.mysql</groupId>
  8.     <artifactId>mysql-connector-j</artifactId>
  9.     <version>8.0.33</version>
  10. </dependency>
复制代码
配置文件
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
  3. <hibernate-configuration>
  4.    
  5.     <session-factory>
  6.         
  7.         <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
  8.         <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/jpa_study?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai</property>
  9.         <property name="hibernate.connection.username">root</property>
  10.         <property name="hibernate.connection.password">a1b2c3</property>
  11.         
  12.         <property name="show_sql">false</property>
  13.         
  14.         <property name="format_sql">false</property>
  15.         
  16.         <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
  17.         
  18.         <property name="hibernate.hbm2ddl.auto">create-drop</property>
  19.         
  20.         <property name="current_session_context_class">thread</property>
  21.         
  22.         <mapping />
  23.         <mapping />
  24.         <mapping />
  25.         <mapping />
  26.     </session-factory>
  27. </hibernate-configuration>
复制代码
一对一

User 实体类
  1. @Entity
  2. @Table(name = "user")
  3. @Data
  4. public class User {
  5.   /*...省略其他内容*/
  6.   
  7.   // 关联列的名称:address_id
  8.   @JoinColumn(name = "address_id")
  9.   @OneToOne(
  10.           // 懒加载
  11.           fetch = FetchType.LAZY
  12.   )
  13.   private Address address;
  14. }
复制代码
Address 实体类
  1. @Entity
  2. @Setter
  3. @Getter
  4. @Table(name = "address")
  5. public class Address {
  6.   /*...省略其他内容*/
  7.   @OneToOne(
  8.       // 实体关联的被拥有者,只想User.address字段
  9.       mappedBy = "address"
  10.   )
  11.   private User user;
  12. }
复制代码
测试
  1. @Test
  2. public void oneToOneTest() {
  3.     AddressDao addressDao = new AddressDao();// Dao层已经在https://www.cnblogs.com/heirem/p/17616689.html说过了,这里就放代码了
  4.     Address address = new Address();
  5.     address.setDetail("广东中山");
  6.     addressDao.save(address);
  7.     UserDao userDao = new UserDao();
  8.     User user = new User();
  9.     user.setName("张三");
  10.     user.setEmail("zhangsan@email.com");
  11.     userDao.save(user);
  12.     user.setAddress(address);
  13.     userDao.update(user);
  14.     userDao.findAll().forEach(System.out::println);
  15. }
复制代码
  1. User(id=1, name=张三, email=zhangsan@email.com, address=org.example.entity.Address@74bdfa0b, vLog=[], roles=[])
复制代码
一对多

User实体类
  1. @Entity
  2. @Table(name = "user")
  3. @Data
  4. public class User {
  5.   /*...省略其他内容*/
  6.   @OneToMany(
  7.     // 懒加载
  8.     fetch = FetchType.LAZY,
  9.     // 映射字段,指的是Vlog实体类中映射此实体类的字段,实体关联的被拥有者
  10.     mappedBy = "user"
  11.   )
  12.   private List<Vlog> vLog;
  13. }
复制代码
Vlog实体类
  1. @Entity
  2. @Table(name = "vlog")
  3. @Getter
  4. @Setter
  5. public class Vlog {
  6.   /*...省略其他内容*/
  7.   @JoinColumn(name="user_id")// join列,即外键列
  8.   @ManyToOne(
  9.           fetch = FetchType.LAZY
  10.   )
  11.   private User user;
  12. }
复制代码
测试
  1. @Test
  2. public void oneToManyTest() {
  3.     UserDao userDao = new UserDao();
  4.     User user = new User();
  5.     user.setName("张三");
  6.     user.setEmail("zhangsan@email.com");
  7.     userDao.save(user);
  8.     VlogDao vlogDao = new VlogDao();
  9.     Vlog v1 = new Vlog();
  10.     v1.setUrl("www.bilirubin.com/video/1");
  11.     vlogDao.save(v1);
  12.     Vlog v2 = new Vlog();
  13.     v2.setUrl("www.bilirubin.com/video/2");
  14.     vlogDao.save(v2);
  15.     v1.setUser(user);
  16.     v2.setUser(user);
  17.     vlogDao.update(v1);
  18.     vlogDao.update(v2);
  19.     userDao.findAll().forEach(System.out::println);
  20.     vlogDao.findAll().forEach(System.out::println);
  21. }
复制代码
  1. User(id=1, name=张三, email=zhangsan@email.com, address=null, vLog=[org.example.entity.Vlog@6f7a20da, org.example.entity.Vlog@77ba583], roles=[])
  2. org.example.entity.Vlog@4cd7e993
  3. org.example.entity.Vlog@685e6a68
复制代码
多对多
  1. @Entity
  2. @Table(name = "user")
  3. @Data
  4. public class User {
  5.   /*...省略其他内容*/
  6.   @ManyToMany(
  7.     // 懒加载
  8.     fetch = FetchType.LAZY,
  9.     // 关联操作,不过因为多对多只会影响关联表和本表的数据,即user_role表和user
  10.     cascade = {CascadeType.ALL}
  11.   )
  12.   @JoinTable(
  13.     // User Role表关联表的名称
  14.     name = "user_role",
  15.     // joinColumns 链接表的外键,记录此类的的id
  16.     joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "id")},
  17.     // inverseJoinColumns 链接表的外键,记录链接类的id
  18.     inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "id")}
  19.   )
  20.   private List<Role> roles;
  21. }
复制代码
  1. @Entity
  2. @Table(name = "role")
  3. @Setter
  4. @Getter
  5. public class Role {
  6.   /*...省略其他内容*/
  7.   @ManyToMany(
  8.       fetch = FetchType.LAZY,
  9.       // 实体关系的拥有者,即在User.roles已经声明过关联规则,这边直接关联User.roles就好了
  10.       mappedBy = "roles"
  11.   )
  12.   private List<User> users;
  13. }
复制代码
测试
  1. @Test
  2. public void manyToManyTest() {
  3.     RoleDao roleDao = new RoleDao();
  4.     Role roleUser = new Role();
  5.     roleUser.setName("user");
  6.     roleUser.setDescription("普通用户");
  7.     roleDao.save(roleUser);
  8.     Role roleAdmin = new Role();
  9.     roleAdmin.setName("admin");
  10.     roleAdmin.setDescription("超级用户");
  11.     roleDao.save(roleAdmin);
  12.     UserDao userDao = new UserDao();
  13.     User u1 = new User();
  14.     u1.setName("张三");
  15.     u1.setName("张三@email.com");
  16.     userDao.save(u1);
  17.     User u2 = new User();
  18.     u2.setName("李四");
  19.     u2.setName("李四@email.com");
  20.     userDao.save(u2);
  21.     u1.setRoles(List.of(roleUser));
  22.     u2.setRoles(List.of(roleUser,roleAdmin));
  23.     userDao.update(u1);
  24.     userDao.update(u2);
  25.     userDao.findAll().forEach(System.out::println);
  26. }
复制代码
  1. User(id=1, name=张三@email.com, email=null, address=null, vLog=[], roles=[org.example.entity.Role@48d44b46])
  2. User(id=2, name=李四@email.com, email=null, address=null, vLog=[], roles=[org.example.entity.Role@48d44b46, org.example.entity.Role@dd20ebc])
复制代码
数据库表图解


mappedBy属性 和 JoinColumn注解

mappedby : 属性指向实体关联表的拥有者,声明在被拥有者。简单说就是另一边定义了关联规则,这边不用再定义一遍了,直接引用就行。
@JoinColumn: 外键列

  • 在一对一中@JoinColumn 声明在那个实体类中,生成数据库表时外键列就在那个类。
  • 在一对多中@JoinColumn 必须声明在多的那个实体类中
  • 在多对多中@JoinColumn 必须配合@JoinTable使用
toString()造成的栈溢出StackOverflowError

hibernate中实体类如果有互相关联,比如:一对一关系中 User实体中声明了Address的字段private Address address,Address实体中声明了User的字段private User user。在序列化或者打印时,可能出现循环加载关联字段。比如打印User的实例,User的toString中又调用了Address的toString,这是去加载Address实体类的信息,加载出来后Address的toString中有引用了User的toString方法,完了就这样不断的互相调用,循环且套直至StackOverflowError
解决方法:
打印-删除掉User实体类toString引用的Address.toString的代码。
序列化-跳过User的Address字段。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

篮之新喜

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表