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

I'm trying to do insert via a native query with JPA, but I don't want to create a transaction:

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

int count = query.executeUpdate();

this ends up with the TransactionRequiredException:

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

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

However, if I unwrap the Hibernate session and execute the same query - it works:

Session session = em.unwrap(Session.class);

Query query = session.createSQLQuery("INSERT INTO person (id, firstname, lastname) VALUES ('1','Ronnie','Dio')");

int count = query.executeUpdate();

So my question is - what am I doing wrong in the first sample? Is transaction really required to execute insert/update/delete queries in JPA?

If it is, is there any link to documentation that specifies it clearly? If it's not - what am I doing wrong?

解决方案

It seems you are building an application that does not run inside a container supporting JTA managed transactions. In such an environment, you have to handle/manage transactions for yourself, i.e., you have to control when transactions are opened, committed or rolled back. This scenario is referred to as resource-local entity manager.

In section 7.5.2 Resource-local EntityManagers of the official JPA 2.2 specification (p. 345) we find:

An entity manager whose transactions are controlled by the application through the EntityTransaction

API is a resource-local entity manager. A resource-local entity manager transaction is mapped

to a resource transaction over the resource by the persistence provider. Resource-local entity managers

may use server or local resources to connect to the database and are unaware of the presence of JTA

transactions that may or may not be active

Further down in the spec document the EntityTransaction interface is given. It allows you to call

begin() to "Start a resource transaction"

commit() to "Commit the current resource transaction, writing any

unflushed changes to the database."

rollback() to "Roll back the current resource transaction." in case something went wrong on the database side while committing changes.

That's for the theory part.

For your code example, you might want to change it as follows:

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

}

This should avoid the TransactionRequiredException you encounter. Moreover, you should avoid the use createNativeQuery, as you are mis-using a fundamental concept of an Object-Relational-Mapper (ORM), i.e. the mapper will transform objects into tuples and vice versa for you. This - in general - should ease the pain of writing insert/update queries for a large amount of domain entities.

Have a look into section 3.1.1 EntityManager Interface (p. 65) of the spec document linked above and make use of the methods

persist(..) - "Make an instance managed and persistent." or

merge(..) - "Merge the state of the given entity into the current persistence context."

For more infos on the difference of both approaches see the posts here and here.

Hope it helps.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值