Transactional error while commiting - java

I am trying to solve this error in Payara41 server Java EE 7, this sample works on WildFly-9 Java 7 EE and on Glassfish-3.1 Java EE 6 (without #Transactional and #TransactionalManagement)
#Stateful
#Transactional //default TxType.REQUIRED
#TransactionManagement(TransactionManagementType.BEAN)
public class ImprovementDaoImpl extends AbstractBaseDaoClass implements ImprovementDao {
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
#PersistenceContext(unitName = "pu", type = PersistenceContextType.EXTENDED)
private EntityManager em;
#Resource
private UserTransaction tx;
...
}
Here's some stacktrace, what apperas after executing tx.flush();:
javax.transaction.TransactionalException: Managed bean with Transactional annotation and TxType of REQUIRED encountered exception during commit javax.transaction.RollbackException: Transaction marked for rollback.
(...)
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
So far I've tried to use interceptor and #TransactionAttribute, but none helped...
Thanks for any advice/help! :)

I know this is old, but hopefully this helps someone out there...
Question 21363423: Throwing an application exception causes TransactionalException says
You are throwing an exception from a method whose invocation will be
intercepted at runtime and additional logic wrapped around it:
transaction management;
exception handling.
Your exception cannot transparently jump over that logic, and the
specification (probably) says a TransactionalException will be thrown,
wrapping your original exception...
Question 18888572: How do you find out what Exception caused the CDI Transaction Rollback?
Shows how to use a CDI Interceptor to catch the exceptions. I can't tell from the limited info from the OP what his/her specific issue is, but when I received this exception I has to review the WebLogic server log and found the entry where it told me a unique contraint was violated.. Time to add some interceptors...

Related

EJB with CMT when migrate from JBoss 7 to WildFly 9

