看来您正在构建一个不在支持的容器内运行的应用程序JTA托管交易。在这样的环境中,您必须自己处理/管理事务,即您必须控制事务何时打开、提交或回滚。这种情况被称为资源本地实体管理器.
在部分7.5.2资源本地EntityManager官方的JPA 2.2 规范 https://raw.githubusercontent.com/javaee/jpa-spec/master/jsr338-MR/JavaPersistence.pdf(第 345 页)我们发现:
实体管理器,其事务由应用程序通过以下方式控制EntityTransaction
API 是一个资源本地实体管理器。映射资源本地实体管理器事务
持久性提供者对资源进行的资源事务。资源本地实体管理器
可能使用服务器或本地资源连接到数据库并且不知道 JTA 的存在
交易可能活跃也可能不活跃
在规范文档的更下方EntityTransaction
给出了接口。它可以让你打电话
-
begin()
to “启动资源交易”
-
commit()
to “提交当前资源事务,写入任何
未刷新对数据库的更改。”
-
rollback()
to “回滚当前资源事务。”以防在提交更改时数据库端出现问题。
这是理论部分。
对于您的代码示例,您可能希望将其更改如下:
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
,因为您错误地使用了对象关系映射器(ORM)的基本概念,即映射器会将对象转换为元组,反之亦然。一般来说,这应该可以减轻为大量域实体编写插入/更新查询的痛苦。
看一下部分3.1.1 EntityManager接口(第 65 页)上面链接的规范文档并使用这些方法
-
persist(..)
- “使实例成为托管且持久的实例。” or
-
merge(..)
- “将给定实体的状态合并到当前的持久性上下文中。”
有关两种方法差异的更多信息,请参阅帖子here https://stackoverflow.com/q/1069992/2849346 and here https://stackoverflow.com/a/4509389/2849346.
希望能帮助到你。