我在尝试从Java调用到SQLServer的SQL查询时遇到了一个奇怪的问题。
对Java函数的单个调用很好,但是当我在循环中(2至30迭代)进行相同操作时,我有时(并非总是如此)会有这样的错误:
由:com.microsoft.sqlserver.jdbc.sqlserverexception:ledélaiincriparti - la requarte aExpiré。 在com.microsoft.sqlserver.jdbc.tdscommand.checkforinterrupt(iobuffer.java:5918)
我注意到的几件事:
- 它总是在循环的同一步骤中失败,前提是迭代项目保持不变(例如,如果在15步的第7步中失败,它将始终在步骤7中失败!) )
- 如果我跳过或更改任何迭代项目,包括先前失败的项目,它将在另一个步骤中失败...并且在下一步中不会失败,但是 - 看起来像是 - 随机一个
- 如果我将失败的查询(从调试)复制/粘贴到sqlquerybrowser中并执行:它可以使用
- 如果我从SQL Server Profiler复制/粘贴了失败的查询:它有效!
- 如果我从SQL Server查询浏览器中执行循环(迭代输入参数):它有效!
- 如果我在Junit测试中执行循环,则只能在对序列上进行迭代:它也有效!
- 在SQL Server Profiler中,我可以看到成功的请求需要200至600毫秒才能完成,而失败的一个毫无疑问需要15000毫秒(=当前配置的超时)
- 当我更改超时时,查询会不断计时。
这是我尝试执行的,没有成功:
- 每个步骤/查询一项交易
- 更新服务器'连接超时'et'查询超时'通过sp_serveroption( exec sp_serveroption'myServer sqlexpress','connect timeout',45; )))
- 更改 QUERYTIMEOUT 从Java
- 更改SQL查询浏览器{server}>" properties">"高级">" Parallelism" 的"查询等待"选项
- 请勿丢弃临时表#MatchingDays
- 将随机令牌添加到#MatchingDays,以防止并发冲突
- 添加查询周围的开始/结束
- 用waitfor延迟延迟延迟t 延迟请求
- 使用存储过程而不是持有请求的字符串
- 从"最后"语句中执行齐平 避免会话。
- 重新启动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
其他一些信息
- Java 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
}
...欢迎任何技巧!
最终,我设法使它起作用:将" savetableObject"方法从循环内部移动到外部的外部,做到了。但是,尽管我找到了一个解决方案,但我仍然不明白为什么以前的插入物嵌入了自己的专门交易中,导致该锁定在下一次迭代中,并在另一项交易中保持!...因此,如果您有提示:它们是:它们是:仍然欢迎!
顺便说一句,这篇文章帮助我发现了哪个对象已锁定!
@Jean:非常感谢您的许多问题,这些问题帮助我专注于核心原因!