高效的SQL测试查询或验证查询,可在所有(或大多数)数据库中使用


148

许多数据库连接池库都提供了测试其SQL连接是否空闲的功能。例如,JDBC池库c3p0具有一个名为的属性preferredTestQuery,该属性将在配置的时间间隔上在连接上执行。同样,Apache Commons DBCP具有validationQuery

我看到的许多示例 查询都是针对MySQL的,建议将其SELECT 1;用作测试查询的值。但是,此查询不适用于某些数据库(例如HSQLDB,SELECT 1需要使用FROM子句)。

是否存在与数据库无关的查询,该查询同样有效,但适用于所有SQL数据库?

编辑:

如果没有(似乎是这种情况),有人可以建议一套适用于各种数据库提供程序的SQL查询吗?我的意图是根据数据库提供程序的配置以编程方式确定可以使用的语句。



1
注意:不再需要配置测试查询,请参阅下面的答案
TimBüthe16年

Answers:


274

经过一些研究以及此处提供的一些答案的帮助:

SELECT 1

  • H2
  • 的MySQL
  • Microsoft SQL Server(根据NimChimpsky
  • PostgreSQL的
  • SQLite的

SELECT 1 FROM DUAL

  • 甲骨文

SELECT 1 FROM any_existing_table WHERE 1=0

要么

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB(经过1.8.0.10版测试)

    注意:我尝试WHERE 1=0在第二个查询中使用一个子句,但是它不能用作Apache Commons DBCP的值validationQuery,因为该查询不返回任何行


VALUES 1 要么 SELECT 1 FROM SYSIBM.SYSDUMMY1

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix

那应该是“ SELECT 1 FROM any_existing_table WHERE 1 = 0”-否则调用可能很慢。顺便说一下,SELECT 1和SELECT 1 FROM DUAL都可以与H2一起使用。
Thomas Mueller 2010年

2
我知道这已经有两年历史了,但是您可能要同时添加Apache Derby VALUES 1SELECT 1 FROM SYSIBM.SYSDUMMY1Apache Derby
daiscog 2012年

假设OP想要一个Java答案:我相信Java 6现在已经过时了。在此页面的其他地方查看我的答案。
peterh 2014年

您可以添加这两样你的答案,DB2: “选择当前日期从SYSIBM.SYSDUMMY1” Informix的: “SELECT COUNT(*)FROM systables中”
迈克尔·

@Michael如果您想提出修改建议,我会批准。另外,您将获得几个代表积分。
罗布·赫鲁斯卡

22

如果您的驱动程序兼容JDBC 4,则不需要专门的查询来测试连接。而是使用Connection.isValid来测试连接。

JDBC 4是2006年以来Java 6的一部分,您的驱动程序现在应该支持它!

像HikariCP这样的著名连接池仍然具有用于指定测试查询的config参数,但强烈不鼓励使用它:

🔠connectionTestQuery

如果您的驱动程序支持JDBC4,我们强烈建议不要设置此属性。这是针对不支持JDBC4 Connection.isValid()API的“旧版”数据库的。这是将在从池中为您提供连接之前执行的查询,以验证与数据库的连接仍然有效。再次,尝试运行不带该属性的池,如果驱动程序不兼容JDBC4,HikariCP将记录错误。默认值:无


9

不幸的是,没有SELECT语句无论数据库如何都将始终有效。

大多数数据库支持:

SELECT 1

某些数据库不支持此功能,但是有一个名为DUAL的表,可以在不需要表时使用:

SELECT 1 FROM DUAL

MySQL出于兼容性原因也支持此功能,但并非所有数据库都支持。对于不支持以上任何一种方法的数据库,一种解决方法是创建一个名为DUAL的表,其中包含一行。

HSQLDB不支持以上两种,因此您可以创建DUAL表或使用:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database

感谢你的回答。由于您的“没有SELECT语句将始终有效”语句,我对我的问题进行了稍微的更新。SELECT 1 FROM DUAL也不适用于HSQLDB。
罗布·赫鲁斯卡

1
+1,这也是我研究的重点,特别是对于HSQLDB案例。
罗布·赫鲁斯卡

哪些不支持“选择1”?从双重选择中选择oracle是吗?不是sql server,或者至少是mysql
NimChimpsky 2010年

+1我已经放弃尝试使用RDBMS独立方式的想法了!
马丁·史密斯

2

我用这个:

select max(table_catalog) as x from information_schema.tables

检查连接以及运行postgreSQL,MySQL和MSSQL的查询(结果为1行)的能力。


2

我用

Select COUNT(*) As X From INFORMATION_SCHEMA.SYSTEM_USERS Where 1=0

对于hsqldb 1.8.0



1

select 1 将在SQL Server中工作,不确定其他。

使用标准的ansi sql创建一个表,然后从该表中查询。


ansi SQL是否涵盖create table
马丁·史密斯

是的,它确实。如果使用ansi数据类型。如果“选择1”没有起作用,我会感到惊讶。
NimChimpsky 2010年

1

假设OP需要Java答案:

从JDBC3 / Java 6开始,应该使用isValid()方法,而不要发明自己的方法。

当调用此方法id时,要求驱动程序的实现者对数据库执行某种查询。您-仅作为JDBC用户-不必知道或理解此查询是什么。您要做的就是相信JDBC驱动程序的创建者已经正确完成了他/她的工作。


2
我相信OP在谈论的不是针对容器,而是针对容器的连接池配置的验证查询。例如,在Tomcat的context.xml中(在其中设置“资源”),它需要一个validationQuery,Tomcat用来验证连接。Tomcat本身必须进行更改才能利用isValid()。这不是OP可以控制的。
迈克尔

还值得注意的是,“ JDBC驱动程序的创建者已正确完成其工作”并不能真正得到保证。我只是发现Postgres,HSQLDB或H2都没有费心去实现该方法,因此它总是在此处引发异常。
akroy 2014年

1

怎么样

SELECT user()

我以前用过。MySQL,H2还可以,我不认识其他人。


1

刚刚发现这是很难的方法

SELECT 1 FROM DUAL

也适用于MaxDB。


这不能为问题提供答案。一旦您拥有足够的声誉,您就可以在任何帖子中发表评论;相反,请提供不需要问询者澄清的答案。- 来自评论
Peter Brittain

我不明白,它为接受的答案增加了价值,那么问题出在哪里呢?
拉尔斯·德克尔

正如您提到的:由于我无法评论已接受的答案,因此在此我将其作为答案。因此最好不要写一篇帖子,尽管仅仅因为缺少声誉可能会有所帮助?
拉尔斯·德克

TBH,这是一个千钧一发......而不是重复的答案,这应该已经对原来的答复评论。否则,您可能会对原件进行建议的编辑。
彼得·布里顿



0

对于MSSQL

这帮助我确定了链接服务器是否还活着。使用Open Query连接和TRY CATCH将错误结果放入有用的东西。

IF OBJECT_ID('TEMPDB..#TEST_CONNECTION') IS NOT NULL DROP TABLE #TEST_CONNECTION
IF OBJECT_ID('TEMPDB..#RESULTSERROR') IS NOT NULL DROP TABLE #RESULTSERROR
IF OBJECT_ID('TEMPDB..#RESULTSGOOD') IS NOT NULL DROP TABLE #RESULTSGOOD

DECLARE @LINKEDSERVER AS VARCHAR(25)    SET @LINKEDSERVER = 'SERVER NAME GOES HERE'
DECLARE @SQL AS VARCHAR(MAX)
DECLARE @OPENQUERY AS VARCHAR(MAX)

--IF OBJECT_ID ('dbo.usp_GetErrorInfo', 'P' ) IS NOT NULL DROP PROCEDURE usp_GetErrorInfo;  
--GO  

---- Create procedure to retrieve error information.  
--CREATE PROCEDURE dbo.usp_GetErrorInfo  
--AS  
--SELECT     
--    ERROR_NUMBER() AS ErrorNumber  
--    ,ERROR_SEVERITY() AS ErrorSeverity  
--    ,ERROR_STATE() AS ErrorState  
--    ,ERROR_PROCEDURE() AS ErrorProcedure  
--    ,ERROR_LINE() AS ErrorLine  
--    ,ERROR_MESSAGE() AS Message;  
--GO  


BEGIN TRY
SET @SQL='
SELECT 1 
'''
--SELECT @SQL
SET @OPENQUERY = 'SELECT * INTO ##TEST_CONNECTION FROM OPENQUERY(['+ @LINKEDSERVER +'],''' + @SQL + ')'
--SELECT @OPENQUERY
EXEC(@OPENQUERY)
SELECT * INTO #TEST_CONNECTION FROM ##TEST_CONNECTION
DROP TABLE ##TEST_CONNECTION
--SELECT * FROM #TEST_CONNECTION
END TRY

BEGIN CATCH
-- Execute error retrieval routine.
IF OBJECT_ID('dbo.usp_GetErrorInfo') IS NOT NULL -- IT WILL ALWAYS HAVE SOMTHING... 
    BEGIN
        CREATE TABLE #RESULTSERROR (
        [ErrorNumber]       INT
        ,[ErrorSeverity]    INT
        ,[ErrorState]       INT
        ,[ErrorProcedure]   INT
        ,[ErrorLine]        INT
        ,[Message]          NVARCHAR(MAX) 
        )
        INSERT INTO #RESULTSERROR
        EXECUTE dbo.usp_GetErrorInfo
    END
END CATCH

BEGIN 
    IF (Select ERRORNUMBER FROM #RESULTSERROR WHERE ERRORNUMBER = '1038') IS NOT NULL --'1038' FOR ME SHOWED A CONNECTION ATLEAST. 
        SELECT
        '0' AS [ErrorNumber]        
        ,'0'AS [ErrorSeverity]  
        ,'0'AS [ErrorState]     
        ,'0'AS [ErrorProcedure] 
        ,'0'AS [ErrorLine]      
        , CONCAT('CONNECTION IS UP ON ', @LINKEDSERVER) AS [Message]            
    ELSE 
        SELECT * FROM #RESULTSERROR
END

docs.microsoft.com

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.