【问题标题】:How to enforce case sensitive table and column names in MySql?如何在 MySql 中强制区分大小写的表名和列名?
【发布时间】:2012-03-15 14:48:53
【问题描述】:

问题是我们在 windows 机器上工作,一旦完成,我们将代码部署到 unix 机器上。该代码在 Windows 上运行良好,但在 unix 中,在正确更改表名后,我们会收到类似“不存在这样的表”的错误,它在 unix 中也可以正常运行。实际上,在 Windows 中默认情况下没有区分大小写的表名,但在 unix 中它们确实有(读到 MySQL 表实际上是文件,在 unix 中我们有区分大小写的文件名,但在 Windows 中没有)。解决方法可能是再次创建所有表,并让表名小写。是的,我们也可以这样做,没关系。

但是,我们仍然可以对 MySql(windows 机器)中的表名进行区分大小写。如果是,那么请告诉我该怎么做。

【问题讨论】:

  • 这是一个有趣的问题。导致您的 SQL 在 Windows 中而不是在基于 Unix 的系统中工作的问题。 AFAIK,没有解决办法。
  • @greggles - Mac OS 有不同的考虑。

标签: mysql windows case-sensitive


【解决方案1】:

该设置称为lower_case_table_names。如果设置为0,比较会区分大小写。

然而,

如果您在具有不区分大小写的文件名的系统(例如 Windows 或 Mac OS X)上运行 MySQL,则不应将此变量设置为 0。如果在不区分大小写的文件系统上使用 --lower-case-table-names=0 将此变量强制为 0,并使用不同的字母大小写访问 MyISAM 表名,则可能会导致索引损坏。

在所有系统(包括 Linux)中使所有表名小写,即。将其设置为 1 的值,听起来是更好的选择:

表名称以小写形式存储在磁盘上,名称比较不区分大小写。 MySQL 在存储和查找时将所有表名转换为小写。此行为也适用于数据库名称和表别名。

【讨论】:

  • 问题是我可以在 windows 机器上更改设置,但不能在 unix 系统中更改。通过这个解决方案,如果我可以访问 unix 中的 my.ini 文件,我可以将此设置更改为 1,它会解决问题。但我想反过来。意味着我不想在 unix 中创建不区分大小写的表格,而是希望在 windows 中创建区分大小写的表格。
  • @Rakesh 请参阅选项0,但不建议这样做。我不明白这个问题是如何发生的 - 你不能确保你的代码使用正确的名称吗?部署到 Linux 时是否会更改表名?
【解决方案2】:

在 Unix 上,lower_case_table_names 的默认值为 0。在 Windows 上,默认值为 1。在 Mac OS X 上,MySQL 4.0.18 之前的默认值为 1,自 4.0.18 起为 2。

要解决此问题,您可以在 my.ini 文件中查找设置:lower_case_table_names,该文件位于以下位置或附近:C:\Program Files\MySQL\MySQL Server 4.1,具体取决于您运行的版本。如果你没有找到设置,你可以像我一样将它添加到 my.ini 文件的末尾,如下所示:

lower_case_table_names=0

在测试它是否工作之前,记得重启 MySQL 服务。

如果您只在一个平台上使用 MySQL,您通常不必更改 lower_case_table_names 变量的默认值。但是,如果要在文件系统区分大小写不同的平台之间传输表,则可能会遇到困难。例如,在 Unix 上,您可以有两个名为 my_table 和 MY_TABLE 的不同表,但在 Windows 上,这些名称被认为是相同的。为避免因数据库或表名字母大小写引起的数据传输问题,您有两种选择:

在所有系统上使用 lower_case_table_names=1。这样做的主要缺点是,当您使用 SHOW TABLES 或 SHOW DATABASES 时,您看不到原始字母大小写的名称。

在 Unix 上使用 lower_case_table_names=0,在 Windows 上使用 lower_case_table_names=2。这将保留数据库和表名的字母大小写。这样做的缺点是您必须确保您的语句在 Windows 上始终以正确的字母大小写引用您的数据库和表名。如果您将语句转移到字母大小写很重要的 Unix,如果字母大小写不正确,它们将不起作用。

