一、现象
先看现象:数据库表有大写、有小写。
二、探索过程
因为项目使用了 Spring + dorado 框架组合,原以为是框架配置问题,先尝试从配置文件着手,如下:
第一轮探索:从项目配置文件着手
<property name="hibernateProperties">
<props>
<!-- <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop> -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.connection.isolation">8</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
</props>
</property>
hibernate.ejb.naming_strategy 表示用于指定用于创建数据库表和列名的命名策略(Naming Strategy)。命名策略决定了 Hibernate 如何将实体类的属性名、类名等映射到数据库表和列的名称。
org.hibernate.cfg.ImprovedNamingStrategy 表示在表和列名称之间使用下划线并将名称转换为小写,这在需要与已有数据库命名规范不匹配时很有用。
默认情况下,Hibernate使用物理命名策略(Physical Naming Strategy)和隐式命名策略(Implicit Naming Strategy)。物理命名策略是指实体类和属性名称直接映射到数据库表和列名称,而隐式命名策略则根据一定的规则生成这些名称。
在application.properties文件中配置:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.hibernate.naming.physical-strategy 表示用于指定Hibernate的物理命名策略(Physical Naming Strategy)。
请注意,从 Hibernate 5 开始,推荐使用 org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
作为物理命名策略的默认实现。
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
当然,也可以自定义实现命名规则,我没有自己实现,下面的搬来的示例代码。
package com.example;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class MyPhysicalNamingStrategy implements PhysicalNamingStrategy {
@Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) {
// 实现逻辑
return name;
}
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment) {
// 实现逻辑
return name;
}
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
// 实现逻辑
return name;
}
@Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironment) {
// 实现逻辑
return name;
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) {
// 实现逻辑
return name;
}
}
经过上面配置,删除数据表后,重新运行项目 。
结果:☹️☹️☹️。依然是大写
第二轮探索:从数据库层面着手
经过上面的修改,发现还是不能生效后,带着疑问去看看数据库是不是有什么配置影响了。
果然,经过一顿搜索,发现MySQL数据库配置有一个名为 lower_case_table_names 的配置项,可以影响数据表的大小写。其配置值如下所示:
- 0(或默认值): 表名和数据库名区分大小写。
- 1: 表名和数据库名不区分大小写。在创建表和查询时,将它们视为大小写不敏感。
- 2: 表名区分大小写,数据库名不区分大小写。在创建表时,表名大小写敏感;在查询时,表名大小写不敏感,但数据库名大小写敏感。
看了以上配置说明后,在MySQL配置文件(通常是 my.cnf
或 my.ini
)中,添加以下行来设置:
[mysqld]
lower_case_table_names=1
请注意⚠️:
- 在更改此设置后,可能需要重启MySQL服务才能使更改生效。
- 在MySQL的官方文档中建议,在使用
lower_case_table_names
设置时,不要将其设置为0,以免在移植数据库到大小写不敏感的系统时造成问题。
查看配置项:
show variables like 'lower_case_table_names%';
我在配置时,因为我使用了 docker 来运行 MySQL,所以在配置时遇到了如下问题:
1、docker-compose.yml 配置文件./mysql/conf/upload.cnf 挂载不上去,报错:
Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/host_mnt/opt/nginx/dockers/lnmp/mysql/conf/upload.cnf" to rootfs at "/etc/mysql/conf.d/upload.cnf": mount /host_mnt/opt/nginx/dockers/lnmp/mysql/conf/upload.cnf:/etc/mysql/conf.d/upload.cnf (via /proc/self/fd/9), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
经 google 后,是因为文件权限问题:
$ chmod 655 ./mysql/conf/upload.cnf
2、额外的配置文件(upload.cnf)不生效
直接进入容器后,查看了my.cnf 文件
# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html
[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
innodb_buffer_pool_size = 256M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M
skip-host-cache
skip-name-resolve
datadir=/var/lib/mysql
socket=/var/run/mysqld/mysqld.sock
secure-file-priv=/var/lib/mysql-files
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
#log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
[client]
socket=/var/run/mysqld/mysqld.sock
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
注意以下两个目录,在 docker-compose.yml 是不是挂载正确:
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mysql.conf.d/
最后,重启 MySQL 容器,立即生效了。
最终结果:
三、总结
- 因为项目使用了比较老旧 dorado 框架技术,很容易联想到时框架本身问题。
- 对MySQL数据库基本配置不熟悉。
附录:docker-compose.yml文件
mysql57:
image: mysql:5.7.44
container_name: MySQL-5.7
ports:
- "3308:3306"
command:
--max_connections=1000
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--default-authentication-plugin=mysql_native_password
restart: always
volumes:
- ./mysql/data:/var/lib/mysql
- ./mysql/conf/my.cnf:/etc/my.cnf
- ./mysql/conf/upload.cnf:/etc/mysql/conf.d/upload.cnf:rw
environment:
- MYSQL_ROOT_PASSWORD=kcsm@111
- LOWER_CASE_TABLE_NAMES=1
networks:
- lnmp-network