简体   繁体   English

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

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

I need to ensure that inserts are committed during the execution of a stored procedure.我需要确保在执行存储过程期间提交插入。 Using Spring Boot Starter Data JPA 1.5, this was the default behavior for a JpaTransactionManager .使用 Spring Boot Starter Data JPA 1.5,这是JpaTransactionManager的默认行为。 With Spring Boot 2.x, inserts are not committed until the stored procedure completes execution.使用 Spring Boot 2.x,在存储过程完成执行之前不会提交插入。

So, calling this stored procedure using Spring Boot 2.x transaction mgmt, will not insert after 1 minute:因此,使用 Spring Boot 2.x 事务管理调用此存储过程,将不会在 1 分钟后插入:

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

    WAITFOR DELAY '00:01';
end
GO

But calling it using Spring Boot 1.5 transaction mgmt, will insert immediately which is what I need.但是使用 Spring Boot 1.5 事务管理调用它,会立即插入,这正是我所需要的。

Here's the code.这是代码。 Transaction Manager:交易经理:

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

Repo:回购:

public interface TestRepository extends Repository<String, Long> {

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

}

Test case:测试用例:

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

    @Autowired
    private TestRepository testRepo;

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

}

I'm using SQL Server 2016 and its default transaction level is set to READ COMMITTED.我使用的是 SQL Server 2016,它的默认事务级别设置为 READ COMMITTED。

How can I make sure that inserts in a stored procedure are committed immediately during execution?如何确保在执行期间立即提交存储过程中的插入?

Update更新

After a bit more research, I found that with Spring's transaction manager I'm in implicit transaction mode.经过更多研究,我发现使用 Spring 的事务管理器时,我处于隐式事务模式。 But when I don't use it, I'm in autocommit.但是当我不使用它时,我处于自动提交状态。 In other words, select @@OPTIONS & 2 returns 2 with Spring's transaction manager and 0 without it.换句话说, select @@OPTIONS & 2使用 Spring 的事务管理器返回2 ,没有它返回0 So, I think that explains why I'm seeing differences on when the insert commits.所以,我认为这解释了为什么我在插入提交时看到差异。 If that's right, then I just need to know how to set autocommit.如果这是对的,那么我只需要知道如何设置自动提交。 The default mode must have changed either with Spring or the SQL Server jdbc driver (I was using 4.2 and now using 8.2.0.jre8).默认模式必须使用 Spring 或 SQL Server jdbc 驱动程序更改(我使用的是 4.2,现在使用的是 8.2.0.jre8)。

Update 2更新 2

Why is it important that some other process can see the insert into mytempTable before the stored procedure completes?为什么某些其他进程可以在存储过程完成之前看到对 mytempTable 的插入很重要? Because in the production stored procedure, it does the insert, calls off into some service (that I believe selects data from that row and inserts data into another table), and then the sp waitfor data to appear in the table inserted by the service.因为在生产存储过程中,它执行插入,调用某个服务(我相信从该行中选择数据并将数据插入另一个表),然后 sp waitfor数据出现在服务插入的表中。 So, in the case that the service can't see insert, the stored procedure hangs waiting for the service to insert in the other table.所以,在服务看不到insert的情况下,存储过程挂起,等待服务插入到另一个表中。

I think the solution is to not use an explicit transaction and just let SQL Server default to auto commit.我认为解决方案是不使用显式事务,而让 SQL Server 默认为自动提交。 Unfortunately, that also means no rollback if something goes wrong in the stored procedure.不幸的是,这也意味着如果存储过程出现问题,则不会回滚。 But given the stored procedure and the service are third party components that I can't change, I suppose that is my only option.但鉴于存储过程和服务是我无法更改的第三方组件,我想这是我唯一的选择。 Still wondering why the behavior was different between Spring Boot 1.5 and 2.x or the JDBC driver.仍然想知道为什么 Spring Boot 1.5 和 2.x 或 JDBC 驱动程序之间的行为不同。

Update 3更新 3

It turns out that there is no difference in the behavior between Spring Boot 1.5 and 2.x or the JDBC driver versions.事实证明,Spring Boot 1.5 和 2.x 或 JDBC 驱动程序版本之间的行为没有区别。 That is, the inserts never occur until after the transaction completes.也就是说,直到事务完成后才会发生插入。 The reason that I observed the difference in behavior has something to do with the fact that I was testing using Spring Boot 1.5 in an older project and that older project is a composite project with two data source and two transaction managers unlike my Spring Boot 2.x project.我观察到行为差异的原因与我在旧项目中使用 Spring Boot 1.5 进行测试有关,而旧项目是一个复合项目,与我的 Spring Boot 2 不同,它具有两个数据源和两个事务管理器。 x项目。 Not sure why that or what would make insert occur immediately in the old project but it does.不知道为什么会在旧项目中立即发生插入,但确实如此。

At any rate, looking at SQL Server logs, I can confirm that regardless of Spring / JDBC version, it inserts immediately when auto-commit mode is on.无论如何,查看 SQL Server 日志,我可以确认无论 Spring/JDBC 版本如何,它都会在自动提交模式打开时立即插入。

If executing a stored procedure follows the 'transactional-write-behind' pattern of standard entity operations then the normal behavior is for SQL statements to be queued until such time as the transaction completes.如果执行存储过程遵循标准实体操作的“事务-后写”模式,那么正常行为是 SQL 语句排队直到事务完成。

Spring Data repositories are transactional by default so even without the explicit @Transactional(transactionManager="transactionManager") in your test a transaction is in operation. Spring Data 存储库默认是事务性的,因此即使在您的测试中没有显式@Transactional(transactionManager="transactionManager")事务也在运行。

https://vladmihalcea.com/a-beginners-guide-to-jpahibernate-flush-strategies/ (assuming you are using Hibernate here but probably similar concepts in other JPA implementations). https://vladmihalcea.com/a-beginners-guide-to-jpahibernate-flush-strategies/ (假设您在这里使用 Hibernate,但在其他 JPA 实现中可能有类似的概念)。

Try this to trigger an immediate flush:试试这个来触发立即刷新:

@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.

相关问题 第一笔交易完成后,第二笔交易仍在等待中 - Second transaction remains waiting after the first completes 如何在存储过程中提交事务之前在SQL Server中锁定选择的行 - How to lock a SELECted rows in Sql Server until transaction is COMMITTED in a Stored Procedure 提交的 Sequelize 事务的结果是“未定义” - Result of committed Sequelize transaction is "undefined" 下级过程失败时exec into(insert into from storage procedure)后出现神秘错误:“当前事务无法提交” - Mysterious error after exec into (insert into from stored procedure) when subordinate procedure fails: "current transaction cannot be committed" tsql多插入带回滚的事务中 - tsql mutiple inserts in a transaction with rollback WCF事务流未成功完成 - WCF Transaction Flow not getting committed on success 具有提交承诺隔离级别和表约束的事务 - Transaction with Read Committed Isolation Level and Table Constraints 检查已提交的事务,如果是,则返回一个值 - Check transaction committed and if so return a value 如果嵌套事务已成功提交,父事务是否有可能失败 - Is it possible for parent transaction to fail if nested transaction was successfully committed “事务已在事务范围内隐式或显式提交或中止” - “The transaction has already been implicitly or explicitly committed or aborted” in transaction scope
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM