没有事务的 JPA 更新查询 - 事务是强制性的吗?

k-s*_*ver 4 java hibernate jpa transactions

我正在尝试使用 JPA 通过本机查询进行插入,但我不想创建事务:

Query query = em.createNativeQuery("INSERT INTO person (id, firstname, lastname) VALUES ('1','Ronnie','Dio')");
int count = query.executeUpdate();
Run Code Online (Sandbox Code Playgroud)

这最终会出现 TransactionRequiredException:

javax.persistence.TransactionRequiredException: Executing an update/delete query

at org.hibernate.ejb.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:99)
Run Code Online (Sandbox Code Playgroud)

但是,如果我打开 Hibernate 会话并执行相同的查询 - 它会起作用:

Session session = em.unwrap(Session.class);
Query query = session.createSQLQuery("INSERT INTO person (id, firstname, lastname) VALUES ('1','Ronnie','Dio')");
int count = query.executeUpdate();
Run Code Online (Sandbox Code Playgroud)

所以我的问题是 - 我在第一个示例中做错了什么?在 JPA 中执行插入/更新/删除查询真的需要事务吗?如果是,是否有任何明确指定的文档链接?如果不是——我做错了什么?

MWi*_*ner 5

看来您正在构建一个不在支持的容器内运行的应用程序JTA管理事务的容器内运行的应用程序。在这样的环境中,您必须自己处理/管理事务,即您必须控制事务何时打开、提交或回滚。这种情况称为资源本地实体管理器

在第 7.5.2节中,资源本地 EntityManager在官方JPA 2.2 规范中,我们发现:

实体管理器,其事务由应用程序通过以下方式控制EntityTransaction API 控制的实体管理器是资源本地实体管理器。资源本地实体管理器事务由持久性提供者映射到资源上的资源事务。资源本地实体管理器可以使用服务器或本地资源连接到数据库,并且不知道 JTA 事务的存在,这些事务可能处于活动状态,也可能不处于活动状态

在规范文档的下面EntityTransaction给出了接口。它可以让你打电话

  1. begin()“开始资源事务”
  2. commit()“提交当前资源事务,将任何未刷新的更改写入数据库。”
  3. rollback()“回滚当前资源事务”。以防在提交更改时数据库端出现问题。

这是理论部分。对于您的代码示例,您可能希望将其更改如下:

EntityTransaction tx = null;
try {
    tx = em.getTransaction();
    // start a new transaction, i.e. gather changes from here on...
    tx.begin();

    // do your changes here
    Query query = em.createNativeQuery("INSERT INTO person (id, firstname, lastname) VALUES ('1','Ronnie','Dio')");
    int count = query.executeUpdate();

    // write changes to database via commit
    tx.commit();
} catch(RuntimeException re) {
    if(tx != null && tx.isActive()) {
        // ensure no semi-correct changes are pending => cleanup
        tx.rollback();
    }
    // handle exception, log it somewhere...
}
Run Code Online (Sandbox Code Playgroud)

这应该避免TransactionRequiredException您遇到的情况。此外,您应该避免使用createNativeQuery,因为您错误地使用了对象关系映射器(ORM)的基本概念,即映射器会将对象转换为元组,反之亦然。一般来说,这应该可以减轻为大量域实体编写插入/更新查询的痛苦。

看一下部分上面链接的规范文档的3.1.1 EntityManager Interface (p. 65) 部分并使用这些方法

  • persist(..)- “使实例成为托管且持久的实例。” 或者
  • merge(..)- “将给定实体的状态合并到当前的持久性上下文中。”

有关两种方法差异的更多信息,请参阅此处的帖子此处的帖子。

希望能帮助到你。