zxjdbc调用存储过程的正确用法是什么?

时间:2013-08-05 10:30:13

标签: java sql-server stored-procedures jdbc jython

我正在尝试使用zxJDBC连接到在SQL Server 2008 R2(Express)上运行的数据库并调用存储过程,并向其传递一个参数。我正在使用jython-standalone 2.5.3,理想情况下不想安装其他模块。

我的测试代码如下所示。

数据库名称为CSM

存储过程:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      <Author,,Name>
-- Create date: <Create Date,,>
-- Description: <Description,,>
-- =============================================
CREATE PROCEDURE dbo.DUMMY 
    -- Add the parameters for the stored procedure here
    @carrierId VARCHAR(50)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- Insert statements for procedure here
    INSERT INTO dbo.carrier (carrierId, test)
    VALUES (@carrierId, 'Success')
END
GO

Jython脚本:

from com.ziclix.python.sql import zxJDBC

conn = None
try :
    conn = zxJDBC.connect('jdbc:sqlserver://localhost\SQLEXPRESS', 'sa', 'password', 'com.microsoft.sqlserver.jdbc.SQLServerDriver')
    cur = conn.cursor()
    cur.callproc(('CSM','dbo','DUMMY'), ['carrier1'])
    conn.commit()
except Exception, err :
    print err
    if conn:
        conn.rollback()
finally :
    if conn :
        conn.close()

通过使用cur.execute()我已经能够验证上面是否成功连接到数据库,并且我可以查询它。但是,到目前为止,我还无法使用参数成功调用存储过程。

文档here(可能已过期?)表示可以使用字符串或元组调用callproc()来标识过程。给出的例子 -

c.callproc(("northwind", "dbo", "SalesByCategory"), ["Seafood", "1998"], maxrows=2)

当我尝试使用此方法时,收到以下错误

Error("Could not find stored procedure 'CSM.DUMMY'. [SQLCode: 2812], [SQLState: S00062]",)

看来zxJDBC忽略了包含过程标识符的dbo部分。

如果我用“CSM.dbo.DUMMY”作为第一个参数调用callproc,那么我会收到此错误

Error('An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name. [SQLCode: 1038], [SQLState: S0004]',)

在运行我的脚本时在数据库上使用分析器显示在第二种情况下执行以下SQL:

use []
go

因此,当使用单个字符串来标识过程时,似乎未正确解析数据库名称。

我尝试解决此问题之一是尝试调用callproc,如下所示:

cur.callproc(('CSM', '', 'dbo.DUMMY'), ['carrier1'])

这让我只有

Error("Procedure or function 'DUMMY' expects parameter '@carrierId', which was not supplied. [SQLCode: 201], [SQLState: S0004]",)

在这种情况下,我认为正在发生的是zxJDBC尝试调用系统存储过程(sp_proc_columns)来确定我想要调用的存储过程所需的参数。我的猜测是,如果过程标识符的格式不正确,则zxJDBC无法获得有效/正确的返回值,并假设不需要参数。

所以基本上我并没有因为如何把它变成

而陷入困境
  • 使用正确的数据库名称
  • 使用sp_proc_columns
  • 正确确定所需参数
  • 使用正确的名称
  • 调用我的存储过程

所有这些都在同一时间。

我确实有一个解决方法,就是使用像

这样的东西
cur.execute('EXEC CSM.dbo.DUMMY ?', ['carrier1'])

但是我觉得callproc()是正确的解决方案,并且在我调用具有大量参数的存储过程时可能会生成更清晰的代码。

如果有人能够发现我正在犯的错误,或者知道这不会像我想的那样发挥作用,那么任何意见都会非常感激。

由于

修改

正如i-one所建议的那样,我在调用我的存储过程之前尝试添加cur.execute('USE CSM')(同时从过程调用中删除数据库名称)。遗憾的是,这会产生与上面相同的对象或列缺失错误。分析器显示正在执行USE CSM,然后是USE [],因此似乎callproc()始终在过程本身之前触发USE语句。

