【问题标题】:JPA update query without transaction - is transaction mandatory?没有事务的 JPA 更新查询 - 事务是强制性的吗?
【发布时间】:2018-12-01 00:45:37
【问题描述】:

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

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

这以 TransactionRequiredException 结束:

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

at org.hibernate.ejb.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:99)

但是,如果我打开 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();

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

【问题讨论】:

  • 您无法避免创建事务。您只能使其隐含(例如通过会话)

标签: java hibernate jpa transactions


【解决方案1】:

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

在官方JPA 2.2 specification (p. 345) 的 7.5.2 Resource-local EntityManagers 部分中,我们发现:

一个实体管理器,其事务由应用程序通过EntityTransaction 控制 API 是一个资源本地实体管理器。映射资源本地实体管理器事务 持久性提供者对资源的资源事务。资源本地实体管理器 可能使用服务器或本地资源连接到数据库并且不知道 JTA 的存在 可能活跃也可能不活跃的交易

在规范文档的更下方,给出了EntityTransaction 接口。它允许您调用

  1. begin() “启动资源事务”
  2. commit() to "提交当前资源事务,写入任何 对数据库的未刷新更改。”
  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...
}

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

查看上面链接的规范文档的 3.1.1 EntityManager 接口部分(第 65 页)并使用这些方法

  • persist(..) - “让一个实例成为托管和持久的。”
  • merge(..) - “将给定实体的状态合并到当前持久化上下文中。”

有关这两种方法差异的更多信息,请参阅帖子herehere

希望对你有帮助。

【讨论】:

    【解决方案2】:

    我建议不要创建本机查询,而是为该人创建一个 JPA 实体,并且使用 JPARepository,您可以为该人使用保存方法来插入任何记录。

    【讨论】:

      猜你喜欢
      • 2016-09-12
      • 2020-06-21
      • 2011-12-22
      • 1970-01-01
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      • 2015-09-16
      • 1970-01-01
      相关资源
      最近更新 更多