欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

眼見不一定為實(shí)之MySQL中的不可見字符詳解

 更新時(shí)間:2024年06月25日 08:30:52   作者:夜郎king  
這篇文章主要給大家介紹了關(guān)于眼見不一定為實(shí)之MySQL中不可見字符的相關(guān)資料,不可見字符是指在文本中無法直接顯示出來的字符,它們通常用于控制文本的格式或布局,需要的朋友可以參考下

前言

在開始今天的博客內(nèi)容之前,正在看博客的您先來看看以下這兩條sql,如果您剛好還有MySQL的環(huán)境。不妨先猜測(cè)一下它輸出的內(nèi)容,然后看看是否有什么區(qū)別?第一條sql如下:

select length('G30L3B01') as l1;

接著再來看另一條sql,sql腳本如下:

select length('G30L3 B01') as l2;

各位不妨猜測(cè)一下,上面兩條sql語句的執(zhí)行結(jié)果l1和l2分別是多少?是不是在你的預(yù)料之中。 這里不賣關(guān)子了,相信執(zhí)行過sql的朋友一定看到了結(jié)果。沒有數(shù)據(jù)庫客戶端的朋友來看我的執(zhí)行結(jié)果。在給出結(jié)果之前,首先把基礎(chǔ)環(huán)境介紹一下。這里的服務(wù)器用的的個(gè)人的Windows 7 專業(yè)版開發(fā)機(jī),數(shù)據(jù)庫服務(wù)用的是MySQL5.7,打開的查詢服務(wù)窗口所在的數(shù)據(jù)庫編碼是UTF-8。

上面這個(gè)結(jié)果有沒有超出你的預(yù)想,這兩個(gè)字符串“看”起來似乎是一模一樣的。這里的“看”我打了引號(hào),至于原因,后面會(huì)講到。本文即以上述場(chǎng)景為例,講解在MySQL中,為什么會(huì)有這種“看”起來一致,但實(shí)際上不一樣的問題,通過現(xiàn)象找本質(zhì),通過一步一步的排查,找到問題的根源,最后在尋根溯源后,找解決的辦法;從應(yīng)用代碼編程的角度和底層數(shù)據(jù)庫的角度來解決上述問題。如果您現(xiàn)在也遇到了這種“看”起來不正常的值,不妨一起交流一下。

一、問題的由來

首先依然要介紹一下上述問題的出現(xiàn)場(chǎng)景,以便于其它的朋友在此情此景下,有更大的印象。因此本節(jié)首先將對(duì)問題的場(chǎng)景進(jìn)行詳細(xì)的描述。這里打算從兩個(gè)方面講述,第一個(gè)方面是講述需求背景,即在什么情況下作這個(gè)事。第二個(gè)是講述數(shù)據(jù)背景,把相關(guān)的表設(shè)計(jì)也說明一下。

1、需求背景

事情發(fā)生的背景是這樣的,客戶要求我們做一個(gè)功能,他們會(huì)提供一個(gè)數(shù)據(jù)的Excel模板,然后我們需要將這些數(shù)據(jù)批量導(dǎo)入到數(shù)據(jù)庫中。這個(gè)需求咋一看起來,是一個(gè)非常簡(jiǎn)單的需求啊。讀取Excel的依賴庫,一大把。解析Excel的數(shù)據(jù),然后批量插入到數(shù)據(jù)庫中,對(duì)于MybatisPlus或者其它的ORM工具都是非常簡(jiǎn)單的事。當(dāng)時(shí)我們選擇的是阿里巴巴開源的讀取Excel的組件。感興趣的朋友可以自己上github搜索一下。然后也基于組件也已經(jīng)將Excel沒個(gè)表格都讀取到了內(nèi)存中,然后調(diào)用MP的批量插入方法,意外的是在進(jìn)行批量插入的時(shí)候數(shù)據(jù)庫報(bào)錯(cuò)了。下面還是將數(shù)據(jù)庫的表先做一個(gè)介紹。

2、數(shù)據(jù)表結(jié)構(gòu)