例外:如果您使用 InnoDB 表并试图避免这些数据传输问题,则应在所有平台上将 lower_case_table_names 设置为 1 以强制将名称转换为小写。

如果您打算在 Unix 上将 lower_case_table_names 系统变量设置为 1,则必须先将旧的数据库和表名转换为小写,然后再停止 mysqld 并使用新的变量设置重新启动它。

请查看 MySQL 网站以获取更多信息,以及一些重要的警告http://dev.mysql.com/doc/refman/4.1/en/identifier-case-sensitivity.html

【讨论】:

    【解决方案3】:

    (此答案并未为您提供解决问题的明确途径,但提供了更多见解。)

    Mac OS 的注意事项与 Windows 不同:

    9.2.2 标识符区分大小写 在 MySQL 中,数据库对应于数据目录中的目录。数据库中的每个表对应于数据库目录中的至少一个文件(可能更多,取决于存储引擎)。触发器也对应于文件。因此,底层操作系统的大小写敏感性在数据库、表和触发器名称的大小写敏感性中起作用。这意味着此类名称在 Windows 中不区分大小写,但在大多数 Unix 中都区分大小写。一个值得注意的例外是 macOS,它基于 Unix,但使用不区分大小写的默认文件系统类型 (HFS+)。然而,macOS 也支持 UFS 卷,它是区分大小写的,就像在任何 Unix 上一样。请参阅第 1.8.1 节,“标准 SQL 的 MySQL 扩展”。 lower_case_table_names 系统变量也会影响服务器如何处理标识符区分大小写,如本节后面所述。

    -- https://dev.mysql.com/doc/refman/8.0/en/identifier-case-sensitivity.html

    来自一些错误报告:

    未能将表名完全转换为小写,导致稍后在尝试重命名表时出错。 (尤其是分区表)

    在 macOS 上未将表名与设置为 lower_case_table_names=2 的小写进行比较,这导致重新启动服务器后不稳定。 (错误 #28170699、错误 #91204)

    MySQL 8.0的重要说明:

    现在禁止使用与初始化服务器时使用的设置不同的lower_case_table_names 设置来启动服务器。该限制是必要的,因为数据字典表字段使用的排序规则基于服务器初始化时定义的设置,并且使用不同的设置重新启动服务器会在标识符的排序和比较方式方面引入不一致。 (错误 #27309094,错误 #89035)

    当我最后一次遇到这个问题时,我决定完成将所有表名小写并更改所有代码的艰巨任务。抱歉,我没有更好的办法。

    【讨论】:

      【解决方案4】:

      您可以将代码放入 JPA 中,将所有物理名称、模式名称、序列名称和表名称转换为小写,并在两个系统上使用大小写,这样数据库就可以从 Windows 导出并导入 Unix,而不会遇到任何问题。

      在某处添加此类:

      public class ImprovedNamingStrategy implements PhysicalNamingStrategy {
      
          @Override
          public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnv) {
              return convert(identifier);
          }
      
          @Override
          public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnv) {
              return convert(identifier);
          }
      
          @Override
          public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnv) {
              return convert(identifier);
          }
      
          @Override
          public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnv) {
              return convert(identifier);
          }
      
          @Override
          public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnv) {
              return convert(identifier);
          }
      
          /**
           * Converts table name.
           *
           * @param identifier
           *            the identifier.
           * @return the identifier.
           */
          private Identifier convert(Identifier identifier) {
              if (identifier == null || identifier.getText().trim().isEmpty()) {
                  return identifier;
              }
              return Identifier.toIdentifier(identifier.getText().toLowerCase());
          }
      }
      

      并将这个属性添加到你的 persistence.xml

      <property name="hibernate.physical_naming_strategy" value="ImprovedNamingStrategy" />
      

      【讨论】:

        猜你喜欢
        • 2011-09-09
        • 2011-01-01
        • 2017-01-31
        • 1970-01-01
        • 1970-01-01
        • 2016-11-10
        • 2011-09-02
        相关资源
        最近更新 更多