我们最近将我们的开发数据库从SQL Server 2005移到了SQL Server 2008 R2,我们遇到了以下情况。
如果我们插入带有DATETIME列的记录,然后我们尝试在where子句中使用此插入时间,则查询有时不返回任何结果,这是因为DATETIME数据类型发生的舍入。
以下是如何复制此行为的示例:
import java.sql.*;
public class JDBCTest {
public static void main( String args[] )
{
try
{
// Load the database driver
Class.forName( "com.microsoft.sqlserver.jdbc.SQLServerDriver" ) ;
// Get a connection to the database
Connection conn = DriverManager.getConnection("jdbc:sqlserver://DEVENV;user=?;" +
"password=?;databaseName=jdbctest" ) ;
//Insert
PreparedStatement ps = conn.prepareStatement( "INSERT INTO dbo.test VALUES (?)" ) ;
java.util.Date date= new java.util.Date();
java.sql.Timestamp currentTimestamp= new java.sql.Timestamp(date.getTime());
ps.setTimestamp(1, currentTimestamp );
ps.execute();
ps.close() ;
PreparedStatement psSel = conn.prepareStatement( "SELECT * FROM test WHERE date = ?" ) ;
psSel.setTimestamp(1,currentTimestamp);
ResultSet rs = psSel.executeQuery() ;
if (rs.next()){
while( rs.next() ) System.out.println( rs.getString("id") + " " + rs.getString("date") ) ;
}
else {
System.out.println("NO RESULTS!");
}
rs.close() ;
psSel.close() ;
conn.close() ;
}
catch( Exception e )
{
System.out.println( e ) ;
}
}
}
使用SQL事件探查器,我们看到执行了以下操作:
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@P0 datetime2',N'INSERT INTO dbo.test VALUES (@P0) ','2014-04-24 09:49:41.3360000'
select @p1
在数据库中,这是插入的记录:
2014-04-24 09:49:41.337
执行where时,会将以下内容发送到数据库:
declare @p1 int
set @p1=0
exec sp_prepexec @p1 output,N'@P0 datetime2',N'SELECT * FROM test WHERE date = @P0 ','2014-04-24 09:49:41.3360000'
select @p1
SELECT不返回任何数据。问题是由于某种原因,JDBC驱动程序将参数作为DATETIME2发送,然后引擎比较DATETIME和DATETIME2而不考虑DATETIME的舍入,因此where子句失败。
使用SQL Server 2005时,行为是预期的行为,因为在2008版本中引入了DATETIME2。
到目前为止,我们提出的解决方案是隐式地将参数转换为DATETIME。从长远来看,将数据库DATETIME列更改为DATETIME2,但同时最后一个解决方案是不可行的。
此问题是否有解决方法?