為了實(shí)現(xiàn)將數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫中,根據(jù)面向?qū)ο蟮脑瓌t,我們將Excel表格中的每個(gè)單元格都設(shè)計(jì)成了一個(gè)字段,然后對(duì)字段的數(shù)據(jù)類型進(jìn)行了設(shè)計(jì),同時(shí)包括數(shù)據(jù)長(zhǎng)度。其中有一個(gè)項(xiàng)是輸入數(shù)據(jù)的編碼,然后用戶是有編碼規(guī)則的,每一個(gè)數(shù)據(jù)都有一個(gè)對(duì)應(yīng)的編碼規(guī)則。我們簡(jiǎn)單的看了他們的編碼規(guī)則,得知其長(zhǎng)度大致為8位,因此我們?cè)跀?shù)據(jù)庫中設(shè)計(jì)成了varchar(8);這么設(shè)計(jì)其實(shí)是中規(guī)中矩的,非常合理。然而在上面的批量入庫過程中就一直報(bào)對(duì)應(yīng)的這個(gè)字段too long。這個(gè)異??雌饋砗芷婀郑?yàn)槲覀內(nèi)斯と?ldquo;看”的時(shí)候,這個(gè)字符串的長(zhǎng)度確實(shí)是8。于是陷入了沉思。

二、定位問題

既然在開發(fā)過程當(dāng)中出現(xiàn)了問題,那么如何解決問題呢?在解決問題之前,首先要定位問題,只有正確的定位問題,才能對(duì)癥下藥,問題才能迎刃而解。因此本節(jié)將重點(diǎn)講解怎么定位問題。

1、初步的問題

當(dāng)看到上面問題的時(shí)候,第一感覺是懵的,剛開始都有點(diǎn)不敢相信自己的眼睛。因?yàn)槿庋鄹?ldquo;看”不出來這個(gè)字符串居然不是8位。最開始懷疑的是在字符串的前后可能存在空格,因此導(dǎo)致了其長(zhǎng)度超出了8位。為此我們將數(shù)據(jù)進(jìn)行去空,使用sql進(jìn)行去空如下:

SELECT length('G30L3B01') AS VisibleLength,
       length(replace('G30L3 B01', '?', '')) AS CleanLength;

然后發(fā)現(xiàn)還是不對(duì),經(jīng)過替換后其長(zhǎng)度還是11,說明還是超長(zhǎng)了。 

2、編碼是否有問題

在進(jìn)行空字符過濾之后還是沒有解決問題。于是換了一個(gè)方向,想著有沒有可能是字符集的問題。其實(shí)大家可以看看UTF-8的字符集規(guī)范,字符集雖然會(huì)有一定的影響,但是這里存儲(chǔ)的都是英文和數(shù)字,其長(zhǎng)度均是標(biāo)準(zhǔn)的1,因此不存在字符的問題。問題一下子沒有了方向,不知道往哪個(gè)方面去排查。

3、依然回到字符本身

在第一次嘗試了空字符替換無果,又排除了字符編碼的問題后,再一次將目光投入到字符本身。這一次的想法是,雖然空字符本文替換后,長(zhǎng)度還是11,但是這并不說明其內(nèi)容一定是空格。有沒有什么其它的東西在搗亂呢。有時(shí)候找問題就是這樣,反反復(fù)復(fù)。

三、深入字符本身

上面從幾個(gè)方面分析了可能存在的問題,尤其是第三點(diǎn),我們從最開的字符又回到了起點(diǎn)。那么這次采用什么分析思路呢?本小節(jié)深入道來。

1、回歸本質(zhì)

為了來看看這個(gè)數(shù)據(jù)到底是什么?我們將字符串轉(zhuǎn)為十六進(jìn)制的字符串,通過比較原始字符串來看看區(qū)別。在MySQL中可以使用HEX(str)實(shí)現(xiàn)轉(zhuǎn)換。相關(guān)的轉(zhuǎn)換SQL如下所示:

SELECT HEX('G30L3B01') AS hex_representation,HEX('G30L3 B01') as n2;

hex_representation	n2
4733304C33423031	4733304C33EFBBBF423031

不知道眼尖的你發(fā)現(xiàn)了問題沒有,上面這條SQL執(zhí)行完之后發(fā)現(xiàn),其目標(biāo)字符串似乎不一樣啊。后面的字符串,也就是有問題的字符串其長(zhǎng)度真的超長(zhǎng)了。下面仔細(xì)對(duì)比這兩個(gè)字符串。

4733304C33        423031    
4733304C33 EFBBBF 423031

為了方便展示,我把相同的部分進(jìn)行對(duì)比,我們發(fā)現(xiàn),前面的字符經(jīng)過十六進(jìn)制的轉(zhuǎn)換后,一共16個(gè)字節(jié),8位。是符合我們的預(yù)期的,而下面的十六進(jìn)制字符則多了6字節(jié),一共22字節(jié),記11位。這也就是為什么這兩個(gè)字符串不一樣的原因。那么這個(gè)多出來的EFBBBF又是什么呢?由于這是轉(zhuǎn)成了十六進(jìn)制的表示,我們需要將其轉(zhuǎn)為十進(jìn)制。將十六進(jìn)制轉(zhuǎn)十進(jìn)制,如果不想計(jì)算的朋友可以在網(wǎng)頁中直接搜索:

