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严格遵循事务的只读约束,直接丢弃了写操作的提交请求。
解决方案
调整事务配置
移除仓库接口类上的@Transactional(readOnly = true),或者针对saveAndFlush方法单独配置非只读事务:@Repository public interface BookRepository extends JpaRepository<Book, String> { @Override @Transactional // 覆盖类上的只读事务配置 <S extends Book> S saveAndFlush(S entity); }确保关联实体状态正确
保存Book对象前,确认tags集合中的Tag实体是已持久化的状态(即已存在于H2数据库中)。如果需要新增Tag,可在@ManyToMany注解上添加cascade = CascadeType.PERSIST或CascadeType.ALL,让Book保存时级联保存关联的Tag:@ManyToMany(cascade = CascadeType.PERSIST) @JoinTable(...) Set<Tag> tags = new HashSet();统一数据库事务隔离级别
将H2数据库的事务隔离级别设置为与MySQL一致(通常为READ_COMMITTED),在application配置文件中添加:spring.datasource.hikari.transaction-isolation=TRANSACTION_READ_COMMITTED
内容的提问来源于stack exchange,提问作者JDGuide
相关产品推荐
相关产品推荐

