I propose to support to propagate a savepoint operation via TransactionSynchronization.
Background
I'm the MyBatis's developer. Now, If application developer use the savepoint(=PROPAGATION_NESTED) feature together with MyBatis, If perform select statement after rollback a savepoint, an application may get the rolled back data from MyBatis's local cache.
I want to the opportunity for clearing local cache that hold on MyBatis module at savepoint operations(at roll backed mainly) for resolving potential problem.
Related Issues
Example Testing Code
package com.example;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionOperations;
import org.springframework.transaction.support.TransactionTemplate;
@SpringBootTest
class MybatisSpringGh785ApplicationTests {
@Autowired
MessageMapper mapper;
@Autowired
PlatformTransactionManager transactionManager;
@Test
void contextLoads() {
// TransactionOperations for standard JDBC Transaction
DefaultTransactionDefinition txDef = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionOperations txOperations = new TransactionTemplate(transactionManager, txDef);
// TransactionOperations for JDBC savepoint Transaction
DefaultTransactionDefinition savepointTxDef = new DefaultTransactionDefinition(
TransactionDefinition.PROPAGATION_NESTED);
TransactionOperations savepointTxOperations = new TransactionTemplate(transactionManager, savepointTxDef);
// Insert test data
txOperations.executeWithoutResult(s -> {
mapper.insert(new Message(1, "Hello!"));
});
// Do Testing
txOperations.executeWithoutResult(txStatus -> {
// Select latest message and save to local cache
Message messageBefore = mapper.select(1);
// Execute processing on savepoint transaction
savepointTxOperations.executeWithoutResult(savepointTxStatus -> {
// Update and clear local cache
mapper.update(new Message(1, "Hello World!!"));
// Select latest message and save to local cache
mapper.select(1);
// Mark to rollback savepoint
savepointTxStatus.setRollbackOnly();
});
// Select latest message but does not return latest message from database because does not clear local cache when savepoint rollback
Message messageAfter = mapper.select(1);
Assertions.assertThat(messageAfter.message()).isEqualTo(messageBefore.message()); // Failed assertion
});
}
record Message(int id, String message) {
}
@Mapper
interface MessageMapper {
@Select("SELECT id, message FROM messages WHERE id = #{id}")
Message select(int id);
@Insert("INSERT INTO messages (id, message) VALUES(#{id}, #{message})")
void insert(Message message);
@Update("UPDATE messages SET message = #{message} WHERE id = #{id}")
void update(Message message);
}
}
CREATE TABLE messages
(
id bigint primary key,
message varchar(256) not null
);
I propose to support to propagate a savepoint operation via
TransactionSynchronization.Background
I'm the MyBatis's developer. Now, If application developer use the savepoint(=
PROPAGATION_NESTED) feature together with MyBatis, If perform select statement after rollback a savepoint, an application may get the rolled back data from MyBatis's local cache.I want to the opportunity for clearing local cache that hold on MyBatis module at savepoint operations(at roll backed mainly) for resolving potential problem.
Related Issues
Example Testing Code