當(dāng)然你也可以在MySQL中進(jìn)行進(jìn)制轉(zhuǎn)換,轉(zhuǎn)換方法如下:

-- CONVERT(CONV('EFBBBF', 16, 10), UNSIGNED) 是在mysql中實(shí)現(xiàn)將16進(jìn)制轉(zhuǎn)10進(jìn)制數(shù)據(jù)
select length(char(15711167)),hex(char(15711167)),CONVERT(CONV('EFBBBF', 16, 10), UNSIGNED);

執(zhí)行之后,可以看到:

length(char(15711167))	hex(char(15711167))	CONVERT(CONV('EFBBBF', 16, 10), UNSIGNED)
3	EFBBBF	15711167

到這里,為什么兩個(gè)“看”起來一模一樣的字符串,實(shí)際上不一樣呢?根源就在這里,在字符串的中間位置插入了不可見字符。就是這不可見字符EFBBBF導(dǎo)致我們做數(shù)據(jù)插入時(shí)報(bào)too long。

2、數(shù)據(jù)庫解決之道

在明確了以上的問題所在之后,我們就可以根據(jù)實(shí)際情況來進(jìn)行調(diào)整。只要將這種不可見字符替換掉即可。實(shí)現(xiàn)的方式也很簡(jiǎn)單,sql如下:

select length(REPLACE('G30L3 B01', CHAR(15711167),''))  t;

t
8

通過replace函數(shù)就實(shí)現(xiàn)了不可見字符EFBBBF的去除,這樣再調(diào)用Insert語句,就不會(huì)報(bào)too long的問題。

3、代碼層解決

除了在數(shù)據(jù)庫層來解決問題,還可以在什么地方解決呢?在編碼層解決是否可行。答案是肯定的。下面我們來詳細(xì)介紹一下代碼層的處理辦法,以java語言為例。其實(shí)原理是一樣的,都是要將不可見字符進(jìn)行替換掉。

/*
* 字節(jié)數(shù)組轉(zhuǎn)16進(jìn)制字符串
*/
public static String bytesToHexString(byte[] bArr) {
	if (bArr == null) {
		return null;
	}
	StringBuffer sb = new StringBuffer(bArr.length);
	String sTmp;
	for (int i = 0; i < bArr.length; i++) {
		sTmp = Integer.toHexString(0xFF & bArr[i]);
		if (sTmp.length() < 2)
			sb.append(0);
		sb.append(sTmp);
	}
	return sb.toString();
}

// 轉(zhuǎn)化十六進(jìn)制編碼為字符串
public static String toStringHex(String s) {
	byte[] baKeyword = new byte[s.length() / 2];
	try {
		for (int i = 0; i < baKeyword.length; i++) {
	baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
		}
		s = new String(baKeyword, "utf-8");// UTF-16le:Not
	} catch (Exception e1) {
			e1.printStackTrace();
	}
	return s;
}

下面給出測(cè)試代碼,您可以實(shí)際測(cè)試以下結(jié)果,看是否與我的預(yù)期一樣:

public static void main(String[] args) {
		System.out.println("G8014Z03".substring(0, 2));
		System.out.println(bytesToHexString("G30L3 B01".getBytes()).toUpperCase()); // 長(zhǎng)
		System.out.println(bytesToHexString("G30L3B01".getBytes()).toUpperCase()); // 短
		System.out.println("G30L3 B01".length()); // 長(zhǎng)
		System.out.println("G30L3B01".length()); // 短
		System.out.println("進(jìn)制轉(zhuǎn)換======================================================");
		System.out.println(toStringHex("4733304C33423031"));
		System.out.println(toStringHex("4733304C33423031").length());
		System.out.println(toStringHex("4733304C33EFBBBF423031"));
		System.out.println(toStringHex("4733304C33EFBBBF423031").length());
		System.out.println("================================================");
		System.out.println(toStringHex("4733304C33EFBBBF423031".replaceAll("EFBBBF", "")));
		System.out.println(toStringHex("4733304C33EFBBBF423031".replaceAll("EFBBBF", "")).length());
		
		System.out.println("G30L3 B01".equals("G30L3B01"));
		
		System.out.println(toStringHex("4733304C33EFBBBF423031".replaceAll("EFBBBF", "")).equals("G30L3B01"));
	}

在代碼中使用上述代碼也可以實(shí)現(xiàn)目標(biāo)字符的替換,將不可見字符進(jìn)行替換掉。歡迎在實(shí)踐中進(jìn)行測(cè)試使用。

四、總結(jié)

