Java 中字符串以 Unicode 方式编码的, 其长度通常计算的是字符数,一个中文也算一个字符:
public static void main(String[] args) {
String fileName = "中文English,12345";//中文、英文、标点、数字都算一个字符
int len = fileName.length();
System.out.println("len="+ len);
}
len=15
字节取决于所使用的字符编码,通常我使用UTF-8,Mysql中一个UTF-8编码的字符占3字节。例如:
CREATE TABLE `group_space` (
`GROUP_ID` decimal(16,0) NOT NULL,
`USER_FILE_ID` decimal(18,0) DEFAULT NULL,
`USER_ID` decimal(20,0) DEFAULT NULL,
`GROUP_SIZE` decimal(10,0) DEFAULT NULL,
`CREATE_TIME` timestamp NULL DEFAULT NULL,
`REVIEW_STATUS` decimal(1,0) DEFAULT NULL,
`GROUP_NAME` varchar(5) DEFAULT NULL,
`LAST_OPTIME` timestamp NULL DEFAULT NULL,
`PUBLIC_LEVEL` decimal(1,0) DEFAULT NULL,
`ENTER_LEVEL` decimal(1,0) DEFAULT NULL,
`GROUP_NUMBER` varchar(20) DEFAULT NULL,
`GROUP_MODEL` decimal(3,0) DEFAULT NULL,
`GROUP_STATUS` decimal(1,0) DEFAULT NULL,
`UNI_CONTACT_ID` decimal(20,0) DEFAULT NULL,
PRIMARY KEY (`GROUP_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
15字节。插入数据,给该GROUP_NAME字段赋值5个中文’我是中国人‘,sql如下:
INSERT INTO `group_space` (`GROUP_ID`, `USER_FILE_ID`, `USER_ID`, `GROUP_SIZE`, `CREATE_TIME`, `REVIEW_STATUS`, `GROUP_NAME`,
`LAST_OPTIME`, `PUBLIC_LEVEL`, `ENTER_LEVEL`, `GROUP_NUMBER`, `GROUP_MODEL`, `GROUP_STATUS`, `UNI_CONTACT_ID`)
VALUES ('113012502705', '413602500002', '8241', NULL, '2015-09-11 16:24:40', '1',
'我是中国人', '2015-09-11 16:24:40', '2', '2', '113012502701', '200', '1', NULL);
执行无异常,结果:
同样的insert语句,GROUP_NAME增加一个字符’我是中国人a‘,赋值更换主键后再次执行,抛出异常:
[SQL]INSERT INTO `group_space` (`GROUP_ID`, `USER_FILE_ID`, `USER_ID`, `GROUP_SIZE`, `CREATE_TIME`, `REVIEW_STATUS`, `GROUP_NAME`,
`LAST_OPTIME`, `PUBLIC_LEVEL`, `ENTER_LEVEL`, `GROUP_NUMBER`, `GROUP_MODEL`, `GROUP_STATUS`, `UNI_CONTACT_ID`)
VALUES ('113012502706', '413602500002', '8241', NULL, '2015-09-11 16:24:40', '1',
'我是中国人a', '2015-09-11 16:24:40', '2', '2', '113012502701', '200', '1', NULL);
[Err] 1406 - Data too long for column 'GROUP_NAME' at row 1
当服务出现类似因为字段长度不够的问题时,一般首先想到的是进行字段扩容。但是我负责的系统MySql是个分布式的集群,且数据量在亿级以上,而且出现较长字符串的场景只是偶尔外部原因导致,所以并没有采用字段扩容的方式解决该问题。直接在DAO层做了一个字符串截取,对超过数据库限制的GROUP_NAME字段做截取处理,保留前后一部分字符,去除中间部分,用“...”代替。字符串截取代码:
public static void main(String[] args) {
//fileName 字段进行截断(前7字符+...+后10字符)
String fileName = "MySql数据库varchar长度tips-zhujinq.html";
int maxLen = 20;
if (StringUtils.isNotBlank(fileName) && fileName.length() > maxLen) {
int len = fileName.length();
fileName = fileName.substring(0, (maxLen/2)-3) + "..."+ fileName.substring(len-(maxLen/2), len);
}
System.out.println("fileName=" + fileName+", newLen=" + fileName.length());
}
执行结果:
fileName=MySql数据...ujinq.html, newLen=20