篮之新喜 发表于 2023-8-11 11:01:13

hibernate 一对一 一对多 多对多

依赖导入

<dependency>
    <groupId>org.hibernate.orm</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>6.2.7.Final</version>
</dependency>


<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.0.33</version>
</dependency>配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
   
    <session-factory>
      
      <property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
      <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/jpa_study?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai</property>
      <property name="hibernate.connection.username">root</property>
      <property name="hibernate.connection.password">a1b2c3</property>

      
      <property name="show_sql">false</property>
      
      <property name="format_sql">false</property>
      
      <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
      
      <property name="hibernate.hbm2ddl.auto">create-drop</property>
      
      <property name="current_session_context_class">thread</property>

      
      <mapping />
      <mapping />
      <mapping />
      <mapping />
    </session-factory>
</hibernate-configuration>一对一

User 实体类
@Entity
@Table(name = "user")
@Data
public class User {
/*...省略其他内容*/

// 关联列的名称:address_id
@JoinColumn(name = "address_id")
@OneToOne(
          // 懒加载
          fetch = FetchType.LAZY
)
private Address address;
}Address 实体类
@Entity
@Setter
@Getter
@Table(name = "address")
public class Address {
/*...省略其他内容*/

@OneToOne(
      // 实体关联的被拥有者,只想User.address字段
      mappedBy = "address"
)
private User user;
}测试
@Test
public void oneToOneTest() {
    AddressDao addressDao = new AddressDao();// Dao层已经在https://www.cnblogs.com/heirem/p/17616689.html说过了,这里就放代码了
    Address address = new Address();
    address.setDetail("广东中山");
    addressDao.save(address);

    UserDao userDao = new UserDao();
    User user = new User();
    user.setName("张三");
    user.setEmail("zhangsan@email.com");
    userDao.save(user);
    user.setAddress(address);
    userDao.update(user);

    userDao.findAll().forEach(System.out::println);
}User(id=1, name=张三, email=zhangsan@email.com, address=org.example.entity.Address@74bdfa0b, vLog=[], roles=[])一对多

User实体类
@Entity
@Table(name = "user")
@Data
public class User {
/*...省略其他内容*/

@OneToMany(
    // 懒加载
    fetch = FetchType.LAZY,
    // 映射字段,指的是Vlog实体类中映射此实体类的字段,实体关联的被拥有者
    mappedBy = "user"
)
private List<Vlog> vLog;
}Vlog实体类
@Entity
@Table(name = "vlog")
@Getter
@Setter
public class Vlog {
/*...省略其他内容*/

@JoinColumn(name="user_id")// join列,即外键列
@ManyToOne(
          fetch = FetchType.LAZY
)
private User user;
}测试
@Test
public void oneToManyTest() {
    UserDao userDao = new UserDao();
    User user = new User();
    user.setName("张三");
    user.setEmail("zhangsan@email.com");
    userDao.save(user);

    VlogDao vlogDao = new VlogDao();
    Vlog v1 = new Vlog();
    v1.setUrl("www.bilirubin.com/video/1");
    vlogDao.save(v1);

    Vlog v2 = new Vlog();
    v2.setUrl("www.bilirubin.com/video/2");
    vlogDao.save(v2);

    v1.setUser(user);
    v2.setUser(user);
    vlogDao.update(v1);
    vlogDao.update(v2);

    userDao.findAll().forEach(System.out::println);
    vlogDao.findAll().forEach(System.out::println);
}User(id=1, name=张三, email=zhangsan@email.com, address=null, vLog=, roles=[])
org.example.entity.Vlog@4cd7e993
org.example.entity.Vlog@685e6a68多对多

@Entity
@Table(name = "user")
@Data
public class User {
/*...省略其他内容*/

@ManyToMany(
    // 懒加载
    fetch = FetchType.LAZY,
    // 关联操作,不过因为多对多只会影响关联表和本表的数据,即user_role表和user
    cascade = {CascadeType.ALL}
)
@JoinTable(
    // User Role表关联表的名称
    name = "user_role",
    // joinColumns 链接表的外键,记录此类的的id
    joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "id")},
    // inverseJoinColumns 链接表的外键,记录链接类的id
    inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "id")}
)
private List<Role> roles;
}@Entity
@Table(name = "role")
@Setter
@Getter
public class Role {
/*...省略其他内容*/

@ManyToMany(
      fetch = FetchType.LAZY,
      // 实体关系的拥有者,即在User.roles已经声明过关联规则,这边直接关联User.roles就好了
      mappedBy = "roles"
)
private List<User> users;
}测试
@Test
public void manyToManyTest() {
    RoleDao roleDao = new RoleDao();
    Role roleUser = new Role();
    roleUser.setName("user");
    roleUser.setDescription("普通用户");
    roleDao.save(roleUser);

    Role roleAdmin = new Role();
    roleAdmin.setName("admin");
    roleAdmin.setDescription("超级用户");
    roleDao.save(roleAdmin);


    UserDao userDao = new UserDao();
    User u1 = new User();
    u1.setName("张三");
    u1.setName("张三@email.com");
    userDao.save(u1);

    User u2 = new User();
    u2.setName("李四");
    u2.setName("李四@email.com");
    userDao.save(u2);

    u1.setRoles(List.of(roleUser));
    u2.setRoles(List.of(roleUser,roleAdmin));
    userDao.update(u1);
    userDao.update(u2);


    userDao.findAll().forEach(System.out::println);
}User(id=1, name=张三@email.com, email=null, address=null, vLog=[], roles=)
User(id=2, name=李四@email.com, email=null, address=null, vLog=[], roles=)数据库表图解

https://img2023.cnblogs.com/blog/2089409/202308/2089409-20230811104726411-1989444183.png
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字段。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: hibernate 一对一 一对多 多对多