#java #hibernate #jpa #timeout #entitymanager
#java #спящий режим #jpa #тайм-аут #EntityManager
Вопрос:
В настоящее время я получаю ошибки времени ожидания соединения из своих запросов 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>
Время ожидания кода истекает в функции запуска моего потока:
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();
}
}
Ошибки тайм-аута, которые я получаю:
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
[...]
Ответ №1:
Да, есть javax.persistence.запрос.тайм-аут. В соответствии со спецификацией JPA 2.0 поддержка этой подсказки запроса необязательна:
Переносимые приложения не должны полагаться на эту подсказку. В зависимости от используемого поставщика сохраняемости и базы данных подсказка может наблюдаться или не наблюдаться.
Значение по умолчанию (в миллисекундах) может быть установлено равным persistence.xml для всех запросов:
<property name="javax.persistence.query.timeout" value="1000"/>
То же свойство может быть также задано при создании EntityManagerFactory через Persistence.createEntityManagerFactory .
Он также может быть переопределен / установлен для каждого запроса:
query.setHint("javax.persistence.query.timeout", 2000);
Ту же функциональность можно получить с помощью подсказок по атрибутам в NamedQuery.
Комментарии:
1. кажется, брандмауэр прерывал соединение при длительных соединениях, которые мне нужно было добавить в мой persistence.xml : javax.настойчивость. запрос.timeout (10000) oracle.jdbc.ReadTimeout (40000) и (ВКЛЮЧИТЬ = сломанный) в моем tnsnames.ora, а также изменить KeepAliveInterval и keepAliveTime в реестре Windows
2. Хотя это старый вопрос, у меня возникла аналогичная проблема при вызове entitymanager.persist(). Как я могу установить свойство timeout в таком случае?
Ответ №2:
Есть два способа настроить период ожидания запроса с помощью Hibernate.
Специфичный для гибернации способ
Если вы загружаете 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();
Обратите внимание, что
setTimeout
метод принимаетint
аргумент, который указывает значение времени ожидания в секундах.
Способ подсказки запроса JPA
Вы также можете использовать подсказку для запроса 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();
Обратите внимание, что
javax.persistence.query.timeout
подсказка запроса принимает значение времени ожидания в миллисекундах.
Способ подсказки запроса в режиме гибернации
Вы также можете использовать 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();
Обратите внимание, что
org.hibernate.timeout
подсказка запроса принимает значение времени ожидания в секундах.
Ответ №3:
Вместо того, чтобы использовать подсказку запроса « javax.persistence.query.timeout
, вы должны использовать « javax.persistence.lock.timeout
.
В последнем случае, если запрос не возвращается в течение указанных миллисекунд, вы получите CannotAcquireLockException
. В первом случае, если транзакция не завершается в течение указанных миллисекунд, вы получите QueryTimeoutException
сообщение, и транзакция будет откатана.
Комментарии:
1. Чтобы уточнить, если вы используете
javax.persistence.query.timeout
, вам нужно завершить полную транзакцию в течение указанного количества миллисекунд. Если вы используетеjavax.persistence.lock.timeout
только блокировку, она должна быть получена в течение указанного количества миллисекунд.