Hibernate多对一/一对多/一对一映射错误排查及关联数据查询代码
我来帮你搞定这个Hibernate映射异常问题,先说说常见的出错原因,再给你完整的可运行代码,保证能打印出包含关联数据的员工信息~
排查Hibernate MappingException及关联配置解决方案
你遇到的org.hibernate.MappingException通常是实体类的映射注解配置出了问题,常见原因包括:
- 实体类没加
@Entity注解,Hibernate无法识别为持久化类 - 双向关联的
mappedBy参数拼写错误,和关联实体的属性名不匹配 - 关联字段的注解参数配置错误(比如
@JoinColumn的列名写错) - 实体类缺少无参构造器(Hibernate强制要求)
- 主键字段未添加
@Id注解,或者主键生成策略配置有误
接下来是正确的实体类配置和测试代码:
1. 实体类代码
Company类(一对多关联Employee)
import javax.persistence.*; import java.util.ArrayList; import java.util.List; @Entity @Table(name = "company") public class Company { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // 双向一对多:mappedBy指定Employee中关联Company的属性名"company" @OneToMany(mappedBy = "company", cascade = CascadeType.ALL, fetch = FetchType.LAZY) private List<Employee> employees = new ArrayList<>(); // 初始化集合避免空指针 // 必须要有无参构造器 public Company() {} public Company(String name) { this.name = name; } // Getter和Setter方法 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> employees) { this.employees = employees; } }
Employee类(多对一关联Company,一对一关联Address)
import javax.persistence.*; @Entity @Table(name = "employee") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; // 多对一关联:指定外键列company_id,FetchType.EAGER确保查询时加载公司数据 @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "company_id") private Company company; // 双向一对一:mappedBy指定Address中关联Employee的属性名"employee" @OneToOne(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.EAGER) private Address address; // 无参构造器 public Employee() {} public Employee(String name) { this.name = name; } // Getter和Setter方法 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Company getCompany() { return company; } public void setCompany(Company company) { this.company = company; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
Address类(一对一关联Employee)
import javax.persistence.*; @Entity @Table(name = "address") public class Address { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String street; private String city; // 一对一关联:指定外键列employee_id,unique=true保证一对一关系 @OneToOne(fetch = FetchType.EAGER) @JoinColumn(name = "employee_id", unique = true) private Employee employee; // 无参构造器 public Address() {} public Address(String street, String city) { this.street = street; this.city = city; } // Getter和Setter方法 public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public Employee getEmployee() { return employee; } public void setEmployee(Employee employee) { this.employee = employee; } }
2. Hibernate配置文件(hibernate.cfg.xml)
放在src/main/resources目录下,替换成你的数据库信息:
<?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/your_db?useSSL=false&serverTimezone=UTC</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">your_password</property> <!-- Hibernate核心配置 --> <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property> <property name="hibernate.show_sql">true</property> <property name="hibernate.format_sql">true</property> <property name="hibernate.hbm2ddl.auto">update</property> <!-- 注册所有实体类 --> <mapping class="com.yourpackage.Company"/> <mapping class="com.yourpackage.Employee"/> <mapping class="com.yourpackage.Address"/> </session-factory> </hibernate-configuration>
3. 主测试类(保存并打印关联数据)
import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateAssociationDemo { public static void main(String[] args) { // 初始化SessionFactory SessionFactory sessionFactory = new Configuration() .configure("hibernate.cfg.xml") .buildSessionFactory(); // 保存测试数据 try (Session session = sessionFactory.openSession()) { session.beginTransaction(); // 创建测试数据并建立关联 Company techCorp = new Company("科技有限公司"); Employee john = new Employee("张三"); Address johnAddr = new Address("北京市朝阳区XX路", "北京"); john.setCompany(techCorp); john.setAddress(johnAddr); johnAddr.setEmployee(john); Employee jane = new Employee("李四"); Address janeAddr = new Address("上海市浦东新区XX街", "上海"); jane.setCompany(techCorp); jane.setAddress(janeAddr); janeAddr.setEmployee(jane); techCorp.getEmployees().add(john); techCorp.getEmployees().add(jane); // 级联保存公司,员工和地址会自动保存 session.save(techCorp); session.getTransaction().commit(); System.out.println("测试数据保存成功!"); } // 查询并打印员工完整数据(包含公司和地址) try (Session session = sessionFactory.openSession()) { session.beginTransaction(); System.out.println("\n=== 员工完整信息 ==="); session.createQuery("from Employee", Employee.class) .getResultList() .forEach(emp -> { System.out.println("员工ID: " + emp.getId()); System.out.println("员工姓名: " + emp.getName()); System.out.println("所属公司: " + emp.getCompany().getName()); System.out.println("居住地址: " + emp.getAddress().getStreet() + "," + emp.getAddress().getCity()); System.out.println("------------------------"); }); session.getTransaction().commit(); } // 关闭SessionFactory sessionFactory.close(); } }
关键注意事项
- 确保所有实体类都添加了
@Entity注解,并且在配置文件中正确注册 - 双向关联的
mappedBy属性必须和关联实体中的属性名完全一致(比如Company的mappedBy="company"对应Employee的private Company company;) - 实体类必须提供无参构造器,Hibernate需要通过它来实例化持久化对象
- 调整
fetch策略:如果是懒加载(FetchType.LAZY),需要在事务内访问关联数据,否则会抛出懒加载异常;示例中用了EAGER方便测试,实际项目中建议按需使用懒加载
内容的提问来源于stack exchange,提问作者rajat kumar
相关产品推荐
相关产品推荐

