处理数据库错误

Adobe AIR 1.0 和更高版本

通常,数据库错误处理与其他运行时错误处理类似。应该编写代码以备可能出现的错误,并对错误作出响应,而不是直到运行时才这样做。通常认为,可以将可能的数据库错误分为以下三类:连接错误、SQL 语法错误和约束错误。

连接错误

大多数的数据库错误是连接错误,它们可能出现在任何操作过程中。尽管存在防止连接错误的策略,但是,如果数据库是应用程序的关键部分,则几乎没有从连接错误中正常恢复的简单方法。

大多数连接错误与运行时和操作系统、文件系统及数据库文件交互的方式有关。例如,如果用户没有在文件系统上的特定位置创建数据库文件的权限,则会出现连接错误。以下策略有助于防止连接错误:

使用特定于用户的数据库文件
为每个用户提供其自己的数据库文件,而不是将单个数据库文件用于在单个计算机上使用应用程序的所有用户。该文件应该位于与用户帐户关联的目录中。例如,它可能在以下位置:应用程序的存储目录、用户的文档文件夹、用户的桌面等。

考虑不同的用户类型
在不同的操作系统上,用不同类型的用户帐户测试应用程序。请勿假定用户具有计算机上的管理员权限。此外,请勿假定安装了某应用程序的个人是运行该应用程序的用户。

考虑各个文件位置
如果允许用户指定保存数据库文件的位置或者选择要打开的文件,请考虑用户可能使用的文件位置。此外,请考虑定义对用户可以存储(或他们可以从中打开)数据库文件的位置的限制。例如,可以仅允许用户打开位于其用户帐户存储位置中的文件。

如果出现连接错误,则很可能出现在创建或打开数据库的首次尝试中。这意味着用户无法在应用程序中执行与数据库相关的任何操作。对于某些类型的错误,如只读或权限错误,一种可能的恢复技术是将数据库文件复制到其他位置。应用程序可以将数据库文件复制到用户有权创建和写入文件的其他位置,然后改用该位置。

语法错误

在 SQL 语句格式不正确,而应用程序尝试执行该语句时,会出现语法错误。由于本地数据库 SQL 语句是作为字符串创建的,因此无法进行编译时 SQL 语法检查。必须执行所有 SQL 语句才能检查其语法。使用以下策略可防止 SQL 语法错误:

全面地测试所有 SQL 语句
如有可能,在开发应用程序的过程中,将 SQL 语句编码为应用程序代码中的语句文本之前,单独对其进行测试。此外,使用代码测试方法(如单元测试)创建一组测试,在代码中运用每个可能的选项和变体。

使用语句参数和避免连接的(动态生成的)SQL
使用参数和避免动态生成的 SQL 语句,意味着每次执行语句时都使用相同的 SQL 语句文本。因此,测试语句和限制可能的变体更为容易。如果必须动态生成 SQL 语句,请将语句的动态部分保持在最小限度内。此外,仔细验证任何用户输入,以确保它不会导致语法错误。

若要从语法错误中恢复,应用程序将需要复杂的逻辑才能检查 SQL 语句和更正其语法。通过遵循用于防止语法错误的上述准则,您的代码可以识别 SQL 语法错误的任何潜在运行时根源(如语句中使用的用户输入)。若要从语法错误中恢复,请为用户提供指导。指出要更正哪些内容才能使语句正确执行。

约束错误

INSERT UPDATE 语句尝试向列添加数据时,会出现约束错误。如果新数据违反表或列的已定义约束之一,则会发生该错误。一组可能的约束包括:

唯一约束
指示对于表中的所有行,在一个列中不能有重复值。或者,将多个列组合在唯一约束中时,这些列中值的组合不得重复。换句话说,对于指定的具有唯一性的一列或多列,每个行必须是不同的。

主键约束
对于约束允许和不允许的数据,主键约束与唯一约束完全相同。

非 null 约束
指定单个列不能存储 NULL 值,因此在每个行中,该列必须具有一个值。

检查约束
允许您在一个或多个表上指定任意约束。常见的检查约束是一个规则,它定义列的值必须在某些界限内(例如,数字列的值必须大于 0)。另一种常见的检查约束类型指定列值之间的关系(例如,一个列的值必须与同一行中其他列的值不同)。

