2010-09-08 30 views
105

Nhiều thư viện kết nối cơ sở dữ liệu cung cấp khả năng kiểm tra kết nối SQL của chúng cho sự không hoạt động. Ví dụ, thư viện tổng hợp JDBC c3p0 có một thuộc tính được gọi là preferredTestQuery, được thực hiện trên kết nối tại các khoảng thời gian được định cấu hình. Tương tự, Apache Commons DBCP có validationQuery.Truy vấn kiểm tra SQL hoặc truy vấn xác thực hợp lệ sẽ hoạt động trên tất cả (hoặc hầu hết) cơ sở dữ liệu

Nhiều người examplequeries Tôi đã xem là dành cho MySQL và khuyên bạn nên sử dụng SELECT 1; làm giá trị cho truy vấn thử nghiệm. Tuy nhiên, truy vấn này không hoạt động trên một số cơ sở dữ liệu (ví dụ: HSQLDB, trong đó SELECT 1 mong đợi một điều khoản FROM).

Có truy vấn cơ sở dữ liệu không thuyết phục nào có hiệu quả tương đương nhưng sẽ hoạt động với tất cả cơ sở dữ liệu SQL không?

Edit:

Nếu không có (mà có vẻ là trường hợp), ai đó có thể đề nghị một loạt các truy vấn SQL mà sẽ làm việc cho các nhà cung cấp cơ sở dữ liệu khác nhau? Ý định của tôi là lập trình xác định một câu lệnh mà tôi có thể sử dụng dựa trên cấu hình của nhà cung cấp cơ sở dữ liệu của mình.

+1

Xem thêm [Query DB2 đơn giản để xác nhận kết nối] (http://stackoverflow.com/questions/2775184/simple-db2-query-for-connection-validation). –

+1

Lưu ý: việc cấu hình truy vấn thử nghiệm là không cần thiết nữa, xem [answer] (http://stackoverflow.com/a/35270023/60518) bên dưới –

Trả lời

190

Sau một chút nghiên cứu cùng với sự giúp đỡ từ một số các câu trả lời ở đây:

SELECT 1

  • H2
  • MySQL
  • Microsoft SQL Server (theo NimChimpsky)
  • PostgreSQL
  • SQLite

SELECT 1 FROM DUAL

  • Oracle

SELECT 1 FROM any_existing_table WHERE 1=0

hoặc

SELECT 1 FROM INFORMATION_SCHEMA.SYSTEM_USERS

  • HSQLDB (thử nghiệm với phiên bản 1.8.0.10)

    Lưu ý: Tôi cố gắng sử dụng một điều khoản WHERE 1=0 trên truy vấn thứ hai, nhưng nó đã không làm việc như một giá trị cho Apache Commons DBCP của validationQuery, kể từ khi truy vấn không trả lại bất kỳ hàng


VALUES 1 hoặc SELECT 1 FROM SYSIBM.SYSDUMMY1

  • Apache Derby (thông qua daiscog)

SELECT 1 FROM SYSIBM.SYSDUMMY1

  • DB2

select count(*) from systables

  • Informix
+0

Điều đó phải là "CHỌN 1 TỪ any_existing_table WHERE 1 = 0" - nếu không cuộc gọi có thể rất chậm. Bằng cách này, cả hai SELECT 1 và SELECT 1 FROM DUAL cũng làm việc với H2. –

+0

Cảm ơn, đó là điều tốt để biết. Tôi đã cập nhật câu trả lời. –

+2

Tôi biết đây là một vài năm tuổi nhưng bạn có thể muốn thêm cả hai 'GIÁ TRỊ 1' và' CHỌN 1 TỪ SYSIBM.SYSDUMMY1' cho Apache Derby – megaflop

5

Rất tiếc, không có câu lệnh SELECT nào sẽ luôn hoạt động bất kể cơ sở dữ liệu.

Hầu hết cơ sở dữ liệu hỗ trợ:

SELECT 1 

Một số cơ sở dữ liệu không hỗ trợ này, nhưng có một bảng gọi là DUAL mà bạn có thể sử dụng khi bạn không cần một bảng:

SELECT 1 FROM DUAL 

MySQL cũng hỗ trợ điều này vì lý do tương thích, nhưng không phải tất cả các cơ sở dữ liệu đều làm. Cách giải quyết cho các cơ sở dữ liệu không hỗ trợ một trong hai bên trên là tạo ra một bảng có tên là DUAL có chứa một hàng duy nhất, sau đó ở trên sẽ hoạt động.

HSQLDB hỗ trợ cả những điều trên, vì vậy bạn có thể tạo bảng DUAL hoặc sử dụng khác:

SELECT 1 FROM any_table_that_you_know_exists_in_your_database 
+0

Không hoạt động với SQL Server. –

+0

Cảm ơn câu trả lời. Tôi đã cập nhật câu hỏi của tôi một chút do "của bạn không có tuyên bố SELECT sẽ luôn luôn làm việc" tuyên bố. 'SELECT 1 FROM DUAL' cũng không hoạt động với HSQLDB. –

+1

+1, đây là về nơi tôi đã đi với nghiên cứu của tôi là tốt, đặc biệt là đối với trường hợp HSQLDB. –

1

select 1 sẽ làm việc trong máy chủ sql, không chắc chắn về những người khác.

Sử dụng tiêu chuẩn ansi sql để tạo bảng và sau đó truy vấn từ bảng đó.

+0

Ansi SQL có bao gồm 'tạo bảng' không? –

+0

có. Nếu bạn sử dụng các loại dữ liệu ansi. Tôi sẽ ngạc nhiên nếu "chọn 1" không hoạt động. – NimChimpsky

2

tôi sử dụng cái này:

select max(table_catalog) as x from information_schema.tables 

để kiểm tra kết nối và khả năng chạy các truy vấn (với 1 hàng như kết quả) cho PostgreSQL, MySQL và MSSQL.

1

tôi sử dụng

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

cho HSQLDB 1.8.0

1

Giả sử OP muốn một câu trả lời Java:

Tính đến JDBC3/Java 6 có các isValid() phương pháp mà nên được sử dụng chứ không phải là phát minh ra phương pháp riêng của mình.

Trình cài đặt của trình điều khiển được yêu cầu thực hiện một số loại truy vấn đối với cơ sở dữ liệu khi id phương thức này được gọi. Bạn - với tư cách là người dùng JDBC đơn thuần - không cần phải biết hoặc hiểu truy vấn này là gì. Tất cả những gì bạn phải làm là tin tưởng rằng người tạo trình điều khiển JDBC đã thực hiện công việc của mình đúng cách.

+2

Tôi tin rằng OP đang nói về truy vấn xác thực cho cấu hình nhóm kết nối của vùng chứa chứ không phải theo lập trình. Ví dụ: trong tệp context.xml của Tomcat, nơi bạn thiết lập Tài nguyên, nó lấy một validationQuery mà Tomcat sử dụng để xác thực kết nối. Bản thân Tomcat sẽ phải được thay đổi để tận dụng lợi thế của isValid(). Đó không phải là điều mà OP có thể kiểm soát. – Michael

+0

Cũng đáng chú ý là "người tạo trình điều khiển JDBC đã thực hiện công việc của mình đúng cách" không thực sự được đảm bảo. Tôi chỉ thấy rằng cả Postgres, HSQLDB và H2 đều không thực hiện phương thức này, vì vậy nó sẽ luôn đưa ra một ngoại lệ ở đó. – akroy

1

Làm thế nào về

SELECT user() 

tôi sử dụng before.MySQL này, H2 là OK, tôi không biết những người khác.

2

Đối với các thử nghiệm sử dụng select count(*), sẽ hiệu quả hơn khi sử dụng select count(1)* có thể làm cho nó đọc tất cả dữ liệu cột.

6

Nếu trình điều khiển của bạn tuân thủ JDBC 4, không cần truy vấn chuyên dụng để kiểm tra kết nối. Thay vào đó, có Connection.isValid để kiểm tra kết nối.

JDBC 4 là một phần của Java 6 từ năm 2006 và trình điều khiển của bạn sẽ hỗ trợ tính năng này ngay bây giờ!

hồ kết nối nổi tiếng, như HikariCP, vẫn có một tham số cấu hình để xác định một truy vấn thử nghiệm nhưng mạnh mẽ khuyến khích sử dụng:

connectionTestQuery

Nếu trình điều khiển của bạn hỗ trợ JDBC4 chúng tôi đặc biệt khuyên bạn không thiết lập tài sản này. Đây là cơ sở dữ liệu "cũ" không hỗ trợ API JDBC4 Connection.isValid(). Đây là truy vấn sẽ được thực hiện ngay trước khi kết nối được cung cấp cho bạn từ hồ bơi để xác thực rằng kết nối với cơ sở dữ liệu vẫn là còn sống. Một lần nữa, hãy thử chạy các hồ bơi mà không có tài sản này, HikariCP sẽ đăng nhập một lỗi nếu trình điều khiển của bạn không tuân thủ JDBC4 để cho bạn biết. Mặc định: none

0

Chỉ cần phát hiện ra cách cứng mà nó là

SELECT 1 FROM DUAL 

cho MaxDB là tốt.

+0

Điều này không cung cấp câu trả lời cho câu hỏi. Khi bạn có đủ [danh tiếng] (http://stackoverflow.com/help/whats-reputation), bạn sẽ có thể [nhận xét về bất kỳ bài đăng nào] (http://stackoverflow.com/help/privileges/comment); thay vào đó, [cung cấp câu trả lời không yêu cầu làm rõ từ người hỏi] (http://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-thay thế). - [Từ đánh giá] (/ review/low-quality-posts/14092840) –

+0

Tôi không hiểu, nó làm tăng thêm giá trị cho câu trả lời được chấp nhận, vậy đâu là vấn đề? –

+0

Và như bạn đã đề cập: như tôi không thể bình luận câu trả lời được chấp nhận, vì vậy tôi đặt nó như là một câu trả lời ở đây. Vì vậy, tốt hơn không viết một bài viết mặc dù nó có thể hữu ích chỉ vì thiếu danh tiếng? –

0

tôi sử dụng này cho Firebird

select 1 from RDB$RELATION_FIELDS rows 1 
0

Đối MSSQL.

Điều này giúp tôi xác định xem máy chủ được liên kết có còn hoạt động hay không. Sử dụng một kết nối truy vấn mở và một TRY CATCH để đưa các kết quả của lỗi vào một cái gì đó hữu ích.

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

Các vấn đề liên quan