JPA JBoss交易没有提交

时间:2016-07-29 02:11:43

标签: java hibernate jpa jboss

编辑 - 更新了persistence.xml以使用Jboss中定义的JTA数据源但仍无法正常工作。

使用spring,只使用JPA,EJB和REST。

我的交易未提交,即使我正在使用@Transactional进行注释。

这是我的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>

这是我的REST课程:

@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]";
    }
}

这是我的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();
    }
}

这是我的实施:

@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;
    }
}

通过SQL登录,我可以看到Hibernate运行查询。但是,当我尝试GET REST endpiont时,我得到一个空数组。

为什么呢?看起来交易不是由集装箱管理的 我不明白。

编辑:

我更改了persistence.xml以使用来自JBOSS的已定义数据源,这里是源:

 <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>

同样的事情,为什么交易现在不起作用?我甚至明确地设置了JTA,即使它在JBoss控制台中默认显示true

有什么问题?

2 个答案:

答案 0 :(得分:1)

  

我没有使用spring,只使用JPA,EJB和REST。   即使我使用@Transactional进行注释,我的交易也没有被提交。

据我所知,@Transactional不是事务管理的EJB注释。正常情况是,如果您未指定使用Bean管理的事务管理,容器将管理事务。在容器管理事务的情况下,容器自动管理事务。它在调用任何业务方法之前启动事务,并在退出方法之前提交。因此,在正常情况下,您不需要做任何事情,因为默认值将适用。

如果要更改默认行为,可以使用@TransactionAttribute注释,并使用TransactionAttributeType枚举设置所需的事务行为。此批注可以在适用于所有业务方法的类级别或单个业务方法上使用。

您遇到的问题可能与您的JPA设置有关。您在persistence.xml中使用JTA作为交易类型。因此,我最好引用JPA 2.0规范的一部分,如下所示,以便您可以看到预期的内容:

  

8.2.1.2 transaction-type

     

transaction-type属性用于指定实体管理器工厂为持久性单元提供的实体管理器是否必须是JTA实体管理器或资源本地实体管理器。此元素的值为JTA或RESOURCE_LOCAL。 JTA的事务类型假定JTA数据源将按照jta-data-source元素的指定或由容器提供。

正如您从规范中看到的那样(粗体标记),预计会有数据源,但您还没有提供数据源;相反,您正在设置适用于Java SE环境的连接属性,如JPA 2.0规范中的以下摘录所示:

  

本规范定义的以下属性旨在用于Java SE环境。

     

•javax.persistence.jdbc.driver - 驱动程序类的完全限定名称

     

•javax.persistence.jdbc.url - 特定于驱动程序的URL

     

•javax.persistence.jdbc.user - 数据库连接使用的用户名

     

•javax.persistence.jdbc.password - 数据库连接验证的密码

因此,您必须在JBoss中为数据库定义数据源,并在persistence.xml中指定。

答案 1 :(得分:1)

我认为问题可能与SQLite驱动程序有关,该驱动程序可能不支持JTA中使用的分布式事务。

然而,在使用JTA时,不应指定JDBC驱动程序,而应在JBoss服务器中创建数据源,并将其 persistence.xml 文件中的JNDI名称添加为jta-data-source