【问题标题】:Why is hibernate failing to save?为什么hibernate无法保存?
【发布时间】:2020-07-27 11:26:08
【问题描述】:

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

这是迁移代码,名为 V2_seed_database.java,位于包 db.migration 中:

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 at net.tekknow.medaverter.service.AppointmentService.save(AppointmentService.java:32) ~[classes/:na]

就在失败的代码行之前,我输出了它说是空的对象的内容,它不是空的:

AppointmentService.save: 约会=id:1, patient_id:1, 日期时间:2010 年 10 月 29 日,医师 ID:1,实验室 ID:1,注释 ID:0

有什么建议吗?

【问题讨论】:

    标签: java hibernate spring-boot flyway


    【解决方案1】:

    这与休眠无关,您正在以不正确的方式使用 spring 依赖注入:您正在尝试自动装配静态字段,这是不允许的。

    Can you use @Autowired with static fields?

    更新

    现在你有

    AppointmentService appointmentService = new AppointmentService();
    

    而不是将此字段注入播种机。

    如果你想让依赖注入工作,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。

    【讨论】:

    • 我最初并没有那样做。 Eclipse 将其作为“快速修复”错误“无法对非静态字段 repo 进行静态引用”提供。那么我应该怎么做呢?
    • 您可能只有 repo 字段作为实例字段,但 save 方法是静态的。不可能从静态方法访问实例字段(因此是快速修复)。您需要将字段和方法都设为非静态
    • 但 save 方法是从公共接口 AppointmentRepository 继承的方法 extends JpaRepository { } JpaRepository 是 Spring Boot(或 Hibernate?)代码,不是我的。
    • 啊,当然可以。对不起,我错过了。谢谢你。我把它拿走了,现在下一个错误显示“org.springframework.beans.factory.BeanCreationException:在文件 [C:\Users\Greg\Projects\MedAverter\target\classes\net\ tekknow\medaverter\controller\AppController.class]:合并 bean 定义的后处理失败;嵌套异常是 java.lang.IllegalStateException:无法自省类 [net.tekknow.medaverter.controller.AppController] 原因:java.lang .NoClassDefFoundError: Lnet/tekknow/medaverter/service/AppointmentService;"
    • 我猜你解决了这个问题,所以会给你功劳。谢谢!
    【解决方案2】:

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

    【讨论】:

    • 我把它改成了 1 但没什么区别
    【解决方案3】:

    在 AppointmentSeeder 中执行此操作,

    @Autowire
    AppointmentService service;
    
    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"));
                service.save(dbAppointment);
            }
        }
    

    【讨论】:

    • 它的@Autowired。但这也没有用。仍然收到相同的错误“原因:java.lang.NullPointerException: null at net.tekknow.medaverter.service.AppointmentService.save(AppointmentService.java:32) ~[classes/:na]”
    • 我根据您的建议修改了主帖中显示的代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 2021-07-14
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多