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.