Domanda

Not sure if somebody faced this problem. I'm using Jboss7.1 Application server with EJB3.1 and JPA2.0 with Hibernate implementation. I'm using back-end Oracle 11g database. Please see the below code. I'm invoking my EJB using a servlet driven by a HTTP GET request.

When I comment out context.setRollbackOnly() in the below code, my web page just hangs forever and I get below stack trace after a while(if I debug, it takes me till persist() method and then doesn't go anywhere).

21:56:22,765 WARN [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check timeout for TX 0:ffffc0a80005:57a36cd7:5303d0bf:30 in state RUN 21:56:22,767 WARN [com.arjuna.ats.arjuna] (Transaction Reaper Worker 2) ARJUNA012095: Abort of action id 0:ffffc0a80005:57a36cd7:5303d0bf:30 invoked while multiple threads active within it. 21:56:22,768 WARN [com.arjuna.ats.arjuna] (Transaction Reaper Worker 2) ARJUNA012108: CheckedAction::check - atomic action 0:ffffc0a80005:57a36cd7:5303d0bf:30 aborting with 1 threads active! 21:56:23,266 WARN [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check timeout for TX 0:ffffc0a80005:57a36cd7:5303d0bf:30 in state CANCEL 21:56:23,767 WARN [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012117: TransactionReaper::check timeout for TX 0:ffffc0a80005:57a36cd7:5303d0bf:30 in state CANCEL_INTERRUPTED 21:56:23,768 WARN [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012120: TransactionReaper::check worker Thread[Transaction Reaper Worker 2,5,main] not responding to interrupt when cancelling TX 0:ffffc0a80005:57a36cd7:5303d0bf:30 -- worker marked as zombie and TX scheduled for mark-as-rollback 21:56:23,770 WARN [com.arjuna.ats.arjuna] (Transaction Reaper) ARJUNA012110: TransactionReaper::check successfuly marked TX 0:ffffc0a80005:57a36cd7:5303d0bf:30 as rollback only

With context.setRollbackOnly() uncommented, then page loads, but there is no record in the back-end table. The same code works intermittently. I can't figure out the actual pattern of when it works!! Can anyone throw some light?

My EJB code is below -

import javax.annotation.Resource;
import javax.annotation.security.DeclareRoles;
import javax.annotation.security.RolesAllowed;
import javax.ejb.Local;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;


@Stateless
@Local(DepartmentLocal.class)
@TransactionManagement(TransactionManagementType.CONTAINER)
@DeclareRoles({"Admin", "Guest"})
public class DepartmentBean{

@Resource
private SessionContext context;

@PersistenceContext(unitName="department-pu")
private EntityManager em;



@TransactionAttribute(TransactionAttributeType.REQUIRED)
@RolesAllowed({"Admin"})
public long addDepartment(Department dep){

    em.persist(dep);        

    //context.setRollbackOnly();
    return dep.getDepartmentId();
}

}

UPDATED:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="DEPARTMENTS")
public class Department {
 @Id
 @Column(name="DEPARTMENT_ID")
 private long departmentId;

@Column(name="DEPARTMENT_NAME")
private String departmentName;

@Column(name="MANAGER_ID")
private long managerId;

@Column(name="LOCATION_ID")
private long locationId;

public long getDepartmentId() {
    return departmentId;
}

public void setDepartmentId(long departmentId) {
    this.departmentId = departmentId;
}

public String getDepartmentName() {
    return departmentName;
}

public void setDepartmentName(String departmentName) {
    this.departmentName = departmentName;
}

public long getManagerId() {
    return managerId;
}

public void setManagerId(long managerId) {
    this.managerId = managerId;
}

public long getLocationId() {
    return locationId;
}

public void setLocationId(long locationId) {
    this.locationId = locationId;
}


}

META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="department-pu" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:jboss/datasources/OracleDS</jta-data-source>
    <class>Department</class>       
    <properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
        <property name="show_sql" value="false"/>
    </properties>
</persistence-unit>

In standalone-full.xml

   <datasources>
       ...
       <datasource jta="true" jndi-name="java:jboss/datasources/OracleDS" pool-name="OjdbcPool" enabled="true" use-java-context="true">
                <connection-url>jdbc:oracle:thin:@localhost:1521:xe</connection-url>
                <driver>ojdbc</driver>
                <pool>
                    <min-pool-size>10</min-pool-size>
                    <max-pool-size>20</max-pool-size>
                    <prefill>true</prefill>
                </pool>
                <security>
                    <user-name>xxx</user-name>
                    <password>xxx</password>
                </security>
            </datasource>
            <drivers>
                <driver name="ojdbc" module="oracle.jdbc">
                    <xa-datasource-class>oracle.jdbc.OracleDriver</xa-datasource-class>
                </driver>
            </drivers>

   </datasources>
È stato utile?

Soluzione

At persist() there is a lock over the table/row (well, that is configurable), and for some reason the Tx can not be rollback because of that... until the timeout arrives.

How looks the Department entity?, match correctly to the table?, and how is the generated sql insert by the ORM?

At least the EJB code looks ok and if you are sure that the entity correctly maps the table, you can focus at database/ORM with its locks.

Option: Sometimes instead of setRollback, I would suggest to throw a runtimeException (IllegalStateException, IllegalArgumentException or a custom), the container will mark automatically for rollback the Tx (and exit as soon as possible from the method), this would make your code more expressive .

Altri suggerimenti

The problem is that this a XA datasource definition, to which a non XA driver is being passed.

XA datasources allows to participate in multi-resource transactions, for example it's possible to do transactions that span tables on two databases.

See here for an Oracle example of setting up and XA datasource, you will need namelly oracle.jdbc.xa.client.OracleXADataSource.

XA transactions work with a two-phase commit protocol, where all participants vote to see if a transaction is "commitable", and only on a second step actually do the commit (or rollback).

It seems here that the JTA transaction manager is hanging waiting for the commit confirmation, but never receives it because the datasource used in not an XA datasource, so it's not aware of the two phase commit protocol.

As a solution, if you don't need XA because multi-resource transactions are not a requirement, then it's a matter of making the datasource non-XA - for example a local-tx-datasource.

Otherwise id the datasource needs to be XA then follow the link above for further details on configuring XA datasources.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top