【经验帖】JAVA中同方法,两次调用Mybatis,一次更新,一次查询,同一事务,第一次修改对第二次的可见性如何

JAVA语言中,在同一个方法中先调用Mybatis方法更新一个实体,然后再调用Mybatis方法查询这个实体,在同一个事务里面(这两个sql使用的方法上面有@Transactional注解),第二次能查到第一次修改的结果吗?

在Java语言中,特别是当你在使用JPA(如Hibernate)或Spring Data JPA等ORM(对象关系映射)框架时,对于事务内的数据修改和查询的行为是高度依赖于事务的隔离级别以及数据库本身的实现细节的。

事务隔离级别有哪些

数据库事务的隔离级别定义了事务可能受其他并发事务影响的程度。SQL标准定义了四个隔离级别,从低到高依次为:

  • READ UNCOMMITTED(读未提交):允许事务读取未被其他事务提交的变更。
  • READ COMMITTED(读已提交):确保事务只能读取已经被其他事务提交的变更。
  • REPEATABLE READ(可重复读):确保如果在事务中多次读取同一数据,那么事务期间看到的数据是一致的。但是,这并不能防止幻读(Phantom Reads)。
  • SERIALIZABLE(可串行化):这是最高的隔离级别,它通过强制事务串行执行,来避免脏读、不可重复读和幻读。

但是JPA的隔离级别是如何影响查询的呢 ?

JPA(Java Persistence

API)的隔离级别通过定义事务之间的可见性和相互影响程度,直接影响了在同一个事务或不同事务中执行的查询操作的结果。这些隔离级别旨在解决并发事务中可能出现的脏读、不可重复读和幻读等问题。以下是JPA隔离级别对查询的具体影响:

  1. READ UNCOMMITTED(读未提交)
    影响:在这个隔离级别下,一个事务可以读取到另一个事务尚未提交的更改。这可能导致脏读,即读取到可能永远不会真正写入数据库的数据。
    查询结果:由于可以读取未提交的数据,查询结果可能包含不稳定的、最终可能不存在的数据。
  2. READ COMMITTED(读已提交)
    影响:这个隔离级别确保事务只能读取到已经被其他事务提交的更改。它避免了脏读,但可能允许不可重复读和幻读。
    查询结果:在同一个事务中,如果两次执行相同的查询且期间有其他事务提交了更改,第二次查询可能会返回与第一次不同的结果。
  3. REPEATABLE READ(可重复读)
    影响:这个隔离级别保证在同一个事务中多次读取同一数据集合时,结果始终一致。它避免了脏读和不可重复读,但可能仍然允许幻读。
    查询结果:在同一个事务中,无论其他事务如何提交更改(只要这些更改不影响当前事务已经读取过的数据),查询结果都将保持一致。
  4. SERIALIZABLE(可串行化)
    影响:这是最高的隔离级别,它通过强制事务串行执行来避免脏读、不可重复读和幻读。在这个级别下,事务之间的操作是完全隔离的。
    查询结果:由于事务是串行执行的,因此查询结果将完全不受其他并发事务的影响。但是,这种隔离级别可能会导致数据库性能显著下降。

JPA/Hibernate 中的事务和查询

在JPA/Hibernate中,当你启动一个事务,并在该事务中先更新一个实体,然后立即查询这个实体(假设是同一实体或基于相同条件),你通常会看到更新后的结果,但这并不是因为隔离级别直接导致了这一点,而是因为:

  • 缓存机制:Hibernate使用一级缓存(Session级别的缓存)和二级缓存(可选的,SessionFactory级别的缓存)。在同一个Session(或JPA的EntityManager)中,当你更新一个实体后,这个更新会立即反映在该Session的缓存中。因此,当你再次查询同一个实体时,Hibernate会从它的缓存中检索更新后的实体,而不是去数据库查询。
  • 事务隔离级别:虽然事务的隔离级别决定了并发事务之间如何看到彼此的数据,但在单个事务内部,你通常能够立即看到你对数据所做的修改,无论隔离级别如何。这是因为事务内部的操作是原子性的,并且数据库和ORM框架通常都会确保这一点。

注意事项

JPA的隔离级别设置通常通过@Transactional注解的isolation属性来实现,但具体实现和效果可能会受到底层数据库系统的影响。

在实际应用中,应根据具体的业务需求和性能要求来选择合适的隔离级别。较高的隔离级别可以提供更好的数据一致性和完整性保证,但可能会降低系统的并发性能和吞吐量。

需要注意的是,JPA标准本身并不直接定义事务隔离级别的具体实现细节,而是提供了与底层数据库事务隔离级别相对应的接口和注解。因此,在实际开发中,应参考所使用数据库系统的文档和最佳实践来设置和调整事务隔离级别。

答案:

在同一个事务中,当你先更新一个实体,然后立即查询这个实体(或基于相同条件查询),你通常会看到更新后的结果,这是因为Hibernate等ORM框架的缓存机制以及事务内部操作的原子性。但是,这并不直接由事务的隔离级别决定,而是由框架的内部实现和数据库的行为共同决定的。如果你需要跨事务查看更新,那么就需要考虑事务的提交和数据库的隔离级别了。

相关推荐
tyler_download5 分钟前
golang 实现比特币内核:实现基于椭圆曲线的数字签名和验证
开发语言·数据库·golang
2401_8574396923 分钟前
SpringBoot框架在资产管理中的应用
java·spring boot·后端
怀旧66625 分钟前
spring boot 项目配置https服务
java·spring boot·后端·学习·个人开发·1024程序员节
李老头探索27 分钟前
Java面试之Java中实现多线程有几种方法
java·开发语言·面试
weixin_4493108431 分钟前
高效集成:聚水潭采购数据同步到MySQL
android·数据库·mysql
芒果披萨32 分钟前
Filter和Listener
java·filter
qq_49244844637 分钟前
Java实现App自动化(Appium Demo)
java
阿华的代码王国1 小时前
【SpringMVC】——Cookie和Session机制
java·后端·spring·cookie·session·会话
Cachel wood1 小时前
Github配置ssh key原理及操作步骤
运维·开发语言·数据库·windows·postgresql·ssh·github
standxy1 小时前
如何将钉钉新收款单数据高效集成到MySQL
数据库·mysql·钉钉