I'm migrating my application from JBoss 7 to WildFly (v9.0.1) and it is not deployed because of bean transaction management error.
Caused by: javax.naming.NamingException: WFLYNAM0062: Failed to lookup env/com.component.eventmgt.EventServiceImpl/transaction [Root exception is java.lang.RuntimeException: WFLYNAM0059: Resource lookup for injection failed: java:jboss/UserTransaction]
at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:157)
at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:83)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:207)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:193)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:189)
at org.jboss.as.naming.deployment.ContextNames$BindInfo$1$1.getReference(ContextNames.java:316)
... 90 more
Caused by: java.lang.RuntimeException: WFLYNAM0059: Resource lookup for injection failed: java:jboss/UserTransaction
at org.jboss.as.naming.deployment.ContextNames$BindInfo$1$1.getReference(ContextNames.java:319)
at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:143)
... 95 more
Caused by: javax.naming.NameNotFoundException: UserTransaction [Root exception is java.lang.IllegalStateException: WFLYEJB0137: Only session and message-driven beans with bean-managed transaction demarcation are allowed to access UserTransaction]
at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:153)
at org.jboss.as.naming.ServiceBasedNamingStore.lookup(ServiceBasedNamingStore.java:83)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:207)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:193)
at org.jboss.as.naming.NamingContext.lookup(NamingContext.java:189)
at org.jboss.as.naming.deployment.ContextNames$BindInfo$1$1.getReference(ContextNames.java:316)
... 96 more
Here is the EventServiceImpl class.
#Stateless
#Remote(EventService.class)
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class EventServiceImpl implements EventService {
/**
* Logger
*/
private static Logger log = LoggerFactory.getLogger(EventService.class);
private EventTableDAO eventDao;
#PersistenceContext(unitName = "SOMF-GT")
private EntityManager entityManager;
#Resource
private UserTransaction transaction;
public List<Map> loadEvents() throws EventsException {
Configuration configurationEntry = new Configuration();
try {
Map configuration = configurationService.getConfiguration();
if (configuration != null) {
eventDao = new EventTableDAO(Event.class, entityManager, transaction);
List<Map> eventsMapList = new ArrayList();
}
}
I know that if i changed the transaction management to BMT with #TransactionManagement(TransactionManagementType.BEAN) but then the following error emerge
WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
I want to know why we have to change this in the first place ?
Any information, please !
These changes rolled out in Wildfly 8 and were (as noted below) based on standardization of the global JNDI namespace in EJB 3.1.
From the Wildfly 8 Developer Guide:
EJB 3.1 introduced a standardized global JNDI namespace and a series of related namespaces that map to the various scopes of a Java EE application. The three JNDI namespaces used for portable JNDI lookups are java:global, java:module, and java:app. If you use JNDI lookups in your application, you will need to change them to follow the new standardized JNDI namespace convention.
To conform to the new portable JNDI namespace rules, you will need to review the JNDI namespace rules and modify the application code to follow these rules.
The guide further notes:
WildFly 8 has tightened up on JNDI namespace names to provide predictable and consistent rules for every name bound in the application server and to prevent future compatibility issues. This means you might run into issues with the current namespaces in your application if they don't follow the new rules.
Here's a snippet from the table showing Examples of JNDI mappings in previous releases and how they might look now specific to the UserTransaction:
Previous Namespace New Namespaces
------------------ --------------
java:comp/UserTransaction java:comp/UserTransaction (This will not be accessible for non EE threads, e.g. Threads your application directly creates)
java:comp/UserTransaction java:jboss/UserTransaction (Globally accessible, use this if java:comp/UserTransaction is not available)
Edit re: WFLYEJB0137:
This is theory-craft and may be worthless - let me know and I'll delete it. Java EE 6 Tutorial - Container-Managed Transactions says:
Enterprise beans that use container-managed transaction demarcation also must not use the javax.transaction.UserTransaction interface.
Further:
(Transaction) Required Attribute
If the client is running within a transaction and invokes the enterprise bean’s method, the method executes within the client’s transaction. If the client is not associated with a transaction, the container starts a new transaction before running the method.
The Required attribute is the implicit transaction attribute for all enterprise bean methods running with container-managed transaction demarcation. You typically do not set the Required attribute unless you need to override another transaction attribute. Because transaction attributes are declarative, you can easily change them later.
The exception message pretty much says it all:
WFLYEJB0137: Only session and message-driven beans with bean-managed transaction demarcation are allowed to access UserTransaction
Your EJB is using container managed transaction (CMT) demarcation which does not inter-operate with bean managed transaction (BMT) demarcation wherein UserTransaction lies.
Regarding a switch to BMT and
WFLYJPA0060: Transaction is required to perform this operation (either use a transaction or extended persistence context)
I found Transaction is required to perform this operation (either use a transaction or extended persistence context) which seems to indicate that the transaction is to be managed by you, as you noted in your comments #Marco. It appears that you have made the appropriate modification.

weblogic.transaction.internal.AppSetRollbackOnlyException: setRollbackOnly called on transaction

I have the bellow case, Where I call doSomeTask() of BeanA but if doSomeTask() fails I want to persist ErrorInfo into another table as well calling the saveError(ErrorInfo) of BeanA. Both of them has #TransactionAttribute(REQUIRES_NEW).
class BeanA {
#TransactionAttribute(REQUIRES_NEW)
public void doSomeTask(){
if(someCondition){
throw new SomeException();
}
// do task
}
#TransactionAttribute(REQUIRES_NEW)
public void saveError(ErrorInfo error) {
// save error info if doSomeTask fails
}
}
class BeanB {
BeanA beanA;
void performTask(){
try{
beanA.doSomeTask();
}catch(Exception e){
ErrorInfo error = getErrorInfo(e)
beanA.saveError(error);
}
}
}
But when doSomeTask() throws Exception saveError() doesn't work and throws Exception
Caused by: weblogic.transaction.internal.AppSetRollbackOnlyException: setRollbackOnly called on transaction
What am I doing wrong and how to fix this error? Thanks in advance for any help.
Sorry, for the late answer. The problem was resolved.
The actual error was hidden. In my case, the actual error was just a JSR 303 validation error of ErrorInfo instance while persisting. Had to add
Dweblogic.transaction.allowOverrideSetRollbackReason=true
on <domain_home>/bin/setDomainEnv.sh to find out the actual error and fix it. Thanks to this answer https://stackoverflow.com/a/38584687/1563286
I have debugged the similar issue not so long ago. In my case the issue was the following:
there was a top level transaction open when the REQUIRES_NEW method is called
After exception in nested transaction commit of the top level one failed to commit as "marked as rollback only"
It turned out that through a new transaction is started the connection holder is shared on TransactionManager level. When exception is thrown inside nested transaction the connection itself is marked as rollback only. So later this is causing the issue.
I was able to resolve the issue by using the savepoints (available since JDBC 3.0). Usually savepoints are disabled in many environments/ORM by default and using them requires additional configuration.
Hope this is of some help.

How do you find out what Exception caused the CDI Transaction Rollback?

We are using CDI with CMT (container managed transactions) to connect to the database in the web app and mark methods called from the front-end that require a transaction with:
#Transactional(value=TxType.REQUIRES_NEW)
This will create a new CDI transaction, however now if an exception occurs doing this code block or any other code block called from this method it will throw the error message:
javax.transaction.TransactionalException: Managed bean with Transactional annotation and TxType of REQUIRES_NEW encountered exception during commit javax.transaction.RollbackException: Transaction marked for rollback.
...
Caused by: javax.transaction.TransactionalException: Managed bean with Transactional annotation and TxType of REQUIRES_NEW encountered exception during commit javax.transaction.RollbackException: Transaction marked for rollback.
...
Caused by: javax.transaction.RollbackException: Transaction marked for rollback.
Is there anyway to get CDI to re-throw the nested error so that you can easily debug what the real cause of the rollback was?
(Running on Java-EE7, Glassfish 4.0, JSF 2.2.2)
It seems the easiest way to do this is by using a CDI Interceptor to catch the exceptions. We can define the CDI Interceptor as follows:
#InterceptorBinding
#Target({ElementType.METHOD, ElementType.TYPE})
#Retention(RetentionPolicy.RUNTIME)
public #interface TransactionDebugger {
}
Once we have defined the CDI Interceptor, we need to create class that is executed when the Interceptor annotation is used. We define an #AroundInvoke so that our code is called before the code in the method we annotate. invocationContext.proceed() will call the method we annotate and give us the result (if any) it returned. So we can put a try, catch (Exception) around this call to catch any kind of Exception that is thrown. Then we can log this exception using the logger (log4j used here), and re-throw the Exception so that any upstream code is also informed of it.
Re-throwing the Exception will also allow us to use CMT (Container Managed Transactions) as then ultimately the container will catch the Exception and throw a transaction RollbackException. However, you could easily use UserTransactions with this also and perform a manual rollback when an exception is caught instead of re-throwing it.
#Interceptor
#TransactionDebugger
public class TransactionInterceptor {
private Logger logger = LogManager.getLogger();
#AroundInvoke
public Object runInTransaction(InvocationContext invocationContext) throws Exception {
Object result = null;
try {
result = invocationContext.proceed();
} catch (Exception e) {
logger.error("Error encountered during Transaction.", e);
throw e;
}
return result;
}
}
Next we must include our new Interceptor in our beans.xml (generally located in src/META-INF), since Interceptors are not enabled by default in CDI. This must be done in ALL projects where the annotation is used, not just the project where the annotation is defined. This is because CDI initializes Interceptors on a per project basis:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
<interceptors>
<class>package.database.TransactionInterceptor</class>
</interceptors>
</beans>
Finally, we must annotate the methods that we call with our new CDI Interceptor. Here we annotate them with #Transactional to start a transaction, and #TransactionDebugger to catch any Exception that occurs within the transaction:
#Transactional #TransactionDebugger
public void init() {
...
}
This will now log ANY error that occurs while executing the init() code. The logging granularity can be changed by changing the try, catch from Exception to a sub-class of Exception in the Interceptor implementation class TransactionInterceptor.
The TransactionalException is thrown at the commit time, i.e. after your code has been fully executed. Since the transaction is marked for rollback, commit cannot take place and the exception is thrown.
However, the transaction was marked for rollback sometime during the execution. I assume you do not mark it for rollback manually, therefore an exception must have been thrown. The exception is either a RuntimeException or it is annotated with #ApplicationException(rollback = true). Since you don't get this exception, the exception must have been caught somewhere. Are you sure you do not catch exceptions thrown from a business method in your code?
To answer the question... No, I don't think it is possible to rethrow the original exception, because it is thrown at different time and place.

EntityManager obtained from JNDI lookup is already closed

For (Glassfish v2.1), two RuntimeExceptions from two separate requests from a session bean:
"org.hibernate.SessionException: Session is closed!"
org.hibernate.SessionException: Session is closed!
at org.hibernate.impl.AbstractSessionImpl.errorIfClosed(AbstractSessionImpl.java:72)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1138)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:67)
[wrapped] javax.persistence.PersistenceException: org.hibernate.SessionException: Session is closed!
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:76)
"java.lang.IllegalStateException: EntityManager is closed"
java.lang.IllegalStateException: EntityManager is closed
at org.hibernate.ejb.EntityManagerImpl.close(EntityManagerImpl.java:97)
at com.sun.enterprise.util.QueryWrapper.clearDelegates(QueryWrapper.java:460)
at com.sun.enterprise.util.QueryWrapper.getResultList(QueryWrapper.java:198)
Both of these EntityManagers were obtained via JNDI lookup (java:comp:/env/TargetSitePersistenceContext)
Using JTA (transaction-type attribute is not defined in persistence.xml).
& SQL Server 2008 w/ sqljdbc4.jar
The code just does the ff:
query = entityManager.createQuery();
query.getResultList();
And that's it. If I'm not mistaken, I believe the app container will handle open/commit/rollback/close, so we shouldn't have any entityManager.close().
What might have caused those two runtime exceptions?
When does GF actually open/close an EntityManager?
Is there any difference between:
an EntityManager obtained via JNDI lookup
via #PersistenceContext Injection? (So far not issues with this style)
All things being equal, a #PersistenceContext injection and a JNDI lookup should return the same EntityManager. So it might be a bug of GlassFish and you might want to reach for them. But make sure to give all the context like type of session bean used for injection, transaction or not etc etc.
Mark your bean with annotation #TransactionAttribute
#Stateless
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public class Repo implements IRepo
{
container managed transaction is regulated by this parameter

EJB transaction isolation levels

Considering we have some ejb's and their transaction settings are :
ejb1 starts doing work with the Requires_New attribute and calls ejb2 which has also requires new attribute on its side.
My question is...if ejb2's transaction fails...will ejb1's transaction fail too ? I suspect not.
Any answers are welcome.
Thx.
No, it won't rollback if you catch the exception thrown by the call to ejb2.
No, ejb1 transaction will not fail as long as (assuming exception is the cause) the exception thrown from ejb2 will not be thrown from ejb1 as well. In this case it will rollback ejb1 independently.

Categories