以上就是本文的主要內(nèi)容,本文以數(shù)據(jù)庫中不可見字符處理為例,講解在MySQL中,為什么會(huì)有這種“看”起來一致,但實(shí)際上不一樣的問題,通過現(xiàn)象找本質(zhì),通過一步一步的排查,找到問題的根源,最后在尋根溯源后,找到解決的辦法;從應(yīng)用代碼編程的角度和底層數(shù)據(jù)庫的角度來解決上述問題。

使用建議,如果您也有這方面的問題,尤其是從Excel或者其它的模板中導(dǎo)入數(shù)據(jù)的,很有可能會(huì)遇到這個(gè)問題。如果碰到看起來一致,但實(shí)際內(nèi)容不一樣的情況,可以試試看是不是碰到了不可見字符,本文即分享了一種在MySQL中的不可見字符的解決方案,同時(shí)分享了使用JAVA語言進(jìn)行上述問題的解決。

到此這篇關(guān)于MySQL中不可見字符詳解的文章就介紹到這了,更多相關(guān)MySQL不可見字符內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MySQL 使用自定義變量進(jìn)行查詢優(yōu)化

    MySQL 使用自定義變量進(jìn)行查詢優(yōu)化

    MySQL自定義變量估計(jì)很少人有用到,但是如果用好了也是可以輔助進(jìn)行性能優(yōu)化的。需要注意的是變量是基于連接會(huì)話的,而且可能存在一些意外的情況,需要小心使用。本篇介紹如何利用自定義變量進(jìn)行查詢優(yōu)化,提高效率
    2021-05-05
  • mysql 8.0.15 壓縮版安裝圖文教程

    mysql 8.0.15 壓縮版安裝圖文教程

    這篇文章主要為大家詳細(xì)介紹了mysql 8.0.15 壓縮版安裝圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • Windows10下mysql 8.0.22 安裝配置方法圖文教程

    Windows10下mysql 8.0.22 安裝配置方法圖文教程

    這篇文章主要為大家詳細(xì)介紹了Windows10下mysql 8.0.22 安裝配置方法圖文教程,文中安裝步驟介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • ?MySQL中?between and的基本用法?操作方法

    ?MySQL中?between and的基本用法?操作方法

    本文主要介紹了MySQL中BETWEEN AND操作符的基本用法,包括數(shù)值查詢和時(shí)間范圍查詢,同時(shí)還詳細(xì)解釋了NOT BETWEEN AND的使用方法,并通過實(shí)例進(jìn)行了詳細(xì)的演示,其中,BETWEEN AND可以用于數(shù)值、日期等類型的字段,包括邊界值
    2024-10-10
  • MySQL基于java實(shí)現(xiàn)備份表操作

    MySQL基于java實(shí)現(xiàn)備份表操作

    這篇文章主要介紹了MySQL基于java實(shí)現(xiàn)備份表操作,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 在MySQL中解析JSON或?qū)⒈碇凶侄沃岛喜镴SON問題

    在MySQL中解析JSON或?qū)⒈碇凶侄沃岛喜镴SON問題

    這篇文章主要介紹了在MySQL中解析JSON或?qū)⒈碇凶侄沃岛喜镴SON問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-04-04
  • mysql觸發(fā)器之創(chuàng)建使用觸發(fā)器簡(jiǎn)單示例

    mysql觸發(fā)器之創(chuàng)建使用觸發(fā)器簡(jiǎn)單示例

    這篇文章主要介紹了mysql觸發(fā)器之創(chuàng)建使用觸發(fā)器,結(jié)合實(shí)例形式分析了mysql創(chuàng)建、查看、調(diào)用觸發(fā)器的相關(guān)操作技巧,需要的朋友可以參考下
    2019-12-12
  • Mysql explain用法與結(jié)果深入分析

    Mysql explain用法與結(jié)果深入分析

    這篇文章主要給大家介紹了關(guān)于Mysql explain用法與結(jié)果分析的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 從0到1學(xué)會(huì)MySQL單表查詢

    從0到1學(xué)會(huì)MySQL單表查詢

    這篇文章主要給大家介紹了關(guān)于如何從0到1學(xué)會(huì)MySQL單表查詢的相關(guān)資料,單表查詢是指從一張表數(shù)據(jù)中查詢所需的數(shù)據(jù),文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Mysql如何同時(shí)交換兩個(gè)表的表名詳解

    Mysql如何同時(shí)交換兩個(gè)表的表名詳解

    這篇文章主要給大家介紹了關(guān)于Mysql如何同時(shí)交換兩個(gè)表的表名,以及MySQL命令rename修改表名的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-01-01

最新評(píng)論