数据库的SQLSTATE[23000]异常,通过自定义异常类来提供更友好的提示信息

发布于:2025-05-12 ⋅ 阅读:(19) ⋅ 点赞:(0)

操作数据库的时候经常会遇到报错:SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ,报错信息给开发者调试没问题,直接展示给用户的话,用户就以为是程序乱码或者程序有问题,实际上是原始提示太不直观 

你可以通过自定义异常类来提供更友好的提示信息。以下是实现方案:

1. 创建自定义数据库异常类

<?php
namespace app\exception;

use think\Exception;

class DatabaseOperationException extends Exception
{
    // 常见数据库错误码映射
    const ERROR_MAP = [
        1062 => '数据已存在,请勿重复添加',
        1451 => '操作失败,存在关联数据',
        1452 => '操作失败,关联数据不存在',
        // 可以添加更多错误码映射
    ];
    
    // 字段重复映射(可根据需要扩展)
    const FIELD_MAP = [
        'id_code' => '身份证号',
        'username' => '用户名',
        'email' => '邮箱',
        'phone' => '手机号',
    ];
    
    public function __construct($message = "", $code = 0, \Throwable $previous = null)
    {
        // 如果是已知的数据库错误码,转换为友好提示
        if (preg_match('/SQLSTATE\[23000\]:.*1062.*Duplicate entry \'.*\' for key \'(\w+)\'/', $message, $matches)) {
            $field = $matches[1] ?? '';
            $fieldName = self::FIELD_MAP[$field] ?? $field;
            $message = "{$fieldName}已存在,请勿重复添加";
            $code = 1062;
        }
        
        parent::__construct($message, $code, $previous);
    }
    
    /**
     * 从数据库异常创建自定义异常
     */
    public static function createFromDbException(\Throwable $e)
    {
        // 尝试从错误信息中提取错误码
        if (preg_match('/SQLSTATE\[23000\]:.*(\d{4})/', $e->getMessage(), $matches)) {
            $errorCode = $matches[1] ?? 0;
            $message = self::ERROR_MAP[$errorCode] ?? $e->getMessage();
            return new self($message, $errorCode, $e);
        }
        
        return new self($e->getMessage(), $e->getCode(), $e);
    }
}

2. 使用方式

try {
    // 尝试创建用户
    $user = User::create($userData);
} catch (\think\db\exception\DbException $e) {
    // 转换为自定义异常
    throw DatabaseOperationException::createFromDbException($e);
} catch (\Exception $e) {
    // 其他异常处理
    throw new \Exception('操作失败,请稍后再试');
}

 3. 全局异常处理(可选)

// 在app/ExceptionHandle.php中

public function render($request, \Throwable $e): Response
{
    // 如果是数据库操作异常
    if ($e instanceof \think\db\exception\DbException) {
        $friendlyException = DatabaseOperationException::createFromDbException($e);
        return json([
            'code' => 400,
            'msg' => $friendlyException->getMessage(),
            'data' => null
        ]);
    }
    
    // 其他异常处理...
    return parent::render($request, $e);
}

 

4. 效果

当用户尝试添加重复的身份证号时,原本的:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '220********25' for key 'id_code'

将被转换为更友好的提示: 

身份证号已存在,请勿重复添加 

5. 扩展建议

  1. 可以根据业务需要扩展FIELD_MAPERROR_MAP,添加更多字段和错误码的映射

  2. 对于多语言应用,可以将提示信息改为从语言包读取

  3. 可以记录原始异常信息到日志,便于调试

这种方式既保持了原始错误信息的完整性(通过日志),又为用户提供了友好的界面提示。

 


网站公告

今日签到

点亮在社区的每一天
去签到