【问题标题】:"Incorrect string value" error with utf8 tables on some computers某些计算机上的 utf8 表出现“不正确的字符串值”错误
【发布时间】:2021-06-09 12:56:43
【问题描述】:

我正在开发与远程 MariaDB 数据库通信的 Delphi 应用程序(通过 ADO 和 ODBC 驱动程序)。发现在某些计算机上无法将西里尔字符串添加到 DB。像这样的错误信息: [MySQL][ODBC 8.0(w) Driver][mysqld-5.5.5-10.3.29-MariaDB]Incorrect string value: '\xC2\xC2\xC8 \xF1\xE8…' for column <here's target tables and columns name> at row 1
字符集是 utf8,整理 - utf8_bin。它在我的装有 Windows 10 的计算机上运行良好,但在装有 Windows 8 和 Vista 的计算机上触发了错误。因此,据我了解,问题不在数据库设置中,而在操作系统中。它可以是什么?也许是区域设置或类似的东西?

更新

表:

SHOW CREATE TABLE equip;

CREATE TABLE `equip` (
 `eqid` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `eqname` varchar(255) COLLATE utf8_bin NOT NULL COMMENT 'Наименование оборудования',
 PRIMARY KEY (`eqid`),
 UNIQUE KEY `eqname_UNIQUE` (`eqname`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

连接到数据库:

  procedure OpenDBConnection;
  begin
    dmMain.dbConnection.Connected := False;
    dmMain.dbConnection.ConnectionString := Format(
      'Driver={MySQL ODBC 8.0 Unicode Driver};Port=%s;Server=%s;Database=%s;User=%s;Password=%s;',
      [Port, Server, Database, User, Password]);
    dmMain.dbConnection.Connected := True;
  end;

将数据插入数据库:

const
  tblEquip = 'equip';
  colEquipName = 'eqname';

  queryInsertEquipment =
    ' INSERT INTO ' + tblEquip + '(' +
    colEquipName + ') ' +
    'VALUES(:' +
    colEquipName + '); ';


function TdmMain.AddEquipment(const Equip: TEquipment;
  const RefreshEquipmentListDataSet: Boolean): Integer;
begin
  Result := 0;

  try
    cmdTemp.CommandText := queryInsertEquipment;
    cmdTemp.Parameters.ParamByName(colEquipName).Value := Equip.Name;
    cmdTemp.Execute;
    Result := GetLastID;

    if RefreshEquipmentListDataSet then
      RefreshDataSet(dsetEquipment, colEquipID, Result);
  except on E: Exception do
    fmMessage.ShowMessage(msgErrorAddEquipment, mtError);
  end;
end;

【问题讨论】:

  • 包括您与数据库连接的代码,并确保您使用 UTF-8 与您的数据库通信。如果您不执行后者,则很可能取决于驱动程序的默认设置。这看起来像 ISO-8859-5: ТТШ ёш
  • @AmigoJack,谢谢你的回复,我用代码更新问题。
  • 今天也尝试在其他虚拟机上运行 Windows 10 - 它可以工作,但在 Windows 7 或 Vista 上 - 不行。再加上这些机器上的 MDAC 更新到 2.8 - 没有结果。
  • 正如我所担心的那样:你无处可说你正在使用 UTF-8。考虑在建立与数据库的连接后执行SET NAMES utf8mb4。另请阅读UTF-8 all the way through
  • 如果通过代码cmdTemp.Parameters.ParamByName(colEquipName).DataType := ftWideString;将参数类型设置为ftWideString,那么它工作正常。但是虽然很奇怪 - 相同的代码在 Windows 10 上工作,但在旧操作系统上不工作。

标签: mysql delphi mariadb odbc charset


【解决方案1】:

您必须定义客户端和数据库之间通信的编码。如果您不这样做,那么数据库会采用一种编码,而客户端可能会采用不同的编码。很可能较旧的安装默认不使用 UTF-8。仅仅因为您的所有数据库表都是使用 Unicode 字符集和排序规则定义的,这并不意味着写入和读取这些表的数据以相同的编码进行通信。

  • MySQLSET NAMES 是一次设置多个变量的便捷方式。使用像 utf8 这样的编码不会转换任何东西 - 它告诉数据库解释该编码中的所有传入字节(并在为所有结果发送字节时使用该编码)。李>
  • PHPmysqli_set_charset() 在内部也是这样做的,但提供了这个函数来让你知道你对其他方便函数的选择(例如 mysqli_real_escape_string())。

在您确定通信实际上以 UTF-8 进行后,只剩下您的客户端本身:如果您交出 Delphi Widestring,驱动程序是否会为您进行转换?或者您是否必须提供实际的 UTF-8 编码字节作为查询?链接不是为了好玩:文档告诉您足够的事实,可以检查和测试 - 无需质疑它们并做出疯狂的假设 - 只会让您理解错误。

【讨论】:

  • 我尝试使用SET NAMES,但收到错误SET NAMES not allowed by driver,因为它不受ODBC 支持(查看stackoverflow.com/a/6417321/813350)。还尝试直接设置变量character_set_clientcharacter_set_resultscharacter_set_connectionutf8,但没有结果。
  • 你确定在连接中总是选择charset=utf8; 是正确的吗?您是否尝试过使用用户的实际语言环境编码,即cp1251?驱动的默认值是多少?这看起来像 shotgun debugging,我帮不了你。
猜你喜欢
  • 2013-02-10
  • 2017-11-13
  • 2017-09-04
  • 2012-02-01
  • 2020-07-29
  • 2012-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多