Java 操作 SQLServer 版本差异、常见问题总结

Jan 2, 2019 阅读(514)

标签: Java SQLServer

调用存储过程阻塞问题排查

使用 JDBC 操作数据库先将数据写临时表,然后执行存错过程, SQLServer 2008 是好好的, 到了 SQLServer 2000 就卡到执行储存过程代码处。错误代码如下:

CallableStatement callableStatement = connection.prepareCall("{call upgettransout(?,?,?,?,?)}");
//输入参数
callableStatement.setString("_sheetno", sheetno);

//输出参数
callableStatement.registerOutParameter("pos_money", Types.VARCHAR);
callableStatement.registerOutParameter("invoice_duty_no", Types.VARCHAR);
callableStatement.registerOutParameter("result", Types.INTEGER);
callableStatement.registerOutParameter("msg", Types.VARCHAR);
callableStatement.execute();

if(1 == callableStatement.getInt("result")) {//成功
    double pos_money = callableStatement.getDouble("pos_money");
    String invoice_duty_no = callableStatement.getString("invoice_duty_no");
    log.info(sheetno + " ,订单存储过程过机成功,pos_money: " + pos_money + " ,invoice_duty_no: " + invoice_duty_no);
    postOrderSuccess(Config.getInstance().getEnt_id(), channel_sheetno, (100 == sale_type) ? null : sheetno, invoice_duty_no, pos_money);
}else {
	log.error(sheetno + " ,订单存储过程过机执行失败," + callableStatement.getString("msg"));
}

通过 debug 发现 callableStatement.setString("_sheetno", sheetno);  绑定参数处阻塞不往后继续运行也不抛出异常。这可能是 SQL Server 2000 驱动包支持参数名称绑定参数的bug。以下是改后的正确兼容代码:

log.debug("准备调用 {call qnh_upgettransout(_sheetno,pos_money,invoice_duty_no,result,msg)} 存储过程核销");
CallableStatement callableStatement = connection.prepareCall("{call qnh_upgettransout(?,?,?,?,?)}");
//输入参数
callableStatement.setString(1, sheetno);
log.debug("绑定存储过程入参完成, _sheetno:" + sheetno);

//输出参数
callableStatement.registerOutParameter(2, Types.VARCHAR);
callableStatement.registerOutParameter(3, Types.VARCHAR);
callableStatement.registerOutParameter(4, Types.INTEGER);
callableStatement.registerOutParameter(5, Types.VARCHAR);

log.debug("准备执行存储过程, _sheetno:" + sheetno);
callableStatement.execute();
log.debug("存储过程执行完成, _sheetno:" + sheetno);
if(1 == callableStatement.getInt("result")) {//成功
    double pos_money = callableStatement.getDouble("pos_money");
    String invoice_duty_no = callableStatement.getString("invoice_duty_no");
    log.info(sheetno + " ,订单存储过程过机成功,pos_money: " + pos_money + " ,invoice_duty_no: " + invoice_duty_no);
    postOrderSuccess(Config.getInstance().getEnt_id(), channel_sheetno, (100 == sale_type) ? null : sheetno, invoice_duty_no, pos_money);
}else {
	log.error(sheetno + " ,订单存储过程过机执行失败," + callableStatement.getString("msg"));
}

 

开发过程中的 SQLException

异常信息如下:

java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Can't start a cloned connection while in manual transaction mode.
	at com.microsoft.jdbc.base.BaseExceptions.createException(Unknown Source)
	at com.microsoft.jdbc.base.BaseExceptions.getException(Unknown Source)
	at com.microsoft.jdbc.base.BaseConnection.getImplConnection(Unknown Source)
	at com.microsoft.jdbc.base.BaseStatement.setupImplConnection(Unknown Source)
	at com.microsoft.jdbc.base.BaseStatement.<init>(Unknown Source)
	at com.microsoft.jdbc.base.BasePreparedStatement.<init>(Unknown Source)
	at com.microsoft.jdbc.base.BaseConnection.prepareStatement(Unknown Source)
	at com.microsoft.jdbc.base.BaseConnection.prepareStatement(Unknown Source)

解决办法是将数据库连接语句加上 “SelectMethod=cursor ”,如下实例:

String url = "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=enterprise;SelectMethod=cursor";

 

总结以下使用 SQL Server 不同版本时JDBC的区别

  • 驱动包不同,驱动类不同

SQL Server 2000 driver: com.microsoft.jdbc.sqlserver.SQLServerDriver

SQL Server 2008 driver: com.microsoft.sqlserver.jdbc.SQLServerDriver

  • 驱动 RUL 不同

SQL Server 2000 URL: jdbc:microsoft:sqlserver://ip:port;DatabaseName=dbname

SQL Server 2008 URL: jdbc:sqlserver://ip:port;DatabaseName=dbname

  • 执行存储过程参数绑定支持程度不同

SQL Server 2000:  只支持 索引序号 来绑定参数;

SQL Server 2008: 支持 索引序号 及 参数名称 绑定参数;

 

 

MongoDB学习园