存储过程和触发器执行阻止

时间:2019-10-16 19:13:43

标签: sql-server stored-procedures clr database-trigger sqlclr

我拥有SQL Server 2017 Express数据库,最多可通过REST Web服务通过Angular 7应用程序连接的6个平板电脑访问。

我有一个存储过程,该过程允许将新用户插入特定的数据库表中。插入一次总是只能插入1条记录,但是对于6个客户端,每个客户端几乎可以同时调用存储过程。

该过程的最后一步是将协议表格打印到特定打印机。最初,这将在客户端进行处理,但是平板电脑无法打印到网络打印机,因此功能现在需要驻留在服务器端。

对于此新要求,协议表是要读取的RTF文档,占位符值将替换为insert语句中的值,并写入临时文件,然后通过应用程序(最可能是写字板)打印到网络打印机与RTF文件格式相关联。

还有一个MS Access前端应用程序,该应用程序使用链接的服务器连接到数据库,但是不具备创建新用户的能力,但是需要能够在Windows中启动“打印协议”操作。由于打印机问题,网络问题等原因导致无法打印协议的情况。

我编写了C#代码,以执行使用UseShellExecute StartInfo属性和Process.Start方法的表单的读取/修改/写入/打印操作。

由于文件的读取/修改/写入/打印过程需要花费几秒钟,因此我担心要在这段时间内添加用于阻止注册的存储过程。

我非常确定我将需要一个CLR存储过程,以便MS Access前端可以启动打印操作,因此我想出的是“ Add_Registration”存储过程(Transact-SQL)。 )将调用CLR存储过程以执行读/修改/写/打印操作,或者在调用CLR存储过程以读取/修改/写/打印的表上插入插入触发器(CLR或Transact-SQL)。 / p>

如果有令人信服的理由,我可以通过在CLR触发器和CLR存储过程中都复制代码来避免从触发器调用存储过程,但是如果可能的话,我试图避免重复代码。

我目前正在考虑的解决方案如下,但是不确定SQL Server如何处理各种情况:

  1. 注册表上的CLR或Transact-SQL Insert触发器,它调用执行读取/修改/写入/打印过程的CLR存储过程。

  2. 一个CLR存储过程,它执行读取/修改/写入/打印过程,从当前的add_registration Transact-SQL存储过程中调用

我不断回到的问题是:

  1. 如果同时或几乎同时完成多个插入操作(每个操作仅进行一次插入操作),Insert CLR触发器如何执行,它们是排队等待然后同步处理还是立即执行?

  2. 与#1相同的问题,除了带有Transact-SQL触发器

  3. 如果多个客户端同时或几乎同时调用CLR存储过程,或者将它们排队,然后同步处理,还是立即执行对存储过程的每次调用,该如何处理? p>

  4. 与#3相同的问题,但带有Transact-SQL存储过程

  5. 如果从Transact-SQL触发器调用了CLR存储过程,则该触发器被阻塞,直到该存储过程返回为止,还是使用该命令在其自身的过程(或类似方法)中产生了对该存储过程的调用触发立即返回?

  6. 与#5相同的问题,除了带有调用CLR存储过程的CLR触发器

我正在寻找有关SQL Server如何处理这些方案的其他建议和/或说明。

1 个答案:

答案 0 :(得分:0)

除非您自己实施,否则没有排队,并且有几种方法可以做到这一点。因此,对于多个并发会话,它们都独立起作用。当然,当涉及到写入数据库(INSERT / UPDATE / DELETE /等等)时,它们显然会按照提交请求的顺序进行操作。

我不确定您为什么要在其中包含触发器,但由于与并发有关,触发器在由触发该触发器的DML语句启动的系统生成的事务中执行。这并不意味着您将拥有单线程INSERT,但是如果触发器正在调用需要一两秒钟才能完成的SQLCLR存储过程(并且触发器无法继续执行,直到存储过程完成/退出),那么就存在锁在该操作期间一直被保持在桌子上。这些锁可能不会阻止其他会话同时插入,但是您可能有其他操作试图修改该表,这些表需要冲突的锁,这些锁需要等待插入+触发器+ SQLCLR proc操作完成。当然,仅当您频繁插入时,这才可能是一个问题,但这取决于您期望新用户的频率,而这可能不会经常使您担心。


我也不确定为什么那时候需要打印任何内容。如果仅具有一个标志/ BIT列(指示是否已打印协议,默认为0),则在几个级别上可能要简单得多。然后,您可以让外部控制台应用程序通过SQL Server Agent或Windows计划任务进行计划,每隔几分钟执行一次,该应用程序从UsersWHERE HasPrintedAgreement = 0中读取。每行都有用于替换值的必填字段,它将打印每行,并在打印后更新UserID设置HasPrintedAgreement = 1。如果您总是希望立即达成协议,甚至可以安排该控制台应用程序每分钟执行一次。