【问题标题】:JPA JBoss transactions not committedJPA JBoss 事务未提交
【发布时间】:2016-07-29 02:11:43
【问题描述】:

编辑 - 更新了 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 端点时,我得到一个空数组。

为什么?看起来事务没有由容器管理。
我不明白。

编辑:

我更改了 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

有什么问题?

【问题讨论】:

    标签: java hibernate jpa jboss


    【解决方案1】:

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

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

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

    您面临的问题可能与您的 JPA 设置有关。您在 persistence.xml 中使用 JTA 作为事务类型。所以我最好引用一段 JPA 2.0 规范如下,以便您了解预期的内容:

    8.2.1.2 交易类型

    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 中指定它。

    【讨论】:

    • 谢谢,我昨天试过了,还是不行。查看我的编辑
    • 您是否尝试过使用&lt;jta-data-source&gt;java:jboss/datasources/ExampleDS&lt;/jta-data-source&gt; 而不是将其定义为属性?应该直接放在persistence-unit标签下。
    • 好的,刚刚切换到那个,还是没有骰子。还将getClasses 方法添加到我的类中,extends Application 显式返回我的端点类,但仍然是相同的东西。
    【解决方案2】:

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

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

    【讨论】:

    • 谢谢,我昨天试过了,还是不行。查看我的编辑。
    猜你喜欢
    • 2011-03-13
    • 1970-01-01
    • 2016-03-31
    • 1970-01-01
    • 2016-08-30
    • 2015-07-24
    • 2015-12-17
    • 1970-01-01
    • 2017-06-17
    相关资源
    最近更新 更多