一、背景
问题的原因也是十分简单,在csdn上随便百度就可以找到解决问题的方法,但为什么还要写这篇文章呢?因为在去尝试的时候自己遇到了一些有趣的问题,并且从中也学到了有意思的知识。
报错: java.sql.SQLException: Field '表字段名' doesn't have a default value,这个错误的产生是使用java代码操作数据库的时候或者在Navicat里面(MYSQL客户端)执行sql语句时出错,mysql要求该字段必须指定一个默认值;
二、情景
我模拟出来一个简单的情景,下面是数据库的表结构情况:
我并不认为这样的表结构有什么问题,但进行添加操作(不给name指定值),会报错:Field 'name' doesn't have a default value ,‘name’和'address'后面相比较缺少了“DEFAULT NULL”(默认值),在此之前我认为就算‘name’不指定"DEFAULT NULL"(默认值)能达到的效果和'address'效果是一样的;
解决方法也是多种多样的,要根据自己的实际业务需求去选择方法解决,解决方法我分为了指定字段默认值和不指定字段默认值两类解决方法。
三、解决
3.1 指定字段默认值
你可以通过下方sql语句来完成对表字段的默认值的设置:
ALTER TABLE '表名' ALTER COLUMN '表字段名' SET DEFAULT NULL;
设置完之后为确保没问题可以使用指令进行查看表结构是否调整(因为有时候像Navict刷新半天也没有更新到最新状态很烦):
show create table '表名';
3.2 不指定字段默认值
第一种:就是每次使用代码操作数据库之前为这个字段指定一个默认值;
第二种:
MySQL 5.0.2 版本之后,默认情况下对于每个插入到表中的记录,如果未提供该表中的某列的值,则该列的值将会被设置为默认值,而不是空值或 NULL,那是因为MySQL 在版本 5.0.2 中引入了 STRICT_TRANS_TABLES
模式。
这种模式提高了数据插入、更新和删除操作的严格性,确保在执行此类操作时不会引起数据不一致或冲突。
在
STRICT_TRANS_TABLES
模式下,MySQL 使用更严格的事务模型来处理 INSERT、UPDATE 和 DELETE 查询,它执行原子性、一致性、隔离性和持久性这四个 ACID 属性。当执行 INSERT 或 UPDATE 操作时,如果数据不能插入或更新到数据表中,则该操作将被回滚,并返回错误信息。需要注意的是,使用
STRICT_TRANS_TABLES
模式可能会增加数据库操作的开销,对于大型数据集或高频率的写入操作可能会影响系统性能,因此需要谨慎使用。如果你不希望使用这种模式可以在 MySQL 的配置文件(my.cnf)中将sql_mode
参数设置为其它模式。另外,在 MySQL 5.7 版本后,
STRICT_TRANS_TABLES
已经包含在ONLY_FULL_GROUP_BY
模式中,这也是默认的 SQL 模式。如果您想在 MySQL 5.7 及以上版本中使用STRICT_TRANS_TABLES
模式,则需要先关闭ONLY_FULL_GROUP_BY
模式,然后启用STRICT_TRANS_TABLES
模式。
因此,要想在不指定默认值的情况下,依旧可以正常完成字段的插入操作,就需要将这个STRICT_TRANS_TABLES
模式从mysql的配置文件中剔除掉。
步骤一:现找到MySQL安装的位置
Windows安装的MySQL配置文件可以通过命令查找出来
-- 配置文件名称my.iniselect @@basedir;select @@datadir;
Linux:
MySQL 在 Linux 中的配置文件名为 my.cnf
,它通常位于 /etc/mysql/
或 /etc/
目录下。
步骤二:修改sql-mode配置,并重启MySQL
(1)windows重启 MySQL 服务
win+R组合键,弹出运行窗口, 输入 services.msc
(2)Linux 下重启 MySQL 服务
输入以下命令以停止 MySQL 服务:
-- 停止MySQL服务sudo systemctl stop mysql-- 开启MySQL服务sudo systemctl start mysql-- 重启MySQL服务sudo systemctl reload mysql
做完以上的操作之后,我们就可以实验了,不知道你们得出的是什么样的结果,欢迎评论区留言;
四、结论
发现使用MySQL客户端去添加已经没有问题了,但使用java代码连接数据库去操作,依旧还是报错,很烦;
所以,我找来了一位大佬,在大佬的分析下,通过查看底层的代码,最终报错定位到
package com.mysql.cj.jdbc包下面的 ConnectionImpl 这个类里面setupServerForTruncationChecks()方法里面,其中jdbcCompliantTruncation的默认值为true,将Mysql JDBC Driver参数jdbcCompliantTruncation设置为false,即可运行成功,代码如下;
// 底层代码private void setupServerForTruncationChecks() throws SQLException { synchronized (getConnectionMutex()) { RuntimeProperty jdbcCompliantTruncation = this.propertySet.getProperty(PropertyKey.jdbcCompliantTruncation); if (jdbcCompliantTruncation.getValue()) { String currentSqlMode = this.session.getServerSession().getServerVariable("sql_mode"); boolean strictTransTablesIsSet = StringUtils.indexOfIgnoreCase(currentSqlMode, "STRICT_TRANS_TABLES") != -1; if (currentSqlMode == null || currentSqlMode.length() == 0 || !strictTransTablesIsSet) { StringBuilder commandBuf = new StringBuilder("SET sql_mode='"); if (currentSqlMode != null && currentSqlMode.length() > 0) { commandBuf.append(currentSqlMode); commandBuf.append(","); } commandBuf.append("STRICT_TRANS_TABLES'"); this.session.execSQL(null, commandBuf.toString(), -1, null, false, this.nullStatementResultSetFactory, null, false); jdbcCompliantTruncation.setValue(false); // server's handling this for us now } else if (strictTransTablesIsSet) { // We didn't set it, but someone did, so we piggy back on it jdbcCompliantTruncation.setValue(false); // server's handling this for us now } } } }
在yaml文件中添加上&jdbcCompliantTruncation=false,便可添加成功;spring: datasource: url: jdbc:mysql://localhost:3306/demo_03?useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8&jdbcCompliantTruncation=false username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver
OK
来源地址:https://blog.csdn.net/m0_71074676/article/details/130463009