我还尝试过打开/关闭自动提交,但无济于事。

修改2

以下评论/建议解决方案的更多信息:

  • 我的连接字符串中的“SQLEXPRESS”是数据库实例名称。
  • 使用双引号而不是单引号无效。
  • 在连接字符串中包含数据库名称(通过;databaseName=CSM;指定here)并从callproc()调用中省略它会导致原始错误,并触发USE []语句

使用callproc(('CSM', 'dbo', 'dbo.DUMMY'), ['carrier1'])会给我一些进展,但会导致错误

错误(“过程或函数'DUMMY'期望参数'@carrierId',未提供。[SQLCode:201],[SQLState:S0004]”,)

我会尝试进一步调查

编辑3

基于我可以看到zxJDBC触发的查询,我手动对我的数据库执行了以下操作:

use CSM
go
exec sp_sproc_columns_100 N'dbo.DUMMY',N'dbo',N'CSM',NULL,N'3'
go

这给了我一个空的结果集,这似乎解释了为什么zxJDBC没有将任何参数传递给存储过程 - 它认为它不需要。我还没弄清楚为什么会发生这种情况。

编辑4

要更新上述内容,空结果集是因为调用应该是

exec sp_sproc_columns_100 N'DUMMY',N'dbo',N'CSM',NULL,N'3'

这很遗憾地给我带来了完整的循环,因为我无法从callproc()调用中的存储过程名称中删除dbo所有者,或者根本找不到该过程。

编辑5

请求的表定义

CREATE TABLE [dbo].[carrier](
    [carrierId] [varchar](50) NOT NULL,
    [test] [varchar](50) NULL
) ON [PRIMARY]

2 个答案:

答案 0 :(得分:3)

虽然完全没有意识到这里使用的技术(除非有一些SQL Server的小知识),但我会尝试一个答案(请原谅我,如果我的jython语法不正确。我试图概述这里的可能性而不是确切的代码)< / p>

我的第一种方法(在this post处找到)将尝试:

cur.execute("use CSM")
cur.callproc(("CSM","dbo","dbo.DUMMY"), ["carrier1"])

这必须与sa用户始终将dbo作为默认架构(在this SO post中描述)

这一事实有关。

如果上述方法不起作用,我还会尝试在JDBC URL中使用CSM数据库名称(这在将JDBC用于其他数据库时非常常见),然后只需调用以下两个中的一个。 / p>

cur.callproc("DUMMY", ["carrier1"])
cur.callproc("dbo.DUMMY", ["carrier1"])

我希望这会有所帮助

更新:我引用了您无法查看的链接的相关部分

>> Program calls a Stored Procedure - master.dbo.xp_fixeddrives on  MS SQL Server

from com.ziclix.python.sql import zxJDBC

def getConnection():
    url = "${DBServer.Url}"
    user= "${DBServer.User}"
    password = "${DBServer.Password}"
    driver = "${DBServer.Driver}"
    con = zxJDBC.connect(url, user, password, driver)
    return con

try:
    conn = getConnection()
    print 'Connection successful'
    cur = conn.cursor()
    cur.execute("use master")
    cur.callproc(("master", "dbo", "dbo.xp_fixeddrives"))
    print cur.description
    for a in cur.fetchall():
        print a
finally:
    cur.close()
    conn.close()
    print 'Connection closed'

指定上述调用函数时出现的错误表明该参数未正确传递。因此,请修改存储过程以获取默认值,并尝试通过params = [None]调用。如果您看到调用成功,那么就指定数据库而言,我们必须做正确的事情。 顺便说一句:most recent documentation建议您应该能够使用语法访问它。

答案 1 :(得分:3)

如评论中所述 callproc 仅适用于SELECT。请尝试这种方法:

cur.execute("exec CSM.dbo.DUMMY @Param1='" + str(Param1) + "', @carrierId=" + str(carrierID))

有关详细信息,请参阅this link