JPA/Hibernate 在 Spring Boot 应用程序中插入不存在的表
Posted
技术标签:
【中文标题】JPA/Hibernate 在 Spring Boot 应用程序中插入不存在的表【英文标题】:JPA/Hibernate inserting into non existing table in spring boot application 【发布时间】:2016-07-14 13:31:14 【问题描述】:我是 spring jpa/boot 的新手。我在 Spring Boot 应用程序中使用 JPA / Hibernate 在 Student
和 StudentCourse
之间创建了一对多关系。
数据库表是student和student_course。
当我运行SchoolApplication.java
时,它失败并出现错误“表或视图不存在”。
这是一个有效错误,因为我还没有创建表 student_course_list
并且只想在 student
和 student_course
表中插入数据。
请您告知为什么 hibernate 正在寻找这个额外的表以及如何解决这个问题?
日志
Hibernate:
insert
into
student_course_list
(student, course_list)
values
(?, ?)
Caused by: org.springframework.dao.InvalidDataAccessResourceUsageException: could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:242) ~[spring-orm-4.2.6.RELEASE.jar:4.2.6.RELEASE]
SchoolApplication.java
package com.school;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.transaction.annotation.Transactional;
import com.school.domain.Student;
import com.school.domain.StudentCourse;
import com.school.service.StudentServiceInterface;
@EntityScan(basePackages="com.school.domain")
@SpringBootApplication
public class SchoolApplication implements CommandLineRunner
@Autowired
protected StudentServiceInterface studentService;
public static void main(String[] args)
SpringApplication.run(SchoolApplication.class, args);
@Override
@Transactional
public void run(String... strings) throws Exception
StudentCourse sc1 = new StudentCourse();
sc1.setCourseId(new Long(1));
sc1.setEndDate(null);
StudentCourse sc2 = new StudentCourse();
sc2.setCourseId(new Long(2));
sc2.setEndDate(null);
//Course List
List<StudentCourse> studentCourse = new ArrayList();
studentCourse.add(sc1);
studentCourse.add(sc2);
Student student = new Student();
student.setFirstName("test first");
student.setLastName("test last");
student.setCourseList(studentCourse);
studentService.saveStudent(student);
学生
@Entity
@Table(name="student")
public class Student
@Id
@Column(name="student_id")
@GeneratedValue(strategy=GenerationType.AUTO, generator="student_seq_gen")
@SequenceGenerator(name="student_seq_gen", sequenceName="SEQ_STUDENT")
private Long studentId;
@OneToMany( targetEntity=StudentCourse.class, cascade = CascadeType.ALL )
private List<StudentCourse> courseList;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
@Column(name="gender")
private char gender;
@Column(name="date_of_birth")
private Date dateOfBirth;
@Column(name="email")
private String email;
@Column(name="city")
private String city;
// getter and setters
.....
.....
学生课程
@Entity
@Table(name="student_course")
public class StudentCourse
@Id
@Column(name="student_course_id")
@GeneratedValue(strategy=GenerationType.AUTO, generator="student_course_seq_gen")
@SequenceGenerator(name="student_course_seq_gen", sequenceName="SEQ_STUDENT_COURSE")
private Long studentCourseId;
@Column(name="student_id")
private Long studentId;
@Column(name="course_id")
private Long courseId;
@Column(name="end_date")
private Date endDate;
// getter and setters
.....
.....
更新:
StudentCourse.java:
@Entity
@Table(name="student_course")
public class StudentCourse
@Id
@Column(name="student_course_id")
@GeneratedValue(strategy=GenerationType.AUTO, generator="student_course_seq_gen")
@SequenceGenerator(name="student_course_seq_gen", sequenceName="SEQ_STUDENT_COURSE")
private Long studentCourseId;
@JoinColumn(name="student_id", nullable = false, updatable = false, insertable = true)
@ManyToOne
private Student student;
@Column(name="course_id")
private Long courseId;
@Column(name="end_date")
private Date endDate;
【问题讨论】:
应用程序未扫描您的实体。你在使用 Spring Data JPA 存储库吗? @Rae,我正在使用 jpa 依赖,-----------StudentCourse
中只有Long studentId
,与Long courseId
相同。这些应该是Student
和Course
对象,然后您可以将mappedBy=
student` 添加到@OneToMany
。
@M.Deinum,抱歉,我没听懂。请您详细回答一下吗?
已经有一个答案解释了这一点。
【参考方案1】:
您没有为您的关系定义JoinColumn
(或JoinTable
对应ManyToMany
)。 Hibernate 正在尝试为您的 student.courseList 关系属性创建一个表。
如下更改您的学生班级:
// You shouldn't need targetEntity, as your collection has the TargetEntity.
// this parameter is only needed if the Generic type is not present
// (e.g. private List courseList)
@OneToMany( cascade = CascadeType.ALL, mappedBy = "student" )
private List<StudentCourse> courseList;
如下更改您的 StudentCourse 课程:
// Replace studentId with a Relationship
@JoinColumn(name="student_id")
@ManyToOne
private Student student;
这将告诉 Hibernate Student -> StudentCourse 的关系由 Student 拥有,并由 student_course 表中的 student_id 列映射。
【讨论】:
它的工作但没有填充 student_course 表中的 student_id。 您是否在StudentCourse?
中设置了Student
能否提供您正在做和看到的示例?
是的,我已经进行了建议的更改。此外,添加了一些额外的属性(nullable = false、updatable = false、insertable = true)请参阅更新的 StudentCourse.java。它将数据插入到 student 和 student_course 表中,但 student_id(外键)没有被插入。
保存学生前需要在StudentCourse中设置学生。喜欢sc1.setStudent(student)
。您可能还应该使 StudentCourse.course 也成为关系。使用相同的模式。
另一个注意,您设置的可为空等属性在运行时不会被验证。它们用于休眠 ddl 生成。如果要在运行时进行验证,需要添加java.persistence.validation注解,如@NotNull
。【参考方案2】:
您并没有告诉您的应用程序扫描实体。在您的主类上添加 @EntityScan
注释。例如
@SpringBootApplication
@EntityScan(basePackages="com.example.model", "com.example.student.model")
public class SchoolApplication implements CommandLineRunner
...
顺便说一句,@ComponentScan
是多余的,@SpringBootApplication
就足够了。如果您要查看 SpringBootApplication
类的内部,您会在那里看到 @ComponentScan
。
【讨论】:
为什么需要添加 EntityScan?因为他的 run 方法中有一个事务?或者是什么原因? 我已经添加了@EntityScan 但仍然遇到同样的错误 这不是必需的,只要@SpringBootApplication
在您的实体的父包中并且您的依赖项列表中有 Spring JPA 库。以上是关于JPA/Hibernate 在 Spring Boot 应用程序中插入不存在的表的主要内容,如果未能解决你的问题,请参考以下文章
JPA---Spring-data-JPA---Hibernate
Spring Boot / JPA / Hibernate,如何根据 Spring 配置文件切换数据库供应商?
spring-data-jpa+hibernate 各种缓存的配置演示
Spring Security JDBC 和 Hibernate JPA