Невозможно добавлять и обновлять значения с помощью Spring Boot, подключающегося к базе данных PostgreSQL

Я пытаюсь обновить «Студент» из базы данных PostgreSQL, но он только удаляет старое значение и создает новое значение идентификатора для нового студента, при этом все остальные поля пусты.

Вот класс для «Студент», из пакета «Постоянство», подпакет «Сущность»:

@Entity

@Table(name = "student")

public class Student {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "student_id_seq")
@SequenceGenerator(name = "student_id_seq", sequenceName = "student_id_seq", allocationSize=1)
@Column(name = "id", nullable = false)
private Integer id;

@Column
private String studentName;

@Column
private Integer studentGroup;

@Column
private String courseName;

@Column
private Integer studentGrades;


public Integer getId() {
    return id;
}

public void setId(Integer id) {
    this.id = id;
}

public String getStudentName() {
    return studentName;
}

public void setStudentName(String name) {
    this.studentName = name;
}

public Integer getStudentGroup() {
    return studentGroup;
}

public void setStudentGroup(Integer group) {
    this.studentGroup = group;
}

public String getCourseName() { return courseName;}

public void setCourseName(String courseName) {this.courseName = courseName;}

public Integer getStudentGrades() {
    return studentGrades;
}

public void setStudentGrades(Integer grades) {
    this.studentGrades = grades;
}
}

Вот как выглядит мой интерфейс для подпакета «Репозиторий» (также из пакета «Постоянство»):

public interface StudentRepository extends JpaRepository<Student, Integer> {}

В «StudentService» (пакет «Бизнес») у меня есть операции для создания, обновления, удаления и просмотра всех студентов, которые у меня есть:

@Service
public class StudentService {

@Inject
StudentRepository studentRepository;

public List<Student> getAllStudentssWithCourses()
{
    return studentRepository.findAll();
}

public Student create(Student newStudent)
{
    return studentRepository.save(newStudent);
}

public void update(Student newStudent, Student oldStudent){
    if (oldStudent == null){
        System.out.println("ERROR! Student does not exist !!!");
    } else{
        newStudent.setId(oldStudent.getId());
        newStudent.setStudentName(newStudent.getStudentName());
        newStudent.setStudentGroup(newStudent.getStudentGroup());
        newStudent.setCourseName(newStudent.getCourseName());
        newStudent.setStudentGrades(newStudent.getStudentGrades());
        studentRepository.save(newStudent);
    }
}


public void delete(Student student){
    studentRepository.delete(student);
}
}

В пакете «Контроллер» у меня есть:

@Controller
public class StudentController {

@Inject
StudentService studentService;

@RequestMapping(value = "/student", method = RequestMethod.GET)
public ModelAndView getStudents()
{
    List<Student> studentList = studentService.getAllStudentssWithCourses();

    ModelAndView mav = new ModelAndView("student_view");
    mav.addObject("studentsWithCoursesList", studentList);
    mav.addObject("newStudent", new Student());
    return mav;

}


@RequestMapping(value = "/student", method = RequestMethod.POST)
public ModelAndView postStudent(@RequestParam(value = "action") String action,@ModelAttribute(value = "newStudent") Student newStudent)
{
    if (action.equals("Create Student"))
        studentService.create(newStudent);
    else if (action.equals("Update Student"))
        studentService.update(new Student(), newStudent);
    else
        studentService.delete(newStudent);
    return new ModelAndView("redirect:student");
}
}

Мой «student_view» в html выглядит так:

 <body background = "https://www.itmagazine.us/wp-content/uploads/2017/10/6f6499a403cf64afea180b6419def4ef.jpg">

 <h1>Welcome, student user !</h1>
 <table  border = "1">
 <thead>
 <tr>
  <th>student.ID</th>
  <th>student.NAME</th>
  <th>student.GROUP</th>
  <th>student.COURSE</th>
  <th>student.GRADES</th>
 </tr>
 </thead>
 <tbody>
 <tr th:each = "student : ${ studentsWithCoursesList }">

  <td th:text = "${ student.id }">ID</td>
  <td th:text = "${ student.studentName }"></td>
  <td th:text = "${ student.studentGroup }"></td>
  <td th:text = "${ student.courseName }"></td>
  <td th:text = "${ student.studentGrades }"></td>
  </td>
 </tr>
 </tbody>
 </table>

 <br/>
 <br/>
 <br/>

  <form   th:object = "${newStudent}" method = "POST">
  <div class = "col-sm-12">
    <label>Student ID</label>
    <input type = "text" th:field = "*{id}"/>
  </div>
  <div class = "col-sm-12">
    <label>Student Name</label>
    <input type = "text" th:field = "*{studentName}"/>
  </div>
  <div class = "col-sm-12">
    <label>Student Group</label>
    <input type = "text" th:field = "*{studentGroup}"/>
  </div>
  <div class = "col-sm-12">
    <label>Course Name</label>
    <input type = "text" th:field = "*{courseName}"/>
  </div>
  <div class = "col-sm-12">
    <label>Student Grades</label>
    <input type = "text" th:field = "*{studentGrades}"/>
  </div>

 <button type = "submit" class = "btn btn-primary" name = "action" value = "Create Student">ADD Student</button>
 <button type = "submit" class = "btn btn-primary" name = "action" value = "Update Student">EDIT Student</button>
 <button type = "submit" class = "btn btn-primary" name = "action" value = "Delete Student">DELETE Student</button>
 </form>
 </body>

