Database - handling of unique constraint violation

前端 未结 2 1394
無奈伤痛
無奈伤痛 2020-12-11 08:30

I have a user creation screen that takes various user details along with first name and mobile number. I have a corresponding USER table in which the First Name and the Mob

相关标签:
2条回答
  • 2020-12-11 08:44

    I think "option 2" (manually checking constraint before attempting to insert) is horrible, not just because of the race hazard (which could be avoided with locking reads), but also (as you note) because of the additional load on the database: after all, to manually check the constraints completely negates the purpose and benefit of using constraints within the database.

    I agree that parsing error message strings feels "dirty", but the strings are well defined. One could even refer to the underlying errmsg.txt or source header files.

    Once one has extracted the key name from the error message, one can use the KEY_COLUMN_USAGE information schema to identify the offending columns:

    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;
      }
    }
    
    0 讨论(0)
  • 2020-12-11 08:50

    Here's a PHP version of eggyal's answer, using MySQLi.

    // 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'];
        }
    }
    
    0 讨论(0)
提交回复
热议问题