2013-12-22 53 views
3

我有一个用户创建屏幕,其中包含各种用户详细信息以及名字和手机号码。我有一个相应的USER表,其中名字和手机号码形成一个复合的唯一密钥。还有其他完整性约束也在此表中定义。数据库处理唯一约束违规

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

当这种冲突发生时,我从MySQL数据库中获取的例外是:

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

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

选项1:在这个异常的catch块,解析MySQL的异常的信息,并查找“uk_FIRST_NAME__MOBILE_idx”。如果存在,则如上所述显示用户友好的消息。

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

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

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

+2

我通常*发现它干净在这些情况下,以第一个“检查”,以确保用户名(或任何限制)是有效的/允许的,然后尝试实际更新并通过DAL公开它 - 这是也可用于提供数据的“实时验证”(例如验证警告)。在小竞争条件下,插入异常可以被视为“我们很抱歉,请再试一次!”。也就是说,数据库是安全网,但不对最终用户错误报告负责。 – user2864740

+0

感谢您指出选项2中的'竞争条件'的可能性。 – PhantomReference

回答

6

我认为“选项2”(在尝试插入之前手动检查约束)是非常可怕的,不仅因为种族危害(可以通过locking reads避免),还因为额外的负载在数据库上:毕竟,手动检查约束完全否定了在数据库中使用约束的目的和好处。

我同意解析错误消息字符串感觉“脏”,但字符串是well defined。甚至可以参考潜在的errmsg.txt或源头文件。

一旦一个人已经从错误消息中提取的键值名,一个可以使用KEY_COLUMN_USAGE信息模式去识别出错的列:

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

“...毕竟,手动检查约束完全否定了在数据库中使用约束的目的和好处“。这是一个很棒的观点!+1 – PhantomReference

-1

这里是一个eggyal's answer PHP版本,使用的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']; 
    } 
}