数据类型(列关联)约束
运行时强制实施列值的数据类型,尝试将类型不正确的值存储在列中时会出现错误。但是,在许多情况下,会转换值以匹配列的已声明数据类型。有关详细信息,请参阅 使用数据库数据类型

运行时不对外键值强制实施约束。换句话说,匹配现有的主键值不需要外键值。

除了预定义的约束类型外,运行时 SQL 引擎还支持使用触发器。触发器类似于事件处理函数。 它是发生某个操作时执行的一组预定义指令。例如,可以定义一个触发器,它在向特定表插入数据或从中删除数据时运行。触发器的一个可能用途是检查数据更改,并在不满足指定的条件时导致出现错误。因此,触发器可以具有与约束相同的用途,防止约束错误和从中恢复的策略也适用于触发器生成的错误。但是,触发器生成的错误的错误 id 与约束错误的错误 id 不同。

在设计应用程序时,就确定了适用于特定表的一组约束。通过有意识地设计约束,可以更轻松地设计应用程序,以防止约束错误和从中恢复。但是,约束错误很难系统地预测和预防。很难预测的原因是,约束错误在添加应用程序数据后才出现。数据在创建后被添加到数据库时会出现约束错误。这些错误通常是由新数据和已经存在于数据库中的数据之间的关系导致的。以下策略可以帮助您避免许多约束错误:

仔细计划数据库结构和约束
约束的用途是强制实施应用程序规则和帮助保护数据库数据的完整性。在计划应用程序时,请考虑如何构建数据库来支持您的应用程序。作为该过程的一部分,确定数据的规则,如某些值是否必需、某值是否具有默认值、是否允许重复值等。这些规则可以指导您定义数据库约束。

明确指定列名
可以编写 INSERT 语句而不明确指定要在其中插入值的列,但是这样做会产生不必要的风险。通过明确命名要在其中插入值的列,可以允许自动生成的值、具有默认值的列和允许 NULL 值的列。此外,这样做可确保所有的 NOT NULL 列都插入了显式值。

使用默认值
每当为列指定 NOT NULL 约束时,尽可能在列定义中指定默认值。应用程序代码也可以提供默认值。例如,代码可以检查 String 变量是否为 null ,并在使用它设置语句参数值之前为它分配一个值。

验证用户输入的数据
提前检查用户输入的数据,以确保它符合约束指定的限制,尤其是对于 NOT NULL CHECK 约束。当然, UNIQUE 约束更难检查,因为这样做会要求执行 SELECT 查询来确定数据是否唯一。

使用触发器
可以编写一个触发器,用于验证(并可能替换)插入的数据或执行其他操作以更正无效的数据。此验证和更正可防止出现约束错误。

在许多方面,约束错误比其他类型的错误更难防范。幸运的是,有几个从约束错误恢复的策略,这样就不会使应用程序变得不稳定或不可用:

使用冲突算法
在列上定义约束时,以及创建 INSERT UPDATE 语句时,您可以选择指定冲突算法。冲突算法定义在出现约束违规时数据库执行的操作。数据库引擎可以执行几种可能的操作。数据库引擎可以结束单个语句或整个事务。它可以忽略错误。它甚至可以删除旧数据,并将它替换为代码尝试存储的数据。

有关详细信息,请参阅 本地数据库中的 SQL 支持 中的“ON CONFLICT(冲突算法)”部分。

提供纠正反馈
可以提前识别可能影响特定 SQL 命令的一组约束。因此,可以预期语句可能导致的约束错误。知道这一点,就可以生成应用程序逻辑来响应约束错误。例如,假定应用程序包括用于输入新产品的数据条目表单。如果数据库中的产品名称列是用 UNIQUE 约束定义的,则在数据库中插入新产品行的操作可能会导致约束错误。因此,应用程序设计用于预期约束错误。在错误发生时,应用程序将提醒用户,指出指定的产品名称已在使用中,并要求用户选择其他名称。另一种可能的响应是,允许用户查看有关同名的其他产品的信息。