当前位置: 首页 > 知识库问答 >
问题:

数据库-唯一约束冲突的处理

常小白
2023-03-14

我有一个用户创建屏幕,它记录了各种用户详细信息以及名字和手机号码。我有一个对应的用户表,其中名字和手机号码构成一个复合唯一键。此表中还定义了其他完整性约束。

当在创建用户屏幕上输入违反此约束的用户数据时,需要向用户显示“用户友好”错误消息。

当这种违反发生时,我从MySQL数据库中得到的异常是:

com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '1-1' for key `uk_FIRST_NAME__MOBILE_idx`

有两个选项可以显示有意义的消息(例如:“错误:给定手机号码的用户名已存在,请更改其中一个”)。

选项1:在这个异常的cat块中,解析MySQL异常的消息并查找uk_FIRST_NAME__MOBILE_idx。如果存在,显示上面提到的用户友好的消息。

选项2:编写一个DAO级别的API,将名字和手机号码作为唯一的两个参数,启动数据库查询,看看是否有匹配这个名字/手机组合的现有记录。如果为true,则向用户显示错误消息;否则,运行插入查询将记录的用户插入到USER表中。

我不喜欢选项1,因为它需要我“解析”异常消息,这不是一个干净的解决方案。我也不喜欢选项2,因为它需要我在数据库上运行“两个查询”,这比选项1的效率低,后者是一个单一的查询解决方案。

问:还有比这两个更好的选择吗?如果不是,在上述两种方法中,哪一种是正确的方法?

共有2个答案

昝欣可
2023-03-14

下面是eggyal使用MySQLi给出的答案的PHP版本。

// Error: 1062 SQLSTATE: 23000 (ER_DUP_ENTRY)               Message: Duplicate entry '%s' for key %d
// Error: 1586 SQLSTATE: 23000 (ER_DUP_ENTRY_WITH_KEY_NAME) Message: Duplicate entry '%s' for key '%s'
if($mysqli->errno === 1062 || $mysqli->errno === 1586)
{
    if(preg_match("/Duplicate entry '(.*)' for key '(.*)'/", $mysqli->error, $matchArray) === 1)
    {
        $duplicatedValue = $matchArray[1];
        $uniqueKeyName = $matchArray[2];

        if(!($stmt = $mysqli->prepare('SELECT COLUMN_NAME'
                                    . '  FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE'
                                    . ' WHERE CONSTRAINT_SCHEMA = ?'
                                    . '   AND CONSTRAINT_NAME = ?')))
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        $schemaName = // Name of the schema (string).
        if(!$stmt->bind_param('ss', $schemaName, $uniqueKeyName))
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        if(!$stmt->execute())
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        $res = $stmt->get_result();
        if(!$res)
        {
            die;    // Error? Check $mysqli->errno and $mysqli->error;
        }
        $row = $res->fetch_assoc();
        if($row === null)
        {
            die;    // No results?
        }
        $columnName = $row['COLUMN_NAME'];
    }
}
何聪
2023-03-14

我认为“选项2”(在尝试插入之前手动检查约束)是可怕的,这不仅是因为竞争危险(通过锁定读取可以避免),而且还因为(正如您所注意的)数据库上的额外负载:毕竟,手动检查约束完全否定了在数据库中使用约束的目的和好处。

我同意解析错误消息字符串感觉很“脏”,但是字符串定义得很好。甚至可以引用基础的errmsg.txt或源代码头文件。

从错误消息中提取密钥名称后,可以使用key\u COLUMN\u用法information模式来识别有问题的列:

public static final int ER_DUP_ENTRY = 1062;
public static final int ER_DUP_ENTRY_WITH_KEY_NAME = 1586;

public static final String REGEX_DUP_ENTRY_WITH_KEY_NAME =
  "Duplicate entry '(.*)' for key '(.*)'";

// ...


try {
// ...
} catch (MySQLIntegrityConstraintViolationException e) {
  switch (e.getErrorCode()) {
    case ER_DUP_ENTRY:
    case ER_DUP_ENTRY_WITH_KEY_NAME:
      Pattern p = Pattern.compile(REGEX_DUP_ENTRY_WITH_KEY_NAME);
      Matcher m = p.matcher(e.getMessage());

      SQLQuery query = session.createSQLQuery(
      " SELECT COLUMN_NAME" +
      " FROM   INFORMATION_SCHEMA.KEY_COLUMN_USAGE" +
      " WHERE  CONSTRAINT_SCHEMA = :schema" +
      "    AND CONSTRAINT_NAME   = :key"
      );
      query.setString("schema", "my_schema");
      query.setString("key"   , m.group(2));

      showDuplicateError(query.list());

      break;
  }
}
 类似资料:
  • 我有一个Spring MVC应用程序,它使用Spring Data JPA作为我的JPA提供者来持久化Hibernate。我有一个数据库表,在列上有一个唯一的约束,因此为什么保存相应的实体可能会导致唯一的约束冲突。我想检测这是否发生在我的服务层中,以便我可以向用户呈现有意义的错误消息。以下是我的服务方法。 我的Spring Data JPA存储库看起来像这样: 现在,当发生唯一的约束冲突时,我得到

  • 我想用插页。。请务必更新。。对两列具有唯一约束的表的语法。这可能吗? mytable对col1和col2有单独的唯一约束。 我可以写: 然而,这不起作用: 错误:冲突时,更新是否需要推理规范或约束名称 这也不起作用: 错误:不存在与冲突规范匹配的唯一或排除约束 这种语法似乎是为两列上的单一复合唯一约束而设计的,而不是两个约束。 如果违反了其中一个唯一约束,有没有办法进行条件更新?这个问题是如何在博

  • 我的桌子有两个独特的列: 我想写保存或更新方法 My jooq code: 但我遇到了异常: “错误:没有唯一或排除约束匹配ON CONFLICT规范” 请帮助。

  • 问题内容: 问题概述 在看似随机的时间,我们会收到一个异常“ PostgreSQL重复键违反了唯一约束”。我确实认为我知道我们的问题是什么,但是我不想在没有可重现的测试用例的情况下对代码进行更改。但是由于除了随机生产之外,我们无法在任何环境中复制它,因此我要求SO的帮助。 在这个项目中,我们有多个postgres数据库,并且为每个数据库中的每个表配置了主键序列。这些序列是这样创建的: 我们使用以下

  • 当尝试使用PostgreSQL执行时,我遇到了一个我不理解的行为。文档似乎指示语句的冲突目标可以是索引表达式或约束名称。但是,当试图引用约束名称时,我得到了一个“列...不存在”错误。 我的第一次尝试是创建一个索引,它可以很好地处理约束推理: 在描述上表时,我在“索引”下看到了以下内容: 我的第二次尝试是将唯一约束显式地放在创建表中: 在描述上表时,“索引:”的输出略有不同(“唯一约束”与前一示例

  • 我遇到一个情况,需要根据另一个列值对一个列[属性]强制执行唯一约束。 例如,我有一个像table(ID,EID,Name,ISDeleted)这样的表 ISDeleted只能有一个值null或'y'(active或deleted),并且我想在EID上创建一个唯一的约束,仅当ISDeleted=null时才创建ISDeleted,因为我不关心是否有多个具有相同ID的已删除记录。请注意,EID可以为空