Java 如何在 JPA EntityManager 查询上设置超时期限
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24244621/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set the timeout period on a JPA EntityManager query
提问by James
I'm currently getting connection timeout errors from my EntityManager queries. Is it possible to set a timeout for these?
我目前从我的 EntityManager 查询中收到连接超时错误。是否可以为这些设置超时?
persistence.xml
持久化文件
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="CallPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>call.structure.Task</class>
<class>call.structure.Installation</class>
<class>call.structure.Contents</class>
<class>call.structure.Recipient</class>
<class>call.structure.CallTask</class>
<class>call.structure.SmsTask</class>
<class>call.structure.EmailTask</class>
<class>call.security.User</class>
<class>call.structure.content.Content</class>
<class>call.structure.content.RecordContent</class>
<class>call.structure.content.WaitContent</class>
<class>call.structure.content.TextContent</class>
<class>call.structure.content.VariableContent</class>
<class>call.structure.content.SoundContent</class>
<class>call.structure.content.SubjectContent</class>
<class>call.structure.content.FileContent</class>
<class>call.structure.Bounce</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@127.0.0.1:1521:TEST"/>
<property name="javax.persistence.jdbc.password" value="userpassword"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="javax.persistence.jdbc.user" value="username"/>
</properties>
</persistence-unit>
</persistence>
Code times out in the run function of my thread:
我的线程的运行函数中的代码超时:
private class TaskDB extends Thread {
private final long WAITING_TIME = 20000L;
@Override
public void run() {
Set<SmsTask> remove = SMSManager.this.getRemoveTask();
Set<SmsTask> normal = SMSManager.this.getNormalTask();
try {
while(true){
EntityManager em = DB.getEM(); //Calls EntityManagerFactory.createEntityManager()
em.getTransaction().begin();
Set<SmsTask> normalClone = new HashSet<SmsTask>(normal);
// Abort task in futur.
List<SmsTask> taskToRemove = new ArrayList<SmsTask>();
if (!remove.isEmpty()) {
String queryString = "SELECT t FROM SmsTask t WHERE t.id IN :remove ";
if (!normalClone.isEmpty())
queryString += "AND t.id NOT IN :normal ";
Query query = em.createQuery(queryString);
query.setParameter("remove", Utils.taskToIdList(remove));
if (!normalClone.isEmpty())
query.setParameter("normal", Utils.taskToIdList(normalClone));
taskToRemove = (List<SmsTask>) query.getResultList();
for (SmsTask task : taskToRemove) {
removedTask.add(task);
remove.remove(task);
}
}
String queryString = "SELECT t FROM SmsTask t WHERE (t.scheduleTime IS NULL OR t.scheduleTime < :dateNow) AND t.status = co.dium.call.structure.Task.StatusTask.NOT_START ";
if (!taskToRemove.isEmpty())
queryString += "AND t.id NOT IN :toRemove ";
Query query = em.createQuery(queryString);
query.setParameter("dateNow", Utils.obtainUniversalTime());
if (!taskToRemove.isEmpty())
query.setParameter("toRemove", Utils.taskToIdList(taskToRemove));
List<SmsTask> taskResults = (List<SmsTask>) query.getResultList();
em.getTransaction().commit();
for (SmsTask task : taskResults)
addTask(task);
SMSManager.TaskRemove.sleep(WAITING_TIME);
}
} catch (InterruptedException ex) {
Logger.getLogger(SMSManager.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("Thread interrompu !");
Thread.currentThread().interrupt();
}
}
The timeout errors that I get:
我得到的超时错误:
org.clipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLRecoverableException: I/O error: Socket read timed out
Error Code: 17002
Call: [....sql query...]
[...]
at org.eclipse.persistence.internal.EJBQueryImpl.getResultList(EJBQueryImpl.java:742)
at call.manager.sms.SMSManager$TaskDB.run(SMSManager.java:367)
Caused by: java.sql.SQLRecoverableException: I/O Error: Scoket read timed out
[...]
采纳答案by Mikko Maunu
Yes, there javax.persistence.query.timeout. According JPA 2.0 specification support for this query hint is optional:
是的,有javax.persistence.query.timeout。根据 JPA 2.0 规范对此查询提示的支持是可选的:
Portable applications should not rely on this hint. Depending on the persistence provider and database in use, the hint may or may not be observed.
便携式应用程序不应依赖此提示。根据使用的持久性提供程序和数据库,提示可能会或可能不会被观察到。
Default value (in milliseconds) can be set to persistence.xml for all queries:
对于所有查询,可以将默认值(以毫秒为单位)设置为 persistence.xml:
<property name="javax.persistence.query.timeout" value="1000"/>
Same property can be also given when creating EntityManagerFactory via Persistence.createEntityManagerFactory.
通过 Persistence 创建 EntityManagerFactory 时也可以提供相同的属性。创建实体管理器工厂。
It can also be overridden/set per query:
它也可以按查询覆盖/设置:
query.setHint("javax.persistence.query.timeout", 2000);
Same functionality can be obtained via attribute hintsin NamedQuery.
可以通过NamedQuery 中的属性提示获得相同的功能。
回答by Vlad Mihalcea
As I explained in this article, there are two ways you can set up the query timeout period with Hibernate.
正如我在本文中解释的那样,您可以通过两种方式使用 Hibernate 设置查询超时时间。
The Hibernate-specific way
特定于 Hibernate 的方式
If you are bootstrapping Hibernate natively or if you are unwrapping the JPA java.persistence.Query
to its org.hibernate.query.Query
equivalent, then you can just use the setTimeout
method:
如果您在本地引导 Hibernate,或者您正在将 JPA 解包java.persistence.Query
为其org.hibernate.query.Query
等效项,那么您可以使用以下setTimeout
方法:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"where lower(p.title) like lower(:titlePattern)", Post.class)
.setParameter("titlePattern", "%Hibernate%")
.unwrap(org.hibernate.query.Query.class)
.setTimeout(1)
.getResultList();
Notice that the
setTimeout
method takes anint
argument which specifies the timeout value in seconds.
请注意,该
setTimeout
方法接受一个int
参数,该参数以秒为单位指定超时值。
The JPA query hint way
JPA查询提示方式
You can also use a JPA query hint, as illustrated in the following example:
您还可以使用 JPA 查询提示,如以下示例所示:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"where lower(p.title) like lower(:titlePattern)", Post.class)
.setParameter("titlePattern", "%Hibernate%")
.setHint("javax.persistence.query.timeout", 50)
.getResultList();
Notice that the
javax.persistence.query.timeout
query hint takes the timeout value in milliseconds.
请注意,
javax.persistence.query.timeout
查询提示采用以毫秒为单位的超时值。
The Hibernate query hint way
Hibernate查询提示方式
You can also use the org.hibernate.timeout
query hint:
您还可以使用org.hibernate.timeout
查询提示:
List<Post> posts = entityManager
.createQuery(
"select p " +
"from Post p " +
"where lower(p.title) like lower(:titlePattern)", Post.class)
.setParameter("titlePattern", "%Hibernate%")
.setHint("org.hibernate.timeout", 1)
.getResultList();
Notice that the
org.hibernate.timeout
query hint takes the timeout value in seconds.
请注意,
org.hibernate.timeout
查询提示采用以秒为单位的超时值。
回答by Stefan
Instead of using the query hint 'javax.persistence.query.timeout
', you should use 'javax.persistence.lock.timeout
'.
不应使用查询提示“ javax.persistence.query.timeout
”,而应使用“ javax.persistence.lock.timeout
”。
In the latter case, if the query does not return within the specified milliseconds you'll receive a CannotAcquireLockException
. In the first case, if the transaction does not finish within the specified milliseconds, you'll receive a QueryTimeoutException
and the transaction will be rolled back.
在后一种情况下,如果查询没有在指定的毫秒内返回,您将收到一个CannotAcquireLockException
. 在第一种情况下,如果事务没有在指定的毫秒内完成,您将收到 aQueryTimeoutException
并且事务将被回滚。