场景:产品经理通过后台系统插入一个字母组成的优惠码(例如:coupon)之后,再从后台通过关键字coupon去查找这个优惠码,查不到,同时影响线上使用。
假设表名:exchange_code.
假设列名:code , varchar类型
症状1:通过Sequel Pro按字段名等等条件搜索coupon,搜索不出来这条记录。
等价于SQL: SELECT * from exchange_cdoe where code = 'coupon';
症状2:通过contains条件搜索,能找到这条记录。
等价于SQL: SELECT * from exchange_cdoe where code contains 'coupon';
症状3:通过 length 函数,计算一下code 长度, 发现长度并不等于coupon的长度6.
看上去是6个字母,却表现出上面的情况。
后面团队想到办法,把里面的内容复制出来,转化为 unicode。
发现了里面包含 unicode \200b 这个不可见字符。
coupon
http://tool.chinaz.com/tools/unicode.aspx (从左至右复制上面这一行字符,去这个网址转换unicode试试)
问题复现
利用java 复现问题
@Test public void testBlog(){ // 字母m 对应unicode u6d String unicode = "\\u6d\\u200b\\u6d"; System.out.println("unicode:"+unicode); String string = unicode2String(unicode) ; System.out.println("string:"+string); } /** * unicode 转字符串 */ public static String unicode2String(String unicode) { StringBuffer string = new StringBuffer(); String[] hex = unicode.split("\\\\u"); for (int i = 1; i < hex.length; i++) { // 转换出每一个代码点 int data = Integer.parseInt(hex[i], 16); // 追加成string string.append((char) data); } return string.toString(); }
输出结果:
unicode:\u6d\u200b\u6d
string:mm
输出结果中mm之间有一个不可见不占位的 \u200b 特殊字符,类似的 \u200c 也是一样的效果。
这些字符的产生 也许是因为”实际上当前版本的统一码并未完全使用这16位编码,而是保留了大量空间以作为特殊使用或将来扩展。” — https://zh.wikipedia.org/wiki/Unicode 。
问题预防:
通过正则表达式校验数据合法性(例如,只允许数字和大小写字母)。
@Test public void testBlog(){ // 字母m 对应unicode \\u6d String unicode = "\\u6d\\u200b\\u6d"; System.out.println("unicode:"+unicode); String string = unicode2String(unicode) ; System.out.println("string:"+string); Pattern pattern = Pattern.compile("[a-zA-Z0-9.]+"); System.out.println("pass? "+pattern.matcher(string).matches()); }
输出结果:
unicode:\u6d\u200b\u6d
string:mm
pass? false
=== 程序员日常小故事 之 隐形的字符===
产品W:“怎么回事啊,这条记录我刚插入的,后台怎么查不出来啊”
程序员T:“我看看怎么回事,之前都是好的啊”
产品H:“这个功能模块怎么又出问题了?”
程序员Z:“我看看啊,数据库里去查一下,怎么数据库里按字段查,也查不出来啊。 ”
某某程序员:“按ID查。”
某某程序员:“查一下这个字段的长度”
某某程序员:“奶奶的,怎么和看上去的长度不一样”
某某程序员:“看看字符串的unicode编码”
某某程序员:“复制到Java里面转成unicode看看”
某某程序员:“奶奶的怎么有不可见字符”
程序员T:“产品W,你是怎么输入不可见字符的…”
产品W:“我是正常操作的呀”
相关推荐
在进行数据库开发的过程中,数据库连接字符串是必不可少的一部分。本文将详细介绍几种常见的数据库连接字符串及其配置参数。这些数据库包括:DBase 5.0、DBASE IV、FoxPro 3.0、Paradox 7.X、Excel 8.0以及Oracle等...
连接字符串中的参数可以因数据库而异,但通常包括: - **Server/DataSource**: 数据库服务器的地址或名称。 - **Database/Initial Catalog**: 要连接的数据库名。 - **User ID/Uid**: 登录数据库的用户名。 - **...
在软件开发过程中,为了增强应用程序的可维护性和灵活性,通常会将数据库连接字符串等敏感信息或频繁更改的信息存储在配置文件中,而不是硬编码到代码里。这不仅可以提高安全性,还便于在不修改代码的情况下更新配置...
其中,`IF NOT EXISTS`是一个可选条件,如果数据库不存在才会创建。`db_name`是你自定义的数据库名,遵循与PHP变量相同的命名规则,不区分大小写。`CHARSET`用于指定数据库的默认字符集,如`utf8`,表示Unicode编码...
在数据库管理中,字符处理是一项基础且至关重要的任务。它涉及到数据的输入、存储、检索以及展示等多个环节,确保字符的正确处理对于数据的一致性和完整性至关重要。以下是一些关于数据库字符处理的关键知识点: 1....
对于不常见的数据库系统,尽管使用较少,但了解其连接字符串格式仍然有助于应对特定场景。参考提供的“数据库连接字符串大全及详解.txt”文件,可以获取更全面的信息和更多示例。 在编程中,正确配置连接字符串是...
解决不同字符集数据库间的数据同步问题是数据库管理员和开发者不得不考虑的问题。本文将详细介绍如何解决不同字符集数据库间的数据同步问题,并提供实际测试环境和测试方法。 标题分析 解决不同字符集数据库间的...
在软件开发过程中,数据库的连接与操作是不可或缺的一部分。为了方便开发者能够快速地实现与不同数据库的连接,本文将详细介绍一系列的数据库连接字符串,涵盖多种数据库类型及连接方式。这些连接字符串不仅包括了...
在软件开发过程中,与数据库的交互是不可或缺的一部分。不同的数据库管理系统(DBMS)采用不同的驱动程序来实现Java应用程序与数据库之间的连接。本文将详细介绍几种常见数据库的连接方式及其对应的驱动字符串配置...
在探讨“数据库中CLOB类型转换的问题”这一主题时,我们首先需要理解CLOB(Character Large Object)数据类型的基本概念及其在数据库中的应用场景。随后,将深入分析CLOB类型转换过程中可能遇到的问题,并提供相应的...
在处理数据库时,中文字符的存储和显示往往成为开发过程中一个不可忽视的问题。本文档主要介绍如何在MySQL数据库中正确地输入中文字符,并确保其能正常显示。通过一系列步骤与配置,可以有效地解决这一问题。 #### ...
在三层架构中,Access数据库连接字符串通常在数据访问层被使用,以确保数据库操作与用户界面和业务逻辑分离,提高代码的可维护性和可重用性。 DBHelper类,正如文件名`DBHelper.cs`所示,通常在数据访问层扮演着...
特别是对于数据库连接字符串的处理,不当的管理可能会导致敏感信息泄露,进而造成不可估量的损失。本文旨在介绍如何在ASP.NET 2.0中通过配置节加密功能来提高数据库连接字符串的安全性。 #### 原理简介 ASP.NET ...
非法字符通常是指那些不符合数据库系统规定或者可能导致解析错误的字符。本工具专注于检测数据表字段中可能存在的非法字符,确保数据结构的合规性。 一、非法字符的类型与影响 1. 特殊字符:例如 `(反引号)、;...
- 数据库字符集是在创建数据库时指定的,一般不建议改动。它分为两部分:字符集和国家字符集。 - 字符集:用于存储CHAR、VARCHAR2、CLOB、LONG等类型的数据,以及表名、列名和PL/SQL变量等标识符。 - 国家字符集:专...
`AttachDBFilename` 或 `Initial File Name` 用于附加一个具体的数据库文件,但通常不推荐在连接字符串中指定,因为这可能导致数据库管理上的问题。 `Current Language` 设置服务器的默认语言,通常是 SQL Server ...