JPA/Hibernate 插入 spring 启动应用程序中不存在的 table

JPA/Hibernate inserting into non existing table in spring boot application

我是 spring jpa/boot 的新手。我在 Spring 引导应用程序中使用 JPA/Hibernate 在 StudentStudentCourse 之间创建了一对多关系。

数据库 table 是学生和 student_course。

当我 运行 SchoolApplication.java 时,它因错误 'table or view does not exist' 而失败。

这是一个有效的错误,因为我没有创建 table、student_course_list 并且只想在 studentstudent_course table 中插入数据s.

请问为什么 hibernate 正在寻找这个额外的 table 以及如何解决这个问题?

日志

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;

您并没有告诉您的应用程序扫描实体。在您的主 class 上添加 @EntityScan 注释。例如

@SpringBootApplication
@EntityScan(basePackages={"com.example.model", "com.example.student.model"})
public class SchoolApplication implements CommandLineRunner {
    ...
}

顺便说一句,@ComponentScan是多余的,@SpringBootApplication就够了。如果您要查看 SpringBootApplication class 内部,您会在那里看到 @ComponentScan

您没有为您的关系定义 JoinColumn(或 JoinTable 代表 ManyToMany)。 Hibernate 正在尝试创建 table 您的 student.courseList 关系 属性。

更改您的学生 class 如下:

// 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 class 如下:

// Replace studentId with a Relationship
@JoinColumn(name="student_id")
@ManyToOne
private Student student;

这将告诉 Hibernate Student -> StudentCourse 的关系由 Student 拥有并映射到 student_course table.

中的 student_id 列