mysql别悄悄帮我做事了

背景:

书接上文,当我在接收工单消息时,直接以字符串(String)的形式接收了日期信息,而没有将其转换为日期(Date)格式,而数据表中是日期格式。这样一来,在设计实体类的时候,我也相应地使用了字符串类型来定义这个字段。当时用的mysql测试的没问题,线上环境用的pgsql,直接报错了。

原因:

实体类是String字段,数据表中是Date类型。mysql有隐式类型转换,没有报错,pgsql对类型检查更加严格,直接会报错。

MySQL 在处理数据时,会进行隐式类型转换。将一个字符串插入到日期字段时,MySQL 会尝试将字符串转换为日期。如果转换成功,则插入成功;如果失败,则可能插入 NULL 或者报错。

java 复制代码
String publishDate = sysDictInfoWithVersionFromDTO.getPublishDate();
// 解析publishDate为时间
if (publishDate == null || publishDate.isEmpty()) {
    throw new IllegalArgumentException("生效时间不能为空");
}
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 根据实际日期格式调整
Date parsedDate;
try {
    parsedDate = dateFormat.parse(publishDate);
    // 进一步处理 parsedDate
} catch (ParseException e) {
    throw new IllegalArgumentException("Invalid date format: " + publishDate, e);
}

MySQL 对数据类型转换的底层机制

MySQL 在处理数据类型转换时,相对宽松。

1. 隐式类型转换:

MySQL 会在必要时自动进行隐式类型转换,以适应目标列的数据类型。这种转换通常发生在插入数据、更新数据或执行查询时。

2. 日期格式解析:

MySQL 会尝试解析字符串,以确定其是否符合日期格式。如果字符串格式正确,MySQL 会将其转换为 DATE 类型。如果格式不正确,MySQL 会尝试解析并可能插入一个默认值(如 0000-00-00)或抛出错误。

3. 默认值和错误处理:

如果转换失败,MySQL 会根据配置和上下文决定如何处理。例如,如果 sql_mode 设置为 STRICT_TRANS_TABLES 或 STRICT_ALL_TABLES,MySQL 会抛出错误。否则,它可能会插入一个默认值。

4. 示例:

当我传入一个String类型到一个日期类型,mysql会尝试转换,同时传入的字符串是"2024-11-12",它会试着解析这个字符串,看能不能转成 DATE 类型。是的话直接插入2024-11-12 00:00:00,所以当时流程可以走通。

底层机制详解

1. 隐式类型转换

MySQL 的隐式类型转换机制主要依赖于其内部的类型转换函数。这些函数在 SQL 执行过程中被调用,以确保数据类型的一致性。例如:

STR_TO_DATE(str, format):将字符串转换为日期。

DATE(str):将字符串转换为日期。

CAST(expr AS type):将表达式转换为目标类型。

字符串到数字的转换
sql 复制代码
  - MySQL 会尝试将字符串转换为数字。如果字符串以数字开头,MySQL 会提取前面的数字部分进行转换。
  - 如果字符串不能转换为数字,MySQL 会将其视为 0。
  SELECT 1 + '1'; -- 结果为 2
  SELECT 1 + '1a'; -- 结果为 2,因为 '1a' 被转换为 1
  SELECT 1 + 'a1'; -- 结果为 1,因为 'a1' 被转换为 0
数字到字符串的转换
arduino 复制代码
- 当需要将数字与字符串连接时,MySQL 会自动将数字转换为字符串。
SELECT CONCAT('The number is ', 1); -- 结果为 'The number is 1'
日期和时间的转换
sql 复制代码
  - `STR_TO_DATE` 函数将字符串转换为日期。
  - `DATE` 函数从日期时间字符串中提取日期部分。
  SELECT STR_TO_DATE('2024-11-13', '%Y-%m-%d'); -- 结果为 '2024-11-13'
  SELECT DATE('2024-11-13 12:34:56'); -- 结果为 '2024-11-13'
比较操作中的类型转换
ini 复制代码
  - 在比较操作中,MySQL 会尝试将字符串转换为数字进行比较。
  SELECT '1' = 1; -- 结果为 1 (true)
  SELECT '1a' = 1; -- 结果为 1 (true),因为 '1a' 被转换为 1
  SELECT 'a1' = 1; -- 结果为 0 (false),因为 'a1' 被转换为 0
