You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中CommandLineRunner内Hibernate执行save操作报错的问题咨询

解决Spring Boot CommandLineRunner中Hibernate保存实体报错的问题

我来帮你分析下这个问题的根源,以及对应的解决办法:

问题原因分析

你遇到的报错Can not set int field springboottest.entity.Item.id to springboottest.entity.Item看起来有点反常——怎么会把Item对象赋值给int类型的id字段?主要是两个因素叠加导致的:

1. 实体类中的重复注解问题

你的Item实体类里重复添加了@GeneratedValue注解:

@Id
@GeneratedValue  // 多余的重复注解
@GeneratedValue(strategy = GenerationType.IDENTITY)

在普通Java环境下,Hibernate可能会忽略重复注解,默认取最后一个生效的配置;但在Spring Boot环境中,Spring对JPA注解的解析逻辑更严格,重复注解会导致Hibernate元数据解析异常,进而在生成并赋值id时出现类型错误。

2. Spring Boot自动配置与手动Hibernate上下文冲突

如果你的项目引入了spring-boot-starter-data-jpa依赖,Spring Boot会自动配置JPA相关的Bean(比如EntityManagerFactory、EntityManager),并且会对实体类进行代理增强。而你手动通过Configuration.buildSessionFactory()创建了一个独立的Hibernate SessionFactory,这两个独立的Hibernate上下文会产生冲突,导致手动创建的SessionFactory在处理被Spring代理后的实体类时,反射赋值出现异常。

解决办法

你可以根据自己的需求选择以下两种方案:

方案一:使用Spring管理的JPA/Hibernate组件(推荐)

既然已经用了Spring Boot,最好遵循Spring的生态,使用它管理的JPA组件,而不是手动创建SessionFactory:

步骤1:修正实体类注解

移除重复的@GeneratedValue注解,保留正确的配置:

@Entity
@Table(name = "items")
@NoArgsConstructor
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    @Getter @Setter
    private int id;

    @Getter @Setter
    @Column(nullable = false)
    private String name;

    public Item(String name) {
        this.name = name;
    }
}

步骤2:注入EntityManager进行操作

修改DBInit类,注入Spring管理的EntityManager,再获取原生Session进行操作:

@Service
public class DBInit implements CommandLineRunner {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public void run(String[] args) {
        Session session = entityManager.unwrap(Session.class);
        Item item1 = new Item("itemName");
        session.beginTransaction();
        session.save(item1);
        session.getTransaction().commit();
    }
}

更简洁的方式:使用Spring Data JPA Repository

如果不想直接操作Session,还可以定义一个Repository接口,Spring会自动实现它:

// 定义Repository接口
public interface ItemRepository extends JpaRepository<Item, Integer> {
}

// 修改DBInit类注入Repository
@Service
public class DBInit implements CommandLineRunner {

    private final ItemRepository itemRepository;

    // 构造注入(Spring 4.3+支持无需@Autowired)
    public DBInit(ItemRepository itemRepository) {
        this.itemRepository = itemRepository;
    }

    @Override
    public void run(String[] args) {
        Item item1 = new Item("itemName");
        itemRepository.save(item1);
    }
}

方案二:禁用Spring Boot的JPA自动配置(坚持原生Hibernate)

如果你一定要用手动创建的SessionFactory,可以禁用Spring Boot的JPA自动配置:

步骤1:修正实体类注解

同样先移除重复的@GeneratedValue注解(和方案一的步骤1一致)。

步骤2:在启动类添加禁用配置

修改Spring Boot启动类,排除JPA自动配置类:

@SpringBootApplication(exclude = JpaAutoConfiguration.class)
public class SpringBootTestApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootTestApplication.class, args);
    }
}

这样你的手动SessionFactory代码就能和普通Java环境一样正常运行了。

为什么普通main方法没问题?

在普通Java环境中,没有Spring的自动配置和实体代理增强,Hibernate可以宽松地处理重复注解,也不存在上下文冲突的问题,所以代码能正常执行。但Spring Boot的环境带来了额外的自动配置和增强逻辑,放大了实体类注解的问题,最终导致报错。

内容的提问来源于stack exchange,提问作者Denys_newbie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 12:17:32