I have two beans: FirstBean and SecondBean.
FirstBean have method method1 with REQUIRED transaction attribute, SecondBean have method method2 with NOT_SUPPORTED transaction attribute.
method1 invokes method2.
#Stateless
class FirstBean implement IFirstBean
{
ISecondBean secondBean;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
void method1()
{
//...
secondBean.method2()
//...
}
}
#Stateless
class SecondBean implement ISecondBean
{
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
void method2()
{
//....
}
}
and it works well.
But when method2 worked for a long time (more then 4-5 min) I get exception on JBoss 4 server
Caused by: java.lang.IllegalStateException: [com.arjuna.ats.internal.jta.transaction.arjunacore.inactive] [com.arjuna.ats.internal.jta.transaction.arjunacore.inactive] The transaction is not active!
at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.java:1379)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:135)
and next on WebLogic 10.3
Caused By: org.hibernate.SessionException: Session is closed!
at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:49)
at org.hibernate.impl.SessionImpl.clear(SessionImpl.java:253)
method1 is finished and exception is thrown after
To be honest I would defer any transactional work until all the non-transactional tasks were completed. Easily done by creating a non-transactional 'wrapper' method:
class FirstBean implements IFirstBean {
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void overlordMethod() {
secondBean.method2();
method1();
}
}
This prevents the long running method for which no transaction is required from causing issues in the method that needs one. Now, five minutes for a method to complete is alot, but assuming that there is no improvements to be made in the runtime, and that you for some reason cannot reorder your method calls, then you can always increase the transaction timeout for your JTA. Read here for a variety of ways to do this on JBoss 4.
In JBoss 4.x using JTA transactions, the default timeout is 5 minutes. You are most likely exceeding the timeout for the transaction in progress when "method 1" was invoked because the elapsed time is being incremented while "method 1"'s transaction has been suspended while executing "method 2". You can confirm this by increasing the timeout to a very large value - JBoss has a TransactionTimeout attribute that you can annotate "method 1" with.
One non-obvious thing to remember is that when a transaction is suspended, it doesn't mean that the transactional timer is stopped.
I use next constraction at the end.
#Stateless
class FirstBean implement IFirstBean
{
ISecondBean secondBean;
#TransactionAttribute(TransactionAttributeType.REQUIRED)
void firstPartOfmethod1()
{
//...
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
void secondPartOfmethod1()
{
//...
}
}
#Stateless
class SecondBean implement ISecondBean
{
#TransactionAttribute(TransactionAttributeType.NEVER)
void method2()
{
//....
}
}
#Stateless
class MainBean implement ISecondBean
{
#TransactionAttribute(TransactionAttributeType.NEVER)
void mainMethod()
{
firstBean.firstPartOfMethod1();
secondBean.method2();
firstBean.secondPartOfMethod1();
//....
}
}
Related
I am working on a spring boot app where I am using transactional and its not rolling back its changes when I throw a exception:
My method:
private BtoBWalletTransactionResponseModel doWalletOperation(BtoBWalletTransactionTypes transactionType, BtoBWalletTransactionRequestModel transactionRequest) {
// DB Operation
BtoBWalletTransaction savedTransaction = commonTransactionalService.finishWalletTransaction(userWallet, btoBWalletTransaction);
log.info("wallet {} txn of amount {} for user {}",transactionType.name(),txnAmount,userId);
// throwing a exception to rollback
throw new RuntimeException("Time to Rollback");
} catch(Exception e){
log.error(e.getMessage());
log.error("error while doing wallet operations for user {}",userId);
throw new WalletException(e.getMessage());
}
}
My common TransactionalService Interface:
public interface CommonTransactionalService {
BtoBWalletTransaction finishWalletTransaction(BtoBUserWallet userWallet,BtoBWalletTransaction btoBWalletTransaction);
}
My Interface Impl:
import javax.transaction.Transactional;
#Service
public class CommonTransactionalServiceImpl implements CommonTransactionalService {
#Autowired
private BtoBWalletTransactionRepo btoBWalletTransactionRepo;
#Transactional
#Override
public BtoBWalletTransaction finishWalletTransaction(BtoBUserWallet userWallet, BtoBWalletTransaction walletTransaction) {
BtoBWalletTransaction savedTransaction = btoBWalletTransactionRepo.save(walletTransaction);
btoBUserWalletRepo.save(userWallet);
return savedTransaction;
}
}
Now even when I am sending a RuntimeException the DB record is not getting rolled back.
Can someone help? stuck since hours here.
Transactional is scoped, if you anotate a method (or class) as #Transactional all the methods this class calls wil also be transactional. and if within this transaction an exception occurs things wil be rolled back.
If however like in you example a non-transactional method calls a transactional one and after that call throws an exception the previous transactioned function wil not be rolled back as it's outside of the transactions scope.
I am facing a problem due which is unknown to me, can you one have faced this problem?
JSON mapping problem: <package>ApiResponse["data"]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: possible non-threadsafe access to the session (through reference chain: <package>.ApiResponse["data"])
I have a standard API response pojo. Which I return every time with ResponseEntity. Everything is working fine, but sometimes I got that above error. I don't why this error occurred .
I got the below log from console
an assertion failure occurred (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: possible non-threadsafe access to the session
org.hibernate.AssertionFailure: possible non-threadsafe access to the session
I think you are trying to share same Hibernate session within multiple threads. That's illegal.
Hibernate Sessions are not thread-safe whereas Hibernate SessionFactory is thread-safe.
So, make a separate DAO layer. Create single sessionfactory object and share it among the DAO classes.
Get a session for a single-threaded DB operation and close the session in that thread.
For example :
#Repository
public class DAO {
#Autowired
private SessionFactory sessionFactory;
public class performDBOperation(Object obj) {
Session session = sessionFactory.currentSession();
session.save(obj);
session.close();
}
}
Now, I have looked at your github code.
I saw the code Exec.java
#Service
public interface Exec {
#Async
#Transactional
public void run();
}
This is incorrect.
Updated :
public interface Exec {
public void run();
}
Update ExecImpl to this :
#Service
public class ExecImpl implements Exec {
#Autowired
private ExecDAO execDAO;
#Override
#Async
#Transactional
public void run() {
// example : create an object to save it.
Object object = ...;
execDAO.saveItem(object);
}
}
Create DAO layer :
Suppose ExecDAO interface and implementation ExecDAOImpl :
public interface ExecDAO {
public void saveItem(Object obj);
// keep here abstract method to perform DB operation
}
#Repository
public class ExecDAOImpl implements ExecDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void saveItem(Object obj) {
Session session = sessionFactory.currentSession();
session.save(obj);
session.close();
}
}
Looking at the code at the link you shared in the comment, I think that
#Async
#Transactional
is a dangerous thing.
I would suggest you to extract a method to do the transactions and try
what I mean is that,
interface ExecImpl{
#Async
void run(){
someThingElse.doTransaction();
}
}
interface SomeThingElse{
#Transactional
void doTransaction();
}
I am still not convinced this will help you. But this is something you can try.
I would also suggest to use readonly transactions for getting data and not have a single transaction for all purposes.
This blog explains why its not good to use these two annotations together whether on a class or on an interface
Consider the following situation:
We receive a request from a web service which updates our entity. Sometimes we might get two requests at (almost) the same time. We had situations in which our entity looked completely wrong, because of concurrent updates. The idea is to lock the entity pessimistic so that whenever the first request comes it instantly locks the entity and the second request can't touch it (Optimistic locking is no alternative for us). I wrote an integration test to check this behaviour.
I got an integration test which looks like the following:
protected static TestRemoteFacade testFacade;
#BeforeClass
public static void setup() {
testFacade = BeanLocator.lookupRemote(TestRemoteFacade.class, TestRemoteFacade.REMOTE_JNDI_NAME, TestRemoteFacade.NAMESPACE);
}
#Test
public void testPessimisticLock() throws Exception {
testFacade.readPessimisticTwice();
}
which calls the bean
#Stateless
#Clustered
#SecurityDomain("myDomain")
#RolesAllowed({ Roles.ACCESS })
public class TestFacadeBean extends FacadeBean implements TestRemoteFacade {
#EJB
private FiolaProduktLocalFacade produkt;
#Override
public void readPessimisticTwice() {
produkt.readPessimisticTwice();
}
}
with produkt being a bean itself
#Stateless
#Clustered
#SecurityDomain("myDomain")
#RolesAllowed({ Roles.ACCESS })
public class ProduktFacadeBean implements ProduktLocalFacade {
#Override
public void readPessimisticTwice() {
EntityManager entityManager = MyService.getCrudService().getEntityManager();
System.out.println("Before first try.");
entityManager.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE);
System.out.println("Before second try.");
entityManager.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE);
System.out.println("After second try.");
}
}
with
public class MyService {
public static CrudServiceLocalFacade getCrudService() {
return CrudServiceLookup.getCrudService();
}
}
public final class CrudServiceLookup {
private static CrudServiceLocalFacade crudService;
private CrudServiceLookup(){
}
public static CrudServiceLocalFacade getCrudService() {
if (crudService == null)
crudService = BeanLocator.lookup(CrudServiceLocalFacade.class, CrudServiceLocalFacade.LOCAL_JNDI_NAME);
return crudService;
}
public static void setCrudService(CrudServiceLocalFacade crudService) {
CrudServiceLookup.crudService = crudService;
}
}
#Stateless
#Local(CrudServiceLocalFacade.class)
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Interceptors(OracleDataBaseInterceptor.class)
public class CrudServiceFacadeBean implements CrudServiceLocalFacade {
private EntityManager em;
#Override
#PersistenceContext(unitName = "persistence_unit")
public void setEntityManager(EntityManager entityManager) {
em = entityManager;
}
#Override
public EntityManager getEntityManager() {
return em;
}
}
The problem that arises now is: If I start the integration test once with a breakpoint at System.out.println("Before second try."); and then start the integration test a second time, the latter one can still read MyEntity. Remarkable is that they were different instances (I made this observation on the instanceId in debug mode). This suggests that the entityManager didn't share his hibernate context.
I made the following observations:
Whenever I call a setter on entity and save it to the db, the lock is aquired. But this is not what I need. I need the lock without having modified the entity.
I tried the method entityManager.lock(entity, LockModeType.PESSIMISTIC_WRITE) as well, but the behaviour was the same.
I found Transaction settings in DBVisualizer. At the moment it is set to TRANSACTION_NONE. I tried all the others (TRANSACTION_READ_UNCOMMITTED, TRANSACTION_READ_COMMITTED, TRANSACTION_REPEATABLE_READ, TRANSACTION_SERIALIZABLE) as well, without any success.
Let the first thread read the entity, then the second thread read the same entity. Let the first tread modify the entity and then the second modify it. Then let both save the entity and whoever saves the entity last wins and no exceptions will be thrown.
How can I read an object pessimistic, that means: Whenever I load an entity from the db I want it to be locked immediately (even if there was no modification).
Both ways you describe ie.
em.find(MyEntity.class, 1, LockModeType.PESSIMISTIC_WRITE)
em.lock(entity, LockModeType.PESSIMISTIC_WRITE)
hold a lock on the related row in database but only for the the entityManager lifespan, ie. for the time of the enclosing transaction, the lock will be so automatically released once you've reached the end of the transaction
#Transactional()
public void doSomething() {
em.lock(entity, LockModeType.PESSIMISTIC_WRITE); // entity is locked
// any other thread trying to update the entity until this method finishes will raise an error
}
...
object.doSomething();
object.doSomethingElse(); // lock is already released here
Have you tried to set the isolation level in your application server?
To get a lock on a row no matter what you are trying to do afterwards (read/write), you need to set the isolation level to TRANSACTION_SERIALIZABLE.
Lock fails only if another thread is already holding the lock. You can take two FOR UPDATE locks on single row in DB, so it's not JPA-specific thing.
I have a transaction like below,
#Transactional
public void changeJobStatus(Long jobId){
JobEntity jobEntity = jobRepository.findOneForUpdate(jobId);
...
}
And findOneForUpdate is to lookup database with pessimistic lock,
public interface JobRepository extends CrudRepository<JobEntity, Long>{
#Lock(LockModeType.PESSIMISTIC_WRITE)
#Query("select j from JobEntity j where j.id = :id")
JobEntity findOneForUpdate(#Param("id") Long id);
}
This works well, if I call changeJobStatus normally.
But when calling in a TimerTask like below,
TimerTask task = new TimerTask() {
#Override
public void run() {
changeJobStatus(jobId);
}
};
timer.schedule(task, waitTime);
there would be an exception:
javax.persistence.TransactionRequiredException: no transaction is in progress
Why this happens? And if there is a way to call transaction in a TimerTask?
The call to changeJobStatus() is effectively direct to your bean (self-invocation), and therefore not subject to the usual Spring proxying when calling between beans. For this reason no transaction is getting started.
See: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-declarative-annotations search for "self-invocation".
There may be several potential ways to approach this:
You could auto-wire a reference to your own bean, which would be fulfilled with a proxy, and call thru that;
You could use mode="aspectj", which performs bytecode weaving (enhancement).
You could control the transaction manually via PlatformTransactionManager;
My approach would depend on whether this is isolated, or a common case. If common, I'd investigate "aspectj" mode; but I would probably hope that it were an outlier and I could stick to the standard Spring "proxy" mode.
This is caused by Spring's AOP limitation. As Thomas has suggested, controlling transaction manually can solve this problem, rather than using #Transactional. Here is the detail implementation,
I have created an simple transaction service like below,
#Service
public class SimpleTransactionService {
private final TransactionTemplate transactionTemplate;
#Autowired
public SimpleTransactionService(PlatformTransactionManager transactionManager){
transactionTemplate = new TransactionTemplate(transactionManager);
}
public void executeTransaction(ITransactionService task){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
task.transactionExecute();
}
});
}
}
ITransactionService is just an simple interface with one method,
public interface ITransactionService {
void transactionExecute();
}
Here is how I use above in my TimerTask,
public void addTimerTask(Object param, Long waitTime){
TimerTask task = new TimerTask() {
#Override
public void run() {
simpleTransactionService.executeTransaction(() -> someOperation(param));
}
};
timer.schedule(task, waitTime);
}
someOperation is the actual transaction executed. With the simple transaction service and a lambda, transaction can be done without any annotation.
Given this example code:
public class MyServiceImpl implements MyService {
#Transactional
public void myTransactionalMethod() {
List<Item> itemList = itemService.findItems();
for (Item anItem : itemList) {
try {
processItem(anItem);
catch (Exception e) {
// dont rollback here
// rollback just one item
}
}
}
#Transactional
public void processItem(Item anItem) {
anItem.setSomething(new Something);
anItem.applyBehaviour();
itemService.save(anItem);
}
}
Here is what I want to achieve:
Only processItem(anItem); should rollback if exception occurs inside it.
If exception occurs, myTransactionalMethod should continue, that means the for-each should end.
If exception occurs inside myTransactionalMethod but not in processItem(anItem), myTransactionalMethod should rollback completely.
Is there a solution that doesn't involve managing transactions manually (without annotations)?.
Edit: I was thinking of using #Transactional(PROPAGATION=REQUIRES_NEW), don't know if it will work within the same bean though.
This is a common misunderstanding. Spring Transactions are implemented through proxies. Proxies are a wrapper around your class. You are accessing the processItem method from the same class, i.e. you don't go through the proxy, so you don't get any transactions. I explained the mechanism in this answer some years ago.
Solution: you need two separate Spring beans if you want nested transactions, both of them must be proxied by #Transactional.
It looks like a case for NESTED transaction. NESTED transaction starts a subtransaction with in the outer transaction with savepoint, allowing it rollback to that savepoint. Since it is a nested transactions they committed at the end of outer transation.
public class MyServiceImpl implements MyService {
#Transactional
public void myTransactionalMethod() {
List<Item> itemList = itemService.findItems();
for (Item anItem : itemList) {
try {
// If you want to call this method directly configure your transaction use to aspectJ for transaction handling or refactor the code. Refer - [http://stackoverflow.com/questions/3423972/spring-transaction-method-call-by-the-method-within-the-same-class-does-not-wo][1]
processItem(anItem);
catch (Exception e) {
// dont rollback here
// rollback just one item
}
}
}
#Transactional(PROPAGATION = PROPAGATION.NESTED)
// Throw some runtime exception to rollback or some checkedException with rollbackFor attribute set in the above annotation
public void processItem(Item anItem) {
anItem.setSomething(new Something);
anItem.applyBehaviour();
itemService.save(anItem);
}
}
Note that, I have not yet tried this below code see if that helps. You might have to tweak it, if needed. In fact I would love to give this code a try myself sometime soon.