使python等待存储过程完成执行
我有一个python脚本,它使用pyodbc调用MSSQL存储过程,如下所示:使python等待存储过程完成执行,python,sql,sql-server,stored-procedures,pyodbc,Python,Sql,Sql Server,Stored Procedures,Pyodbc,我有一个python脚本,它使用pyodbc调用MSSQL存储过程,如下所示: cursor.execute("exec MyProcedure @param1 = '" + myparam + "'") 我在一个循环中调用这个存储过程,我注意到有时,在上次执行完成之前,该过程会再次被调用。我知道这一点,因为如果我添加行 time.sleep(1) 执行行之后,一切正常 有没有一种更优雅、花费更少时间的方式来表达“睡到执行官结束” 更新(Divij的解决方案):此代码目前不适用于我: fro
cursor.execute("exec MyProcedure @param1 = '" + myparam + "'")
我在一个循环中调用这个存储过程,我注意到有时,在上次执行完成之前,该过程会再次被调用。我知道这一点,因为如果我添加行
time.sleep(1)
执行行之后,一切正常
有没有一种更优雅、花费更少时间的方式来表达“睡到执行官结束”
更新(Divij的解决方案):此代码目前不适用于我:
from tornado import gen
import pyodbc
@gen.engine
def func(*args, **kwargs):
# connect to db
cnxn_str = """
Driver={SQL Server Native Client 11.0};
Server=172.16.111.235\SQLEXPRESS;
Database=CellTestData2;
UID=sa;
PWD=Welcome!;
"""
cnxn = pyodbc.connect(cnxn_str)
cnxn.autocommit = True
cursor = cnxn.cursor()
for _ in range(5):
yield gen.Task(cursor.execute, 'exec longtest')
return
func()
没有内置python允许您等待异步调用完成。然而,您可以使用Tornado的iLoop实现这种行为。Tornado的
gen
界面允许您将函数调用注册为任务
,并在调用完成后返回函数中的下一行。下面是一个使用gen
和gen.Task
来自tornado导入gen的
@发电机
def func(*args,**kwargs)
对于范围(5)内的uu:
生成gen.Task(异步函数调用,arg1,arg2)
返回
在本例中,func
的执行在async\u function\u调用
完成后恢复。这样,对asnyc\u函数的后续调用不会重叠,并且您不必在时间内暂停主进程的执行。sleep
调用。以下是我的解决方法:
在数据库中,我创建了一个名为RunningStatus
的表,其中只有一个字段status
,它是一个位,只有一行,最初设置为0
在存储过程开始时,我执行
update RunningStatus set status = 1;
在存储过程的末尾
update RunningStatus set status = 0;
在我的Python脚本中,我打开了一个新连接,并将光标指向同一个数据库。在我的execute
行之后,我只需添加
while 1:
q = status_check_cursor.execute('select status from RunningStatus').fetchone()
if q[0] == 0:
break
您需要建立一个新连接和游标,因为来自旧连接的任何调用都将中断存储过程,并可能导致status
永远不会返回0
这有点刺耳,但对我来说效果很好 我认为我的方法有点粗糙,但同时也更容易理解:
cursor = connection.cursor()
SQLCommand = ("IF EXISTS(SELECT 1 FROM msdb.dbo.sysjobs J JOIN
msdb.dbo.sysjobactivity A ON A.job_id = J.job_id WHERE J.name ='dbo.SPNAME' AND
A.run_requested_date IS NOT NULL AND A.stop_execution_date IS NULL) select 'The job is
running!' ELSE select 'The job is not running.'")
cursor.execute(SQLCommand)
results = cursor.fetchone()
sresult= str(results)
while "The job is not running" in sresult:
time.sleep(1)
cursor.execute(SQLCommand)
results = cursor.fetchone()
sresult= str(results)
当“SPNAME”从jobactivity表返回“作业未运行”时,请休眠1秒并再次检查结果。
这个sql作业的工作,对于SP,应该像在另一个表中一样我知道这很旧,但我只是花了几个小时试图弄清楚如何让Python代码等待MSSQL上的存储过程完成
问题不在于异步调用
解决此问题的关键是确保过程在完成运行之前不会返回任何消息。否则,PYDOBC将来自proc的第一条消息解释为它的结束
使用设置NOCOUNT ON
运行您的过程。另外,确保可能用于调试的任何PRINT
语句或RAISERROR
都已禁用
在进程中添加一个位参数,如@muted
,只有当它是0
时才会引发调试消息
在我的特殊情况下,我正在执行一个proc来处理一个加载的表,而我的应用程序在该过程完成运行之前正在退出并关闭游标,因为我正在获取行计数和调试消息
总结一下,按照
cursor.execute('SET NOCOUNT ON;EXEC schema.proc@muted=1')
PYODBC将等待进程完成。谢谢您的回答!我正在阅读tornado.gen文档,对于任务函数如何与pyodbc光标一起工作,我有点困惑。对cursor.execute
的调用是作为async\u function\u call
的一部分包含的,还是在没有pyodbc的情况下执行存储过程?如果是后者,它如何连接到数据库?理想情况下,您可以将异步函数调用
替换为游标。执行
并将要执行的过程作为参数传递。因此,您的行应该是:yield gen.Task(cursor.execute,“exec MyProcedure@param1'%s'”%myparam)
我尝试了这个确切的示例,但它给了我TypeError:execute()不接受关键字参数
。它对您是否正常工作?嗯,您能将代码中出现错误的那一行粘贴到这里吗?另外,由于要执行的命令涉及字符串插值,因此我会尝试先将命令存储为变量,然后将变量作为参数传递。我制作了一个测试python脚本,该脚本仅连接到MSSQL数据库,然后执行您答案中的确切代码。我创建了一个名为longtest
的存储过程,它基本上只是循环并多次递增计数器。我在行中得到错误,yield gen.Task(cursor.execute,'exec longtest')
。有什么想法吗?太棒了<代码>设置不计数
保存了我的一天!如果存储过程保证在没有错误的情况下运行,这是非常好的,但是如果存储过程在执行过程中可能出错,请小心。如果从未将状态设置回0,则会导致Python脚本中出现无限循环。