You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It seems like there might be a Connection Leak issue when using the NOT_SUPPORTED propagation attribute or creating a transactionless state in Spring Batch and then calling a non-transactional Repository.
The commonality is that, in both NOT_SUPPORTED and BATCH codes, TransactionSynchronizationManager has activeTransaction set to false and the ResourceMap is empty, but TransactionSynchronizationManager.isSynchronizationActive() returns true.
Looking at the example below might make it easier.
@Service
@RequiredArgsConstructor
public class TestService {
private final TestService2 testService2;
@Transactional
public void test() {
testService2.test();
}
}
@Service
@RequiredArgsConstructor
public class TestService2 {
private final TestRepository TestRepository;
@Transactional(propagation = NOT_SUPPORTED)
public void test() {
var e = TestRepository.findByIdNoTx(1L);
}
}
In the scenario described above, after executing the repository in TestService2::test, the connection remains in the TransactionSynchronizationManager's ResourceMap without being properly removed.
Typically, users might believe that since there is no transaction, the connection will be immediately released. However, it seems that in this case, that assumption does not hold true.
Below is an example of a Spring Batch scenario:
@Bean
public Step step1() {
DefaultTransactionAttribute transactionAttribute = new DefaultTransactionAttribute();
transactionAttribute.setPropagationBehavior(Propagation.NEVER.value());
return stepBuilderFactory.get("step1").tasklet((contribution, chunkContext) -> {
var e = testRepository.findByIdNoTx(1L);
return RepeatStatus.FINISHED;
})
.transactionAttribute(transactionAttribute)
.build();
}
Even in cases like the one described, it seems that after the execution of testRepository.findByIdNoTx(), the transaction manager retains the resource in the resource map, leading to the connection not being released as expected.
The problem described above can cause an exception due to db wiat_timeout when the user creates logic that takes a long time between two repository requests (expecting no connection because there is no transaction).
The cause of the problem seems to be the entityManager creation availability branch in EntityManagerFactoryUtils.
else if (!TransactionSynchronizationManager.isSynchronizationActive()) {
// Indicate that we can't obtain a transactional EntityManager.
return null;
}
Line 249 in EntityManagerFactoryUtils is currently using only isSynchronizationActive() for validation.
After creating a typical API application, if you execute the code like the one in the example above when there is no transaction, the TransactionSynchronizationManager.isSynchronizationActive() will be marked as false, returning null, and not maintaining the connection.
I believe this approach is correct.
I'm curious about your thoughts on adding the following validation logic here:
else if (!TransactionSynchronizationManager.isActualTransactionActive() || !TransactionSynchronizationManager.isSynchronizationActive()) {
// Indicate that we can't obtain a transactional EntityManager.
return null;
}
Thank you!
The text was updated successfully, but these errors were encountered:
It seems like there might be a Connection Leak issue when using the NOT_SUPPORTED propagation attribute or creating a transactionless state in Spring Batch and then calling a non-transactional Repository.
The commonality is that, in both NOT_SUPPORTED and BATCH codes, TransactionSynchronizationManager has activeTransaction set to false and the ResourceMap is empty, but TransactionSynchronizationManager.isSynchronizationActive() returns true.
Looking at the example below might make it easier.
In the scenario described above, after executing the repository in TestService2::test, the connection remains in the TransactionSynchronizationManager's ResourceMap without being properly removed.
Typically, users might believe that since there is no transaction, the connection will be immediately released. However, it seems that in this case, that assumption does not hold true.
Below is an example of a Spring Batch scenario:
Even in cases like the one described, it seems that after the execution of testRepository.findByIdNoTx(), the transaction manager retains the resource in the resource map, leading to the connection not being released as expected.
The problem described above can cause an exception due to db wiat_timeout when the user creates logic that takes a long time between two repository requests (expecting no connection because there is no transaction).
The cause of the problem seems to be the entityManager creation availability branch in EntityManagerFactoryUtils.
Line 249 in EntityManagerFactoryUtils is currently using only isSynchronizationActive() for validation.
After creating a typical API application, if you execute the code like the one in the example above when there is no transaction, the TransactionSynchronizationManager.isSynchronizationActive() will be marked as false, returning null, and not maintaining the connection.
I believe this approach is correct.
I'm curious about your thoughts on adding the following validation logic here:
Thank you!
The text was updated successfully, but these errors were encountered: