问题场景

在@Transactional类修饰的同一方法下,对同一张表进行操作。

场景一:

hibernate.query()拿到list数据 // 1
hibernate.merge()合并修改后的list // 2

method2:hibernate.query() // 在方法1里面调用方法2,拿到的是状态1的数据

场景二:

hibernate.query()拿到list数据 //1
jdbcTemplate.removeById()根据id删除数据 // 2,实际调用的是org.springframework.jdbc.core.update()

method2:hibernate.query() // 在方法1里面调用方法2,拿到的是状态2的数据

问题原因

通过hibernate进行数据库连接时,autocommit默认是false,因此须显式调用commit()方法(或者flush()方法)。
而如果使用jdbcTemplate进行数据库连接的话,无需显式执行commit()方法,因为此时autocommit默认为true

Hibernate的flush()

flush()方法的主要作用就是清理缓存,强制数据库与Hibernate缓存同步,以保证数据的一致性。
执行时会清除session缓存并向数据库发送SQL语句并执行,但此时如果数据库当前存在一个事务,数据库会先将这些SQL语句缓存起来,那么此时在数据库中是无法看到SQL语句执行结果的。除非执行commit提交了事务。只要没有执行commit()方法,就能通过rollback()方法进行回滚。

Hibernate的commit()

执行时会先隐式调用flush()方法,再提交事务。执行之后无法rollback()进行回滚。即commit()操作才是真正的将实体数据持久化至数据库。

修改方案

hibernate.query()拿到list数据 // 1
hibernate.merge()合并修改后的list // 2
hibernate.flush()强制同步

method2:hibernate.query() // 在方法1里面调用方法2,拿到的是状态2的数据

这里替换成commit()也是可以的,因为它会先隐式调用flush()方法,再提交事务。
需要注意的是,flush()后虽然method2:hibernate.query()能拿到状态2的数据,但如果此时打断点会发现数据库中还没有更新(只运行了SQL但未提交事务),需要等整个方法结束后(事务提交),才会更新。

暗坑

老代码中用的不是MP,而是自己封装的xxxDao。可以看到一个Dao下将Hibernate和JDBCTemplate混用了,所以经常会出现事务相关的问题,用的时候需要谨慎。

public class BaseDaoImpl<PK extends Serializable, T> implements BaseDao<PK, T> {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @PersistenceContext/*(unitName = "secondary")*/
    private EntityManager em; // JPA的CRUD接口,由Hibernate实现

    @Autowired
    private JdbcTemplate jt;

    protected Class<T> clazz;

    private String tn;

    @SuppressWarnings("unchecked")
    public BaseDaoImpl() {
        // 获取泛型T的类型
        Type t = this.getClass().getGenericSuperclass();
        if (t != null && t instanceof ParameterizedType) {
            Type[] args = ((ParameterizedType) t).getActualTypeArguments();
            if (args != null && args.length > 1) {
                clazz = (Class<T>) args[1];
                tn = DbUtils.tableName(clazz);
            }
        }
    }

    ...
}
Last modification:August 19th, 2021 at 10:44 am
喵ฅฅ