如何用JPA和Hibernate设置Read Uncommitted隔离级?该隔离级能否实现?
嘿,这两个问题问到点子上了,我来给你详细梳理清楚:
有几种不同的方式可以设置,取决于你是想全局配置还是针对单个事务:
全局配置(适用于所有事务)
如果你用JPA标准的persistence.xml,可以在<properties>节点里添加:<property name="hibernate.connection.isolation" value="1"/>这里的
1是Read Uncommitted对应的数据库常量(主流数据库如MySQL、PostgreSQL都用这个值代表该隔离级别)。要是用Spring Boot,直接在配置文件里配置更方便:
# application.properties spring.jpa.properties.hibernate.connection.isolation=1针对单个事务设置
如果你只想让某一个事务使用Read Uncommitted,有两种常用方式:
一是通过Hibernate的Session直接操作连接:Session session = entityManager.unwrap(Session.class); session.doWork(connection -> { connection.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); });二是在Spring环境下用
@Transactional注解指定隔离级别:@Transactional(isolation = Isolation.READ_UNCOMMITTED) public void queryUncommittedData() { // 这个方法内的事务会使用Read Uncommitted级别 }
当然不是!咱们得把数据库事务隔离级别和Hibernate持久化上下文(一级缓存)的特性分开来看:
持久化上下文是持久化实体实例的缓存……自动脏检查是该缓存的优势之一,另一优势是实体的可重复读以及工作单元范围缓存的性能提升……无需额外操作启用持久化上下文缓存,它始终处于启用状态,且基于所述原因无法关闭。
这段话说的是持久化上下文本身会提供会话级的可重复读——也就是在同一个事务里,多次查询同一个实体时,Hibernate会直接从一级缓存返回结果,不会再去数据库查询。但这和数据库层面的Read Uncommitted隔离级别并不冲突:
- 数据库的Read Uncommitted级别是允许读取其他事务未提交的数据,这个规则是在数据库层面生效的。
- 持久化上下文的缓存只是会话内的优化,如果你想获取数据库里最新的(哪怕是未提交的)数据,完全可以绕过一级缓存:
比如用EntityManager.refresh(entity)强制从数据库刷新实体数据;或者在查询时设置缓存模式为CacheMode.IGNORE,让Hibernate直接去数据库查询:
也可以用TypedQuery<YourEntity> query = entityManager.createQuery("SELECT e FROM YourEntity e", YourEntity.class); query.setHint("org.hibernate.cacheMode", CacheMode.IGNORE); List<YourEntity> results = query.getResultList();Session.evict(entity)把实体从一级缓存中移除,下次查询就会去数据库拉取最新数据。
简单来说:持久化上下文的可重复读是会话内的缓存特性,而Read Uncommitted是数据库的事务隔离规则,两者可以共存。只要你正确设置了数据库的隔离级别,并且在需要的时候绕过Hibernate的一级缓存,就能实现Read Uncommitted的效果。
内容的提问来源于stack exchange,提问作者Alex Mi

