电脑技术学习

在SQL Server数据库中使用批处理的注意事项

dn001

  在Windows操作系统中,可以通过批处理程序来让操作系统执行一连串的操作。而SQL server数据库作为微软的又一拳头产品,在其中也实现了批处理的管理机制。简单的说,批处理就是应用程序发送到SQL Server数据库中并得以执行的一组单条或者多条T-SQL语句。数据库会将这个批处理的语句编译为单个可执行单元,即所谓的执行计划,然后加以执行。对于批处理的作用估计不用笔者多说了。笔者这里主要说说在利用批处理来进行批次操作时需要注意的事项。

  一、批处理编译错误或者运行错误对数据库的影响。

  假设现在有一个批处理语句,其中有五条T-SQL语句。这个批处理语句传递到SQL Server数据库之后,数据库系统会先对这个语句进行编译。如果编译错误那么对数据库会有什么影响呢?通常情况下,由于语法错误等因素导致的编译错误会使得可执行计划无法编译。也就是说,此时这个批处理语句中的任何语句都得不到执行。故在批处理语句编译错误的情况下,基本上不会对数据库产生任何影响。

  如果批处理程序编译通过,但是在执行的过程中出现了问题,那么又会对数据库产生什么影响呢?如上面所说的一个批处理程序有五条语句,编译通过后,如果在执行过程中由于一些意外原因导致第三条语句执行失败,此时会对数据库产生什么样的影响?此时就需要根据不同的情况来对待。如果这个错误是因为违反约束所造成的,那么批处理程序仅仅停止执行当前语句,而继续执行批处理中的其他语句。也就是说,由于违反约束而导致批处理程序运行错误的话,那么只影响那条违反约束规则等语句,前面的与后面的语句仍然将得以执行。针对于数据库管理员可能是不喜欢看到的,因为这会破坏数据的一致性。除了违反约束这种情况外,大部分情况下运行时错误将停止执行批处理中当前语句和它之后的其他语句。也就是说,如果在执行第三条语句时发生了错误,则其后面的语句都将不执行。但是其前面已经执行的语句将不受到影响。

  可见无论是违反约束这种错误情况,还是其他的错误情况,当遇到错误时,都有可能批处理中某些语句得到了有效的执行。这往往与数据库管理员或者应用程序开发者的设计意图相悖。因为他们之所以要设计这个批处理程序,往往是让它来实现一整套的功能。如果数据库无法实现这个功能的话,那么他们宁愿一条语句的不执行。如果只执行部分语句的话,会对数据库的一致性产生比较大的负面影响。为了保证批处理程序在遇到错误时,无论是什么错误,都不会对数据库造成负面影响,此时笔者建议数据库管理员或者程序开发者把批处理程序跟事务结合起来使用。也就是说,将批处理程序放置在事务中。如此的话,当批处理程序在运行的过程中遇到错误的话,会导致事务会滚。如此的话,在所有运行的错误之前执行的未提交的数据修改都将被回滚。这就可以避免因为批处理程序运行错误而导致的数据损坏问题。

  二、养成以分号结束语句的习惯。

  在编写批处理程序时,最好能够以分号结束相关的语句。虽然这不是数据库中的强制要求,但是笔者还是强烈建议如此处理。一方面这有利于提高批处理程序的可读性。批处理程序往往用来完成一些比较复杂的成套的功能,而每条语句则完成一项独立的功能。为此有时会一个比较复杂一些的批处理程序其往往有上百行的内容。此时为了提高其可读性,最好能够利用分号来进行语句与语句之间的分隔。二是与未来版本的兼容性。其实SQL Server数据库在设计的时候,一开始这方面就把关不严。现在大部分的标准程序编器都实现了类似的强制控制。根据宪梓微软官方提供的资料来看,在以后的SQL Server数据库版本中,这个规则可能会成为一个强执行的规则,即必须在每条语句后面利用分号来进行分隔。为此为了能够跟后续的SQL Server数据库版本进行兼容,最好从现在开始就采用分号来分隔批处理程序中的每条语句。

  三、批处理程序语句所处理对象不存在或不符合会如何处理?

  如现在某个批处理程序中有五条语句,其中第一条语句是创建表User,第三条语句是往表User中插入数据(插入的数据与第一条语句中定义的数据类型不符合)。当应用程序把这个批处理程序发给SQL Server数据库的时候,系统会对这个批处理对象进行编译。注意此时只是编译,而没有执行。编译只要语法没有错误即可。最后这个批处理程序会被编译成功,但是没有执行,即没有创建User表。编译完成后,这个批处理程序会运行。第一条语句编译后运行没有错误,但是运行到第二条语句的时候由于需要插入的数据跟第一条语句中所建立的数据库对象不符合,则第三条语句会编译失败。此时批处理终止。笔者举这个例子是为了说明2008数据库版本的一个改善,即对于批处理程序中的语句,数据库是编译一条,而执行一条。

  假设这个批处理程序若放在2000版本的SQL Server数据库中,就会出现一个截然不同的结果。由于在2000版本中,对于批处理程序都是整篇编译的。此时在编译的时候就会发现这个对象不符的错误。具体哪一种处理机制好也是各人各有各的看法。笔者还是比较倾向于以前版本的处理方法,即整篇编译。这虽然可能会影响数据库的性能,但是影响不会很大;但是却可以提高批处理程序的正确性。或者说,由此带来的性能方面的损失,可能要比由此对来的对数据库数据的破坏性损失要小的多。不过在这方面各个数据库专家谁也说服不了谁。

 四、批处理程序书写的一些限制要求。

  由于批处理程序中往往需要完成一整套的功能。而且一旦批处理程序开始运行时,就会缺少用户的监督。或者说,互动性会比较差。为此如何保障批处理程序语句的有效性就显得尤其的重要。为此在书写批处理程序时,数据库设置了一些严格的规范。这些规范跟上面所提高的利用分号来分隔批处理程序语句不同。这里提到的规范具有强制性,即为反这个规则的话将会发生变异错误,批处理程序得不到执行。而上面提到的分号规则不具有强制性,其编辑时不会发生语法性错误,在没有其他错误的情况下可以正常执行这个批处理语句。

  如不能够在同一个批处理中更改表,然后引用新列。如在一个批处理程序中,有两条语句。第一条语句用来在一张表中插入一个字段,如在User表中插入员工的出生年月;第二条语句则用来引用这个列,如根据身份证号码来推算出这个员工的出身年月并把这个值赋值给这个第一条语句创建的出身年月字段。这个批处理程序是非法的。因为在第一条语句中其引用了第一条语句创建的新列。这是批处理文件书写中的一条红线,不得违背。但是注意,如果第一条语句不是增加了某个列,而是通过创建表的方式来创建列,那么后面的语句就可以引用这些列。也就说,如果第一条语句创建了一个表User,其中有出身年月这个字段。则在第二条语句中就可以利用这个出身年月字段,如可以利用insert语句为其进行赋值。这个细小的差异要引起数据库管理员的注意。

  通常情况下,一个批处理程序可以包含多条语句。但是在一些特定的情况下会有例外。如果在批处理程序中包含了一些特殊的语句,则此时批处理程序中之能够包含一条语句。如在批处理文件中利用Create View语句创建视图时,就不能够与其他语句组合使用。此时所有跟在该批处理后的其他语句都将被解释为第一个Create语句定义的一部分。另外需要注意的是,如果 EXECUTE 语句是批处理中的第一句,则不需要 EXECUTE 关键字。如果 EXECUTE 语句不是批处理中的第一条语句,则需要 EXECUTE 关键字。

  以上这些都是强制性的规则,数据库管理员在书写批处理程序时必须无条件的遵守。另外笔者再强调一次,这个批处理程序最好能够跟事务结合使用,以防止部分语句执行错误时对数据以执行的破坏。同时最好能够在批处理程序中插入意外处理语句。即使批处理程序全部执行成功,也最好能够给前台客户端发送一些反馈信息,以提高批处理程序与用户之间的互动性。