Мой основной класс:

@SpringBootApplication()

public class Assignment2 {
   public static void main(String[] args){
       SpringApplication.run(Assignment2.class, args);

   }
}

В моем "application.properties" у меня есть:

spring.jpa.database = POSTGRESQL
spring.jpa.show-sql = false
spring.jpa.hibernate.ddl-auto = validate
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation = true


spring.datasource.driverClassName = org.postgresql.Driver
spring.datasource.url = jdbc:postgresql://localhost:5432/ps2
spring.datasource.username = postgres
spring.datasource.password = root

spring.thymeleaf.cache = false

spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

server.port = 8090

Моя база данных в PostgreSQL:

CREATE TABLE public.student
(
    id integer NOT NULL,
    student_name character varying COLLATE pg_catalog."default",
    student_group integer,
    course_name character varying COLLATE pg_catalog."default",
    student_grades integer,
    CONSTRAINT "Student_pkey" PRIMARY KEY (id)
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

ALTER TABLE public.student
OWNER to postgres;
-----
CREATE SEQUENCE public.student_id_seq;

ALTER SEQUENCE public.student_id_seq
    OWNER TO postgres;

Наконец, в "pom.xml" у меня есть:

<?xml version = "1.0" encoding = "UTF-8"?>
<project xmlns = "http://maven.apache.org/POM/4.0.0"
     xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.example</groupId>
<artifactId>demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo1</name>
<description>Demo project for Spring Boot</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.1.RELEASE</version>
</parent>


<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>5.2.3.Final</version>
    </dependency>

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

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>


    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>


    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/postgresql/postgresql -->
    <dependency>
        <groupId>postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>9.1-901-1.jdbc4</version>
    </dependency>

</dependencies>


<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>


</project>
1
0
1 510
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

этот вопрос уже задавался ранее.

В заключение вы должны использовать:

@GeneratedValue(strategy = GenerationType.SEQUENCE)

Это потому, что IDENTITY можно использовать только для этих баз данных:

Sybase, My SQL, MS SQL Server, DB2 и HypersonicSQL.

См. https://stackoverflow.com/a/29028369/6884722

Я изменил IDENTITY на SEQUENCE, и теперь у меня есть: Ошибка создания bean-компонента с именем 'entityManagerFactory', определенным в ресурсе пути к классу [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpa‌​Configuration.class]‌​: вызов метода инициализации не удалось; вложенным исключением является javax.persistence.PersistenceException: [PersistenceUnit: по умолчанию] Невозможно построить Hibernate SessionFactory; вложенным исключением является org.hibernate.tool.schema.spi.SchemaManagementException: проверка схемы: отсутствующая последовательность [hibernate_sequence]

user11391131 21.04.2019 19:19
Ответ принят как подходящий

GenerationType.IDENTITY использует столбец автоинкремента базы данных для создания идентификатора.

Ваш столбец Student.id в дБ явно не является автоинкрементным.

Я считаю, что стандартный синтаксис для автоинкремента доступен начиная с Postgres10.

Автоинкремент PostgreSQL

См. также https://thoughts-on-java.org/jpa-generate-primary-keys/ для ознакомления с различными стратегиями генерации. И следующий вопрос Как выбрать стратегию генерации id при использовании JPA и Hibernate

Подводя итоги, ПОСЛЕДОВАТЕЛЬНОСТЬ - лучший доступный вариант, IDENTITY — хороший выбор, только если вы не можете использовать SEQUENCE, потому что он отключает пакетные обновления JDBC.

Я перешел с IDENTITY на SEQUENCE, и это все еще не работает. Есть ли способ изменить мой первичный ключ и сделать его автоинкрементным?

user11391131 21.04.2019 20:08

Попробуйте указать имя последовательности с помощью @SequenceGenerator. Также создайте эту последовательность в SQL.

Lesiak 21.04.2019 20:11

Это сработало, но теперь я не могу обновить ни одно поле в своей таблице. Он просто удаляет старого ученика и создает нового, только с увеличенным id, а остальные поля пустые.

user11391131 21.04.2019 21:11

Ваше обновление в studentService неверно. Проверьте, что вы передаете этому методу как newStudent. Совет: проверьте реализацию сохранения в вашем репозитории. Он вызывает сохранение или слияние в зависимости от идентификатора (нулевой или не нулевой). Вам не нужен особый случай для обновления. Вам не нужно ничего удалять, чтобы обновить.

Lesiak 21.04.2019 22:14

Другие вопросы по теме