为什么休眠无法保存?

时间:2020-04-14 16:35:50

标签: java hibernate spring-boot flyway

我正在使用Flyway尝试创建,然后在Spring Boot Web应用程序启动时播种数据库。 Flyway在第一次迁移中成功创建了数据库表,但由于NullPointerException而未能在第二次填充中。

这是位于软件包db.migration中的迁移代码,称为V2_seed_database.java:

package db.migration;

import org.flywaydb.core.api.migration.BaseJavaMigration;
import org.flywaydb.core.api.migration.Context;

import net.tekknow.medaverter.db.seeds.AppointmentSeeder;

public class V2__seed_database extends BaseJavaMigration {
    public void migrate(Context context) {
        AppointmentSeeder appointmentSeeder = new AppointmentSeeder();
        appointmentSeeder.seed();
    }
}

这是AppointmentSeeder代码:

package net.tekknow.medaverter.db.seeds;

import org.json.JSONArray; 
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import net.tekknow.medaverter.domain.Appointment;
import net.tekknow.medaverter.service.AppointmentService;

@Service
public class AppointmentSeeder {
    @Autowired
    AppointmentService appointmentService;

    @PostConstruct
    public void seed() {
        String json = "[" +
            "{\"id\":1,\"patient_id\":1,\"dateTime\":\"10/29/2010\",\"physician_id\":1,\"lab_id\":1,\"note_id\":0}" +
        "]";
        org.json.JSONArray appointments = new JSONArray(json);

        for (int i=0; i<appointments.length(); i++) {
            JSONObject appointment = appointments.getJSONObject(i);
            Appointment dbAppointment = new Appointment();
            dbAppointment.setId(appointment.getInt("id"));
            dbAppointment.setPatientId(appointment.getInt("patient_id"));
            dbAppointment.setDateTime(appointment.getString("dateTime"));
            dbAppointment.setPhysicianId(appointment.getInt("physician_id"));
            dbAppointment.setLabId(appointment.getInt("lab_id"));
            dbAppointment.setNoteId(appointment.getInt("note_id"));
            appointmentService.save(dbAppointment);
        }
    }
}   

这是AppointmentRepository代码:

package net.tekknow.medaverter.db;

import org.springframework.data.jpa.repository.JpaRepository;
import net.tekknow.medaverter.domain.Appointment;

public interface AppointmentRepository extends JpaRepository<Appointment,Integer> {
}

这是AppointmentService代码:

package net.tekknow.medaverter.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import net.tekknow.medaverter.db.AppointmentRepository;
import net.tekknow.medaverter.domain.Appointment;

@Service
@Transactional
public class AppointmentService {

    @Autowired
    AppointmentRepository repo;

    public void save(Appointment appointment) {
        System.out.println("AppointmentService.save: appointment="+appointment.toString());
        repo.save(appointment);  //its failing here
    }  
}

这是约会bean:

package net.tekknow.medaverter.domain;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

@Entity
@Table(name = "appointments")
public class Appointment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @NotBlank
    @Column(unique = true)
    private int patient_id;
    @Size(max = 32)
    private String date_time;
    private int physician_id;
    private int lab_id;
    private int note_id;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
... other getters and setters, truncated for brevity

当我运行程序时,迁移开始但在此行失败:

    repo.save(appointment);  //its failing here

,并显示以下错误消息:

由以下原因引起:java.lang.NullPointerException:在null net.tekknow.medaverter.service.AppointmentService.save(AppointmentService.java:32) 〜[classes /:na]

仅在失败的代码行之前,我输出它说为null且不为null的对象的内容:

AppointmentService.save:约会= ID:1,患者ID:1, date_time:10/29/2010,doctor_id:1,lab_id:1,note_id:0

有什么建议吗?

3 个答案:

答案 0 :(得分:1)

这与休眠无关,您以错误的方式使用了Spring依赖项注入:您试图自动装配静态字段,这是不允许的。

请参见Can you use @Autowired with static fields?

更新

现在您有

AppointmentService appointmentService = new AppointmentService();

而不是将此字段注入到Seeder。

如果要使依赖项注入起作用,

Seeder必须是一个Spring管理的bean(可能是@Service)。另请参见@PostConstruct,您可以在初始化bean之后使用它来调用方法。

更新2

您仍在自己使用new实例化Spring Bean,因此不会注入依赖项。

AppointmentSeeder appointmentSeeder = new AppointmentSeeder();

但是,您已经成功地将问题推向了Flyway。现在的问题是Flyway迁移不是Spring Bean:它们是由Flyway而非Spring创建的,因此它们的依赖项不会由Spring自动关联。

Flyway 4.1通过允许使用带有一些配置的预先存在的Spring Bean(或其他Java对象)解决了这个问题

请参见API: Make it possible to use pre-instantiated Java-based migrations #1062

ApplicationContext applicationContext = ...; // obtain a reference to Spring's ApplicationContext.

Flyway flyway = Flyway.configure()
    .dataSource(url, user, password)
    // Add all Spring-instantiated JavaMigration beans
    .javaMigrations(applicationContext.getBeansOfType(JavaMigration.class).values().toArray(new JavaMigration[0]))
    .load();
flyway.migrate();

另请参见JavaMigrationBaseJavaMigration Javadoc。

答案 1 :(得分:0)

也许您应该将JSON文件中的** note_id **的值更改为 1

答案 2 :(得分:0)

在AppointmentSeeder中执行此操作,

xcode-select --install