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

H2数据库@ManyToMany关联数据无法插入中间表BOOK_TAG问题

H2数据库@ManyToMany关联表BOOK_TAG无法插入数据的解决方案

问题背景

使用Hibernate的@ManyToMany关联Books和Tag表时,关联表BOOK_TAG在MySQL中能正常插入数据,但切换到H2数据库后,调用BookRepository的saveAndFlush方法时,日志显示已生成INSERT语句,却没有实际数据写入BOOK_TAG表。

实体类配置如下:

Book.java

@ManyToMany
@JoinTable(
    name = "BOOK_TAG", 
    joinColumns = { @JoinColumn(name = "BOOK_ID") }, 
    inverseJoinColumns = { @JoinColumn(name = "TAG_ID") }
)
Set<Tag> tags = new HashSet(); 

Tag.java

@ManyToMany(mappedBy = "tags", fetch = FetchType.LAZY)
Set<Book> books;    

仓库接口标注了@Transactional(readOnly = true)。

核心原因

问题出在仓库的@Transactional(readOnly = true)配置上:

  • 只读事务模式下,Hibernate会优化事务行为,抑制写操作的提交逻辑。虽然日志中生成了INSERT语句,但由于事务是只读状态,最终不会将数据提交到H2数据库。
  • MySQL对只读事务的写操作兼容性更强,可能会忽略只读标记执行提交,但H2严格遵循事务的只读约束,直接丢弃了写操作的提交请求。

解决方案

  1. 调整事务配置
    移除仓库接口类上的@Transactional(readOnly = true),或者针对saveAndFlush方法单独配置非只读事务:

    @Repository
    public interface BookRepository extends JpaRepository<Book, String> {
        @Override
        @Transactional // 覆盖类上的只读事务配置
        <S extends Book> S saveAndFlush(S entity);
    }
    
  2. 确保关联实体状态正确
    保存Book对象前,确认tags集合中的Tag实体是已持久化的状态(即已存在于H2数据库中)。如果需要新增Tag,可在@ManyToMany注解上添加cascade = CascadeType.PERSIST或CascadeType.ALL,让Book保存时级联保存关联的Tag:

    @ManyToMany(cascade = CascadeType.PERSIST)
    @JoinTable(...)
    Set<Tag> tags = new HashSet(); 
    
  3. 统一数据库事务隔离级别
    将H2数据库的事务隔离级别设置为与MySQL一致(通常为READ_COMMITTED),在application配置文件中添加:

    spring.datasource.hikari.transaction-isolation=TRANSACTION_READ_COMMITTED
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 20:33:18