在数据库日常运维和开发中,用户手机号、身份证号、银行卡号等敏感数据需要按照合规要求做脱敏处理,避免明文存储带来的数据泄露风险。通过存储过程封装脱敏逻辑,可以统一处理规则,提升批量操作的效率。

核心函数说明
要实现脱敏功能,首先需要了解REPLACE和SUBSTRING两个函数的基础用法,不同数据库的函数语法略有差异,以下以MySQL为例说明。
SUBSTRING函数
该函数用于截取字符串的指定部分,基础语法为SUBSTRING(str, start_pos, length),其中str是待处理的字符串,start_pos是起始截取位置,length是截取长度,如果省略length则截取到字符串末尾。
REPLACE函数
该函数用于将字符串中的指定子串替换为新内容,基础语法为REPLACE(str, old_str, new_str),会将str中所有出现的old_str都替换为new_str。
常见敏感数据脱敏逻辑
大部分敏感数据的脱敏规则都是保留前几位和后几位,中间用星号替换,我们可以结合两个函数实现这个逻辑:先通过SUBSTRING取出需要保留的前缀和后缀,再用REPLACE或者直接拼接的方式组合成脱敏后的字符串。
手机号脱敏示例
手机号通常保留前3位和后4位,中间4位替换为星号,实现代码如下:
-- 手机号脱敏:保留前3后4,中间替换为****
SELECT
phone_number,
CONCAT(
SUBSTRING(phone_number, 1, 3),
'****',
SUBSTRING(phone_number, 8, 4)
) AS masked_phone
FROM user_info;
身份证号脱敏示例
身份证号保留前6位和后4位,中间替换为8个星号,实现代码如下:
-- 身份证号脱敏:保留前6后4,中间替换为********
SELECT
id_card,
CONCAT(
SUBSTRING(id_card, 1, 6),
'********',
SUBSTRING(id_card, 15, 4)
) AS masked_id_card
FROM user_info;
封装为通用脱敏存储过程
为了复用脱敏逻辑,我们可以编写存储过程,支持传入表名、字段名和脱敏类型,自动完成对应字段的脱敏更新操作。
-- 创建脱敏存储过程
DELIMITER //
CREATE PROCEDURE sp_mask_sensitive_data(
IN p_table_name VARCHAR(100), -- 目标表名
IN p_column_name VARCHAR(100), -- 待脱敏字段名
IN p_mask_type VARCHAR(20) -- 脱敏类型:phone/id_card/email
)
BEGIN
DECLARE v_sql VARCHAR(1000);
-- 根据脱敏类型生成不同的更新SQL
IF p_mask_type = 'phone' THEN
-- 手机号脱敏逻辑
SET v_sql = CONCAT(
'UPDATE ', p_table_name,
' SET ', p_column_name, ' = CONCAT(
SUBSTRING(', p_column_name, ', 1, 3),
''****'',
SUBSTRING(', p_column_name, ', 8, 4)
) WHERE ', p_column_name, ' IS NOT NULL'
);
ELSEIF p_mask_type = 'id_card' THEN
-- 身份证号脱敏逻辑
SET v_sql = CONCAT(
'UPDATE ', p_table_name,
' SET ', p_column_name, ' = CONCAT(
SUBSTRING(', p_column_name, ', 1, 6),
''********'',
SUBSTRING(', p_column_name, ', 15, 4)
) WHERE ', p_column_name, ' IS NOT NULL'
);
ELSEIF p_mask_type = 'email' THEN
-- 邮箱脱敏逻辑:保留@前第一位和@后域名,中间替换为***
SET v_sql = CONCAT(
'UPDATE ', p_table_name,
' SET ', p_column_name, ' = CONCAT(
SUBSTRING(', p_column_name, ', 1, 1),
''***'',
SUBSTRING(', p_column_name, ', INSTR(', p_column_name, ', ''@''), LENGTH(', p_column_name, '))
) WHERE ', p_column_name, ' IS NOT NULL'
);
END IF;
-- 执行动态SQL
SET @update_sql = v_sql;
PREPARE stmt FROM @update_sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
存储过程优化建议
- 执行脱敏前先对目标字段加索引,提升
SUBSTRING函数的处理效率,避免全表扫描。 - 如果数据量较大,建议分批次执行更新操作,每次处理1000-5000条数据,避免长事务锁表。
- 可以在存储过程中增加日志表记录,每次脱敏操作完成后记录处理的表名、字段名、处理行数和时间,方便后续审计。
- 对于固定格式的敏感数据,可以提前校验字段长度,避免截取位置超出字符串范围导致报错。
存储过程调用示例
调用上述存储过程对user_info表的phone字段做手机号脱敏,代码如下:
-- 调用存储过程脱敏手机号
CALL sp_mask_sensitive_data('user_info', 'phone', 'phone');
-- 调用存储过程脱敏身份证号
CALL sp_mask_sensitive_data('user_info', 'id_card', 'id_card');