繁体   English   中英

使用 PlatformTransactionManager 完成事务后才提交插入

[英]Inserts not committed until after transaction completes using PlatformTransactionManager

我需要确保在执行存储过程期间提交插入。 使用 Spring Boot Starter Data JPA 1.5,这是JpaTransactionManager的默认行为。 使用 Spring Boot 2.x,在存储过程完成执行之前不会提交插入。

因此,使用 Spring Boot 2.x 事务管理调用此存储过程,将不会在 1 分钟后插入:

CREATE procedure [dbo].[test_insert]
as
begin
    insert into myTempTable(col1)
    values ("1");

    WAITFOR DELAY '00:01';
end
GO

但是使用 Spring Boot 1.5 事务管理调用它,会立即插入,这正是我所需要的。

这是代码。 交易经理:

@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactory);
    return transactionManager;
} 

回购:

public interface TestRepository extends Repository<String, Long> {

    @Procedure("test_insert")
    void testInsert();

}

测试用例:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional(transactionManager="transactionManager")
public class InsertRepositoryTest {

    @Autowired
    private TestRepository testRepo;

    @Test
    public void testInsert() throws SQLException {
        testRepo.testInsert();
    }   

}

我使用的是 SQL Server 2016,它的默认事务级别设置为 READ COMMITTED。

如何确保在执行期间立即提交存储过程中的插入?

更新

经过更多研究,我发现使用 Spring 的事务管理器时,我处于隐式事务模式。 但是当我不使用它时,我处于自动提交状态。 换句话说, select @@OPTIONS & 2使用 Spring 的事务管理器返回2 ,没有它返回0 所以,我认为这解释了为什么我在插入提交时看到差异。 如果这是对的,那么我只需要知道如何设置自动提交。 默认模式必须使用 Spring 或 SQL Server jdbc 驱动程序更改(我使用的是 4.2,现在使用的是 8.2.0.jre8)。

更新 2

为什么某些其他进程可以在存储过程完成之前看到对 mytempTable 的插入很重要? 因为在生产存储过程中,它执行插入,调用某个服务(我相信从该行中选择数据并将数据插入另一个表),然后 sp waitfor数据出现在服务插入的表中。 所以,在服务看不到insert的情况下,存储过程挂起,等待服务插入到另一个表中。

我认为解决方案是不使用显式事务,而让 SQL Server 默认为自动提交。 不幸的是,这也意味着如果存储过程出现问题,则不会回滚。 但鉴于存储过程和服务是我无法更改的第三方组件,我想这是我唯一的选择。 仍然想知道为什么 Spring Boot 1.5 和 2.x 或 JDBC 驱动程序之间的行为不同。

更新 3

事实证明,Spring Boot 1.5 和 2.x 或 JDBC 驱动程序版本之间的行为没有区别。 也就是说,直到事务完成后才会发生插入。 我观察到行为差异的原因与我在旧项目中使用 Spring Boot 1.5 进行测试有关,而旧项目是一个复合项目,与我的 Spring Boot 2 不同,它具有两个数据源和两个事务管理器。 x项目。 不知道为什么会在旧项目中立即发生插入,但确实如此。

无论如何,查看 SQL Server 日志,我可以确认无论 Spring/JDBC 版本如何,它都会在自动提交模式打开时立即插入。

如果执行存储过程遵循标准实体操作的“事务-后写”模式,那么正常行为是 SQL 语句排队直到事务完成。

Spring Data 存储库默认是事务性的,因此即使在您的测试中没有显式@Transactional(transactionManager="transactionManager")事务也在运行。

https://vladmihalcea.com/a-beginners-guide-to-jpahibernate-flush-strategies/ (假设您在这里使用 Hibernate,但在其他 JPA 实现中可能有类似的概念)。

试试这个来触发立即刷新:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional(transactionManager="transactionManager")
public class InsertRepositoryTest {

    @Autowired
    private TestRepository testRepo;

    @PersistenceContext 
    primate EntityManager em;

    @Test
    public void testInsert() throws SQLException {
        testRepo.testInsert();
        em.flush(); //write all buffered SQL statements
    }   
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM