Sql Server запрос из Java/ Hibernate случайно истекает при вызове в цикле

Я столкнулся со странной проблемой при попытке выполнить SQL-запрос от вызова Java к SQLServer.

Один вызов java-функции идет хорошо, но когда я делаю то же самое в цикле (от 2 до 30 итераций), я иногда (не всегда) получаю такую ​​ошибку:

Вызывается: com.microsoft.sqlserver.jdbc.SQLServerException: Le délai imparti à la recête expire. на com.microsoft.sqlserver.jdbc.TDSCommand.checkForInterrupt(IOBuffer.java:5918)

Несколько вещей, которые я заметил:

  • Он всегда терпит неудачу на одном и том же шаге цикла, при условии, что повторяющийся элемент остается неизменным (например, если он потерпит неудачу на шаге 7 из 15, он всегда потерпит неудачу на шаге 7!)
  • Он потерпит неудачу на другом шаге, если я пропущу или изменим какой-либо повторяющийся элемент, включая ранее ошибочный элемент... и он не потерпит неудачу на следующем шаге, но - как это выглядит - на случайном уровне
  • Если я копирую / вставляю ошибочный запрос (из отладки) в SqlQueryBrowser и выполняю его: он работает
  • Если я копирую / вставляю ошибочный запрос из Sql Server Profiler: он работает!
  • Если я выполню цикл из браузера запросов SQLServer (итерируя по входным параметрам): это работает!
  • Если я выполню цикл из теста JUnit, только итерируя по параметрам: это тоже работает!!
  • Из Sql Server Profiler я вижу, что успешные запросы занимают от 200 до 600 мс, а если сбой занимает ровно 15000 мс ( = текущее настроенное время ожидания)
  • Когда я изменяю тайм-аут, запрос продолжает истекать.

Это то, что я пытался выполнить, но безуспешно:

  • Используйте одну транзакцию на шаг / запрос
  • Обновите сервер 'timeout соединения' и 'timeout запроса' через sp_ serveroption (EXEC sp_serveroption 'myServer \ SQLEXPRESS', 'timeout соединения', 45;)
  • Изменить queryTimeout из Java
  • Измените параметр "запрос ожидания" в Sql Query Browser {Сервер} > "Свойства" > "Дополнительно" > "Параллелизм"
  • Не удаляйте временную таблицу #MATCHINGDAYS
  • Добавьте случайный токен в #MATCHINGDAYS, чтобы предотвратить конфликты параллелизма
  • Добавьте BEGIN / END вокруг запроса
  • Задержка запроса с WAYITFOR DELAY t
  • использовать хранимую процедуру вместо строки, содержащей запрос
  • выполнить очистку + очистку сеанса из оператора "finally".
  • Перезапуск SqlServer + tomcat
  • Обновите драйвер до mssql-jdbc 6.1.0.jre7
  • Используйте фактическую таблицу вместо временной

вызов Java

(Он встроен в одну транзакцию)

final SessionImpl sess = (SessionImpl) this.getSessionFactory().openSession();
try (Connection conn = sess.connection(); Statement st = conn.createStatement();) {
    final NamedParameterPreparedStatement ps = NamedParameterPreparedStatement.createNamedParameterPreparedStatement(conn, aStringWithTheRequestBelow);
        // ... set parameters here ...
    ps.setQueryTimeout(15);
    final ResultSet rs = ps.executeQuery();
} catch (final SQLException ex) {
    LOG.error("parameter 1 :" + parameter1 + "etc.");
} finally {
    sess.close();
}

запрос TSQL

(Я сделал это для мозга и глаз, но это немного сложнее, чем это выглядит; но в принципе, у вас есть идея об этом)

--DECLARE @date as DATE = '2017-09-03'; -- one of the input parameter set up from java.


IF OBJECT_ID('tempdb.dbo.#MATCHINGDAYS718567154','U') is not null 
DROP TABLE #MATCHINGDAYS718567154; -- RANDOM TOKEN HERE TO AVOID CONCURRENCY

WITH startDateTable AS ( 
    SELECT TOP 1 a.dateStart 
    FROM   someSelection
), 
endDateTable AS ( 
    SELECT TOP 1 endDate
    FROM   anotherSelection
), 
AllDays  AS ( 
    SELECT myFunc_getMaxDate(DATEADD(DAY,1,startDateTable.dateStart), DATEADD(dd, -30,@date))AS [Date] 
    FROM startDateTable 
    UNION ALL 
    SELECT    
    DATEADD(DAY, 1, [Date]) 
    from  AllDays 
    join endDateTable on 1=1 
     WHERE    [Date] < myFunc_getMinDate(DATEADD(dd, +7, @date),endDateTable.endDate)) 


-- build a temporary table with all days from startDate to endDate the recursive way
-- with a min -30 days before input date and 7 days after output date    
SELECT [Date] 
     INTO #MATCHINGDAYS718567154 
         FROM    AllDays 
     OPTION (MAXRECURSION 37) 

SELECT   
    manyFields

from MainTable
-- various joins
join #MATCHINGDAYS718567154 as MD on 1 = 1 
where 1 = 1
and -- etc... many clauses including some computed over MATCHINGDAYS718567154

order by someField

DROP TABLE #MATCHINGDAYS718567154 

Некоторая другая информация

  • Ява 1.7_071
  • Hibernate 4.3.4.Final
  • SqlServer Express 2014
  • Tomcat 7
  • sqljdbc4 4.0

Редактировать 28/11: причина

где-то в моем цикле время от времени вставляется объект из той же таблицы запрашиваемого элемента. Это выполняется в отдельной транзакции (хотя я также пытался выполнить ее в той же транзакции). Проблема не возникает на итерации, когда объект вставлен, но на следующей итерации... Теперь у меня есть причина... Я до сих пор не понимаю, почему это вызывает сбой на следующей итерации... Хотя я подозреваю, что это будет совершенно очевидно, как только я пойму это!

someIterationOver(List<SomeObject> manyObjects){
    from(SomeObject mo : manyObjects){
        List<MyTableObject> myTableObjects = performMyBigQueryOver(mo.getSomeId());
        for(MyTableObject myTableSingleObject : myTableObjects){
            if(myTableSingleObject.matchesSomeCondition()){
                TableSingleObject aNewTableSingleObject = new TableSingleObject("newTableObject");
                // this will cause the problem in the next iteration
                saveTableObject(aNewTableSingleObject);
            }
        }

    }
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
private void saveTableObject(ableSingleObject aNewTableSingleObject){
    this.sessionFactory.getCurrentSession.save(aNewTableSingleObject); // works fine
}

... любые советы приветствуются здесь!

1 ответ

Решение

В конце концов мне удалось заставить его работать: перемещение метода "saveTableObject" из цикла в другое делает свое дело... Но, хотя я нашел решение, я все еще не понимаю, почему предыдущая вставка, встроенная в свою собственную выделенная транзакция, заставила эту блокировку поддерживать до следующей итерации и в другой транзакции!... Так что, если у вас есть советы: они все еще приветствуются!

Кстати, этот пост очень помог мне узнать, какой объект заблокирован!

@ Джин: большое спасибо за ваши многочисленные вопросы, которые помогли мне сосредоточиться на основной причине!

Другие вопросы по тегам