简体   繁体   中英

JPA JBoss transactions not committed

EDIT - Updated persistence.xml to use JTA data source defined in Jboss and still not working.

I'm not using spring, just JPA and EJB and REST.

My transaction is not being committed, even though I'm annotating with @Transactional .

Here is my persistence.xml:

    <persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">
    <persistence-unit name="apppu-sqlite" transaction-type="JTA">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <class>net.mikeski.pro.entities.Asset</class>
        <class>net.mikeski.pro.entities.Tag</class>
        <properties>
            <property name="jta-data-source" value="java:jboss/datasources/ExampleDS"/>
            <property name="hibernate.hbm2ddl.auto" value="create"/>
            <property name="hibernate.show_sql" value="true"></property>
            <property name="hibernate.format_sql" value="true"></property>
        </properties>
    </persistence-unit>
</persistence>

Here is my REST class:

@Stateless
@Path("1.0")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class RestEndpoint {
    @PersistenceContext(name="apppu-sqlite")
    protected EntityManager entityManager;

    @EJB
    AssetDaoEJB assetDao;

    @EJB
    TagDaoEJB tagDao;

    @PUT
    @Path("tags")
    @Transactional
    public Tag addTag(@Valid Tag t){
        tagDao.persist(t);
        return t;
    }

    @GET
    @Path("tags")
    public List<Asset> getAllTags(){
        return assetDao.findAll();
    }
    @GET
    @Path("assets")
    public List<Asset> getAllAssets(){
        return assetDao.findAll();
    }

    @GET
    public String getTest(){
        System.err.println("Entity Manager: " + entityManager);
        System.err.println("Asset Dao: " + assetDao);
        return "[1, 2, 3, 4]";
    }
}

Here is my DAO:

public abstract class GenericEntityDao<E extends BaseEntity> {
    protected Class entityClass;

    protected abstract EntityManager getEntityManager();
    protected abstract boolean isResourceLocalTransaction();

    public GenericEntityDao(Class c) {
        this.entityClass = c;
    }

    @Transactional
    public void persist(E entity) {
        if(isResourceLocalTransaction()){
            getEntityManager().getTransaction().begin();
        }
        getEntityManager().persist(entity);
        if(isResourceLocalTransaction()) {
            getEntityManager().getTransaction().commit();
        }
    }

    public void remove(E entity) {
        if(isResourceLocalTransaction()){
            getEntityManager().getTransaction().begin();
        }
        getEntityManager().remove(entity);
        if(isResourceLocalTransaction()) {
            getEntityManager().getTransaction().commit();
        }
    }

    public E findById(String id) { return (E)getEntityManager().find(entityClass, id); }

    public List<E> findAll(){
        Query q = getEntityManager().createQuery(
                "SELECT e FROM " + entityClass.getName() + " e");
        return (List) q.getResultList();
    }
}

Here is my Implementation:

@Stateless
public class TagDaoEJB extends GenericEntityDao<Tag> {
    @PersistenceContext(name="apppu-sqlite")
    protected EntityManager entityManager;

    public TagDaoEJB() {
        super(Tag.class);
    }

    @Override
    protected EntityManager getEntityManager() {
        return entityManager;
    }

    @Override
    protected boolean isResourceLocalTransaction() {
        return false;
    }
}

With SQL logging on, I can see Hibernate run the query. However, when I then try the GET REST endpiont, I get an empty array.

Why? It looks like the transaction is not being managed by the container.
I don't understand.

EDIT:

I changed the persistence.xml to use a defined datasource from JBOSS, here is the source:

 <subsystem xmlns="urn:jboss:domain:datasources:4.0">
            <datasources>
                <datasource jta="true" jndi-name="java:jboss/datasources/ExampleDS" pool-name="ExampleDS" enabled="true" use-java-context="true">
                    <connection-url>jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE</connection-url>
                    <driver>h2</driver>
                    <security>
                        <user-name>sa</user-name>
                        <password>sa</password>
                    </security>
                </datasource>
                <drivers>
                    <driver name="h2" module="com.h2database.h2">
                        <xa-datasource-class>org.h2.jdbcx.JdbcDataSource</xa-datasource-class>
                    </driver>
                </drivers>
            </datasources>
        </subsystem>

Still same thing, why are the transactions not working now? I even explicitly set JTA even though it shows true by default in the JBoss console.

What's the problem?

I'm not using spring, just JPA and EJB and REST. My transaction is not being committed, even though I'm annotating with @Transactional.

As far as I know, @Transactional is not an EJB annotation for transaction management. The normal case is that the container manages the transactions if you don't specify to use bean managed transaction management. In the case of container managed transaction the container manages transactions automatically. It starts a transaction before it invokes any business method and commits before it exits the method. So, in normal case you don't need to do anything because the defaults will apply.

If you want to change the default behavior you can use @TransactionAttribute annotation and set the required transaction behavior by using TransactionAttributeType enum. This annotation can be used either on class level where it applies for all business methods or on individual business methods.

The problem you are facing might have to do with your JPA setting. You are using JTA as the transaction type in your persistence.xml . So I better quote a section of JPA 2.0 specification as follows so that you can see what is expected:

8.2.1.2 transaction-type

The transaction-type attribute is used to specify whether the entity managers provided by the entity manager factory for the persistence unit must be JTA entity managers or resource-local entity managers. The value of this element is JTA or RESOURCE_LOCAL. A transaction-type of JTA assumes that a JTA data source will be provided either as specified by the jta-data-source element or provided by the container.

As you can see from the spec (bold marked), a datasource is expected but you haven't provided one; instead you are setting connection properties which are intended for Java SE environment as the following extracts from the JPA 2.0 spec shows:

The following properties defined by this specification are intended for use in Java SE environments.

• javax.persistence.jdbc.driver — fully qualified name of the driver class

• javax.persistence.jdbc.url — driver-specific URL

• javax.persistence.jdbc.user — username used by database connection

• javax.persistence.jdbc.password — password for database connection validation

So you have to define a datasource for your DB in JBoss and specify this in the persistence.xml .

I think the problem might be associated with the SQLite driver which might not support distributed transactions used in JTA.

Nevertheless, when using JTA, rather than specifying JDBC driver you should create data source in JBoss server and add its JNDI name in persistence.xml file as jta-data-source .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM