Let's say I have a rest call which creates some object "A" in the database. Method is marked with #Transactional annotation. And just after creation I need to launch another asynchronous process in another thread or through some messaging system or in some other async way. That new process depends on the object "A" and needs to see it.
How can I make sure that transaction is commited before new process starts execution?
For example in Spring there is
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
void afterCommit(){
//do what you want to do after commit
}
})
Does Quarkus has something similar?
You can inject TransactionManager
#Inject
TransactionManager transactionManager;
and do
Transaction transaction = transactionManager.getTransaction();
transaction.registerSynchronization(new Synchronization() {
#Override
public void beforeCompletion() {
//nothing here
}
#Override
public void afterCompletion(int status) {
//do some code after completion
}
});
Related
I need to write a method which is being called from a open transaction & will never rollback, even though exception occurs in the system. I used Propagation.NEVER to achieve this, Is it fine, or I should use PROPAGATION_NOT_SUPPORTED?
#Autowired
private PartnerTransactionService partnerTransactionService;
#PostConstruct
#Transactional
private void test(AuditDTO<Object> audit){
partnerTransactionService.saveAudits(audit);
partnerTransactionService.nonTrasactionsalSaveAudits(audit);
throw new NullPointerException();
}
In some other service class(both are spring managed bean ie sprinf proxy is being created for both)-
public <T> void saveAudits(AuditDTO<T> audit){
if(audit!=null){
PartnerTransaction partnerTransaction=new PartnerTransaction(audit);
partnerTransactionRepository.save(partnerTransaction);
}
}
#Transactional(propagation = Propagation.NEVER)
public <T> void nonTrasactionsalSaveAudits(AuditDTO<T> audit){
if(audit!=null){
PartnerTransaction partnerTransaction=new PartnerTransaction(audit);
partnerTransactionRepository.save(partnerTransaction);
}
}
I throws a NPE to check my code , I found both the data being save irrespective of exception, non being rollback, what I am missing?
I had written rest services in spring that is running perfectly fine.
Now, I need to add perform some db transactions before returning response to user.
This db transaction is independent to response retrieved.
For example,
#PostMapping("login")
public TransactionResponse loginAuthentication(#Valid #RequestBody LoginRequestBody loginRequest) {
TransactionResponse transactionResponse = new TransactionResponse();
try {
transactionResponse = loginService.validateUser(loginRequest);
//independent transaction needs to be executed in a separate thread
loginSerice.addLoginLog(transactionResponse);
//return below response without waiting to compelete above log transaction
return transactionResponse;
}
catch (Exception e) {
return CommonUtils.setErrorResponse(transactionResponse, e);
}
}
I read upon async controller in spring mvc link. Although controller
executes respective functionality in a separate thread but I don't want to wait for db transaction to be completed. After getting response from service layer, it should be forwarded to user without any delay.
Any Suggestions !!
Spring version is 4.3
I posted this answer to help the fellow developers with same kind of requirement (to execute a void function in a separate thread).
Since I am not experienced in multithreading/asynchronous environment, I want to keep it simple by using spring asynchronous methods.
So, First I created the Thread Pool
#Configuration
#EnableAsync
public class ThreadConfig {
#Bean
public TaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(4);
executor.setThreadNamePrefix("WEBAPP");
executor.initialize();
return executor;
}
}
Then I created a service that will execute my code in a separate thread.
#Async
#Service
#Transactional
public class LoggingService {
public void logintransaction() throws Exception{
System.out.println("start login loggin");
Thread.sleep(5000);
System.out.println("exit");
}
}
Lastly, I called the above service on my controller. As I can see Total Time Taken is printed first, then "start login loggin" is printed. This means my new method is executed in a new thread.
#Autowired
private LoggingService loggingService;
#PostMapping("login")
public TransactionResponse loginAuthentication(#Valid #RequestBody LoginRequestBody loginRequest) {
long startTime = System.currentTimeMillis();
TransactionResponse transactionResponse = new TransactionResponse();
try {
transactionResponse = loginService.validateUser(loginRequest);
//independent transaction needs to be executed in a separate thread
//loginSerice.addLoginLog(transactionResponse);
loggingService.logintransaction();
//return below response without waiting to compelete above log transaction
System.err.println("Total Time Taken=>"+(System.currentTimeMillis() - startTime));
return transactionResponse;
}
catch (Exception e) {
return CommonUtils.setErrorResponse(transactionResponse, e);
}
}
Thanks
we are using spring boot 2, and in our integration tests we need manually execute some code in transaction, and on the end of transaction and after asserts, we want rollback that transaction.
We are using explicit defined transactions instead of #Transactional because sometimes we need execute in test 2 transactions.
here is sample of test:
#Test
public void fooTest() {
// transaction 1
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// some code in transaction
}
// transaction 2
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// some code in transaction
}
// here I need rollback these transactions for clean db for another tests
}
can you tell me how to use rollback in our case to rollback both transactions? It is little older code which we maintain so if it possible to do it better in boot 2 I will be gratefull for any advice. We just have to execute 2 transactions in one test.
Store references to each TransactionStatus in AtomicReference and rollback them with transaction manager after the test.
#Test
void test() {
final AtomicReference<TransactionStatus> first = new AtomicReference<>();
final AtomicReference<TransactionStatus> second = new AtomicReference<>();
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// some code in transaction
first.set(status);
}
});
// transaction 2
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
// some code in transaction
second.set(status);
}
});
transactionTemplate.getTransactionManager().rollback(first.get());
transactionTemplate.getTransactionManager().rollback(second.get());
}
If you really need to start two transactions that run independently, doing some work on each one, and you need to check some asserts after they have both run, but before either has committed or rolled back - and then need to commit or rollback both after the asserts, you would need to set up your own multithreaded structure... Something like:
execute(AssertCallback aC, TransactionCallback ... tCs);
This method would start a thread for each of the tCs. Each thread would call the callback method in each one, and on return block on a barrier until all the threads executing tCs get to that same point. The main thread would also be waiting for all the tC threads to block, and then it would run the aC callback, and when that returns, release all the tC threads so they can commit/rollback and exit.
It all seems a little weird, in that the aC callback could not "see" any of the work done by any of the tC callbacks, since that's in transactions that have not been committed yet.
I've never seen this implemented... But, in case you want to see what I was talking about, take a look at the parallel-test project here: https://github.com/moilejter/examples.git
I have a situation in Spring where I am writing data to some external source,
Now before writing the data to the external source,
i take a lock
read the object
perform some operation
write the oject back. and unlock the object.
Below piece of code explaing roughly how i do it.
//Code begins here
Lock lck = new ReentrantLock();
public void manipulateData(){
lck.lock();
//Object obj = read the data
//modify it
Write(obj)
lck.unlock();
}
//Code End here
Now in a multi-threaded environment what currently happens is after write call I am calling unlock but my transaction is not committed until my function execution completes. However since I am calling unlock. Other thread gets the lock and read the data which is actually in correct.
So I want something like the lock should be obtained by other thread only when the transaction commit.
Also I cannot use programmatic transaction.
You can consider extracting the code that reads the object and modifies it to a different method (annotated with #Transactional). The lock should then be taken just before invoking the method and released after the method returns. Something like this:
#Autowired
private Dao dao;
public void manipulateData(){
lck.lock();
dao.update(myObj);
lck.unlock();
}
class Dao {
#Transactional
public void update(MyObject obj) {
//read and modify
}
}
You can implement an Aspect (AOP) similar to this:
First create a proprietary Transactional similar to this:
#Target({ ElementType.METHOD })
#Retention(RetentionPolicy.RUNTIME)
public #interface LockingTransactional {
}
Then the aspect's interesting code should be similar to this:
...
private final Lock lck = new ReentrantLock();
...
#Around("#annotation(<FULL-PACKAGE-NAME-HERE>.LockingTransactional)")
public Object intercept(ProceedingJoinPoint pjp) throws Throwable {
try {
lck.lock();
TransactionStatus status = createTransaction(); // create the transaction "manually"
Object result;
try {
result = pjp.proceed();
} catch (Throwable t) {
txManager.rollback(status);
throw t;
}
txManager.commit(status);
return result;
} finally {
lck.unlock();
}
}
...
private TransactionStatus createTransaction() {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
def.setIsolationLevel(<YOUR-LEVEL-HERE>);
def.setPropagationBehavior(<YOUR-PROPAGATION-HERE>);
return txManager.getTransaction(definition);
}
...
I'm using Spring 2.5 transaction management and I have the following set-up:
Bean1
#Transactional(noRollbackFor = { Exception.class })
public void execute() {
try {
bean2.execute();
} catch (Exception e) {
// persist failure in database (so the transaction shouldn't fail)
// the exception is not re-thrown
}
}
Bean2
#Transactional
public void execute() {
// do something which throws a RuntimeException
}
The failure is never persisted into DB from Bean1 because the whole transaction is rolled back.
I don't want to add noRollbackFor in Bean2 because it's used in a lot of places which don't have logic to handle runtime exceptions properly.
Is there a way to avoid my transaction to be rolled back only when Bean2.execute() is called from Bean1?
Otherwise, I guess my best option is to persist my failure within a new transaction? Anything else clean I can do?
This is one of the caveats of annotations... your class is not reusable!
If you'd configure your transactions in the XML, if would have been possible.
Assuming you use XML configuration: if it's not consuming expensive resources, you can create another instance of bean2 for the use of the code you specified. That is, you can configure one been as you specified above, and one with no roll back for exception.