NULL 值的处理
sql 复制代码
  - 任何与 `NULL` 的运算结果都是 `NULL`。
  - `IFNULL` 函数可以用来处理 `NULL` 值,提供一个默认值。
  SELECT 1 + NULL; -- 结果为 NULL
  SELECT IFNULL(1 + NULL, 0); -- 结果为 0
字符集和排序规则的转换
ini 复制代码
 - MySQL 会自动处理字符集和排序规则的转换,以确保字符串比较的正确性。
SELECT 'abc' = _utf8mb4'abc'; -- 结果为 1 (true)

需要类型转换时,使用显式的转换函数(如 CASTCONVERTSTR_TO_DATE 等),以提高代码的可读性和可维护性。

sql 复制代码
SELECT CAST('1' AS SIGNED) + 1; -- 结果为 2
SELECT CONCAT('The number is ', CAST(1 AS CHAR)); -- 结果为 'The number is 1'

2. 日期格式解析

MySQL 使用内置的日期解析器来处理日期字符串。解析器会尝试识别常见的日期格式,如 YYYY-MM-DD、YYYYMMDD、YY-MM-DD 等。如果字符串格式正确,解析器会返回一个有效的 DATE 值。

3. 默认值和错误处理

MySQL 的行为受 sql_mode 系统变量的影响。sql_mode 定义了 MySQL 的操作模式,包括数据验证和错误处理策略。

常见的 SQL_MODE
模式名称 描述
STRICT_TRANS_TABLES 对事务表(如 InnoDB)启用严格模式。严格模式:如果插入或更新操作违反了数据类型约束,MySQL 会抛出错误而不是警告,并且不会执行该操作。
STRICT_ALL_TABLES 对所有表(包括 MyISAM 和 InnoDB)启用严格模式。
NO_ZERO_DATE 禁止插入零日期('0000-00-00')。
NO_ZERO_IN_DATE 禁止插入部分零日期(如 '2023-00-00')。
ERROR_FOR_DIVISION_BY_ZERO 当除数为零时,返回错误而不是 NULL。
ONLY_FULL_GROUP_BY 要求 GROUP BY 子句中包含所有选择列,除非这些列是聚合函数的结果。
ANSI_QUOTES 允许使用双引号来表示标识符(如表名和列名),而不是字符串。
PIPES_AS_CONCAT 将 || 作为字符串连接操作符,而不是逻辑或操作符。
IGNORE_SPACE 允许在函数名和左括号之间有空格。
TRADITIONAL 包含多个严格模式和其他限制,使 MySQL 行为更接近于传统 SQL 标准。

查看当前的 SQL_MODE

scss 复制代码
SELECT @@sql_mode;

设置 SQL_MODE

ini 复制代码
配置文件设置
在 my.cnf 或 my.ini 文件中添加或修改以下内容:
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,ONLY_FULL_GROUP_BY'
动态设置
SET SESSION sql_mode='STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,ONLY_FULL_GROUP_BY';
全局设置(已经打开的会话不会立即受到新设置的影响)
SET GLOBAL sql_mode='STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO,ONLY_FULL_GROUP_BY';

总结

mysql真好用,嘿嘿。其实写完代码,还是要测试一下pg环境的,当时只测试了mysql环境下的情况。还好系统还没正式投入使用。

相关推荐
ITCharge7 分钟前
Docker 万字教程:从入门到掌握
后端·docker·容器
落尘29834 分钟前
Bean 的作用域和生命周期
后端
是店小二呀35 分钟前
处理Linux下磁盘空间不足问题的实用指南
后端
落尘29836 分钟前
如何通过 JWT 来解决登录认证问题
后端
是店小二呀37 分钟前
处理Linux下内存泄漏问题的诊断与解决方法
后端
倚栏听风雨43 分钟前
IDEA 插件开发 对文件夹下的类进行 语法检查
后端
郝同学的测开笔记1 小时前
云原生探索系列(十七):Go 语言sync.Cond
后端·云原生·go
uhakadotcom1 小时前
持续写作的“农耕思维”:如何像农民一样播种,收获稳定成长与收入
后端·面试·github
Java中文社群1 小时前
国内首个「混合推理模型」Qwen3深夜开源,盘点它的N种对接方式!
java·人工智能·后端
JohnYan1 小时前
工作笔记 - ASN.1密钥结构和编码研究
javascript·后端·安全