0
votes

I am trying to upgrade my application from spring 3.3.x to Spring 4.1. Most of the upgrade has gone smoothly but we see some strange issue with respect to Transaction propagation. We have one service layer class method annotated with @Transactional (read-only=true) calling another lower layer class method annotated with @Transactional (read-only=false) .Both of them are proxied via interfaces and the logs show the TransactionInterceptor being invoked. But when the save is called on the database we get.

"Connection is read-only. Queries leading to data modification are not allowed; "

The previous release of spring works perfectly fine as does spring 4.0.9. But once I switch to 4.1 this error is thrown . Any ideas ? I was under the impression that the transaction is modified to read-write at any point during the invocation if such an advice is hit if the current transaction was initiated as read-only and I have used this like it for a while . Below is the code of something like we are doing. We are using Hibernate 4.1 with JpaTransactionManager as our transaction manager.

public class Service1Impl implements Service1{

public Service2 service2;
@Transactional(read-only=true)
public Job processJob( Data data){
   .....
    service2.saveJob(data);
 }
}


public class Service2Impl implements Service2{

@Transactional(read-only=false)
public Job saveJob( Data data){
   .....

 }
}

Any help or suggestion is greatly appreciated

Thanks

2
It is possible that previously there was a bug and it got fixed somewhere along the line. Alternatively, a bug has been newly introduced in the 4.1 branch. It will be good if you can create a small application that demonstrates the problem and open a JIRA with the Spring team to investigate. I have seen many JIRAs relating to the use of readOnly flag with 4.1 so it is quite possible that you too have been affected by a bug of some sort.manish
Judging from your code what happens now is what I expected what h ave happened before to. If it worked you just were lucky and this probably is fixed. Or you changed something else which now makes it work properly.M. Deinum
Thanks. You were correct. It was recently fixed in 4.1 causing this to finally show up in code such as this.Venkat
Great, 4 hours later.mmm

2 Answers

1
votes

Attribute read-only does not exist. It is readOnly.

When transaction manager finds Transactional annotation all code is executed in one global transaction. Because you started readonly transaction in Service1, Transactional annotation is Service2 is ignored and no change will be commited. Use readonly flag only if you are sure, that any change will be required in underline transaction. Never use readOnly=true if you know, that annotated method will made some changes, or if it calls another service/method that is modifying data

If you want new transacton with readOnly=false in Service2 you can use this:

@Transactional(propagation=Propagation.REQUIRES_NEW)
public Job saveJob( Data data){...}

This will cause that transaction manager will always start new transaction when you enter this method. But this can cause some problems too, because if some exception occurs in this method, rollback will not be performed in transaction that started this method (int this case transaction started in Service1).

0
votes

Found out this was improved and resolved by spring in 4.1 . I posted this question on spring jira and got the reponse

https://jira.spring.io/browse/SPR-12807

Apparently this was bug opened in spring 3.x but resolved in spring 4.1. The original bug is here https://jira.spring.io/browse/SPR-8959

So its now working as desired but one can provide a custom HibernateJpaDialect and set the prepareConnection to false to default to the older behavior.

Thanks