在 MS Access (VBA) 中使用 ADODB 将非 ASCII 插入 MySQL 数据库时出现“不正确的字符串值”,但重试有效

Posted

技术标签:

【中文标题】在 MS Access (VBA) 中使用 ADODB 将非 ASCII 插入 MySQL 数据库时出现“不正确的字符串值”,但重试有效【英文标题】:"Incorrect string value" when inserting non-ASCII into MySQL database using ADODB in MS Access (VBA), but retry works 【发布时间】:2016-12-05 23:55:24 【问题描述】:

在找到bug in mysql ODBC 5.3.6 后,我遇到了另一个问题,使用 MySQL ODBC 5.3.4 也会发生。

我有一个 MS Access 应用程序(Office 2016 ProPlus 32 位),它使用 ADODB 和 MySQL ODBC(5.3.4 32 位)连接到 Windows 上的本地 MySQL 数据库服务器(5.7.16 64 位) 10 Pro 64 位计算机。在 MySQL 数据库中插入非 ASCII 字符失败并出现错误“字符串值不正确”,但如果我再次尝试相同的语句,则 SQL 语句将正确执行并将正确的值插入到数据库表中!

为了隔离问题,我创建了下表:

  CREATE TABLE test2 (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(100) CHARACTER SET utf8mb4,
    PRIMARY KEY (id));

还有一个测试 MS Access 数据库,其中包含以下 VBA 代码(以及对 Microsoft ActiveX Data Objects 6.1 库的引用):

  Public Function dbTestIt2() as Long

  Dim dbConn As New ADODB.Connection
  Dim dbCmd As New ADODB.Command
  Dim dbParams As New ADODB.Parameter
  Dim l As Long

      dbConn.ConnectionString = "Driver=MySQL ODBC 5.3 Unicode Driver;option=3;database=xxx;user=yyy;password=zzz;"
      dbConn.Open
      With dbCmd
          .ActiveConnection = dbConn
          .CommandType = adCmdText
          .CommandText = " INSERT INTO test2 (name) VALUES (?);"
          dbParams.Type = adVarChar
          dbParams.Size = 100
          dbParams.Value = "abcdèfgh"
          dbParams.Direction = adParamInput
          .Parameters.Append dbParams
          .Execute l, , adExecuteNoRecords
      End With
      dbConn.Close

      dbTestIt2 = l

  End Function

my.ini 中的相关行:

  [client]
  default-character-set=utf8mb4
  [mysql]
  default-character-set=utf8mb4
  [mysqld]
  character-set-server=utf8mb4
  collation-server=utf8mb4_unicode_ci

以下是测试结果:

    执行在 .Execute 语句处停止,错误为 80004005:[MySQL][ODBC 5.3(w) 驱动程序][mysqld-5.7.16-log] 字符串值不正确:行中列 'name' 的 '\xE8gh' 1; 如果我继续调试(F8),SQL语句正确执行,正确的值插入到数据库表中; 如果我使用“ANSI”ODBC 驱动程序而不是“Unicode”驱动程序,此测试第一次成功,但随后更复杂(例如中文)的非 ASCII 字符被问号替换; 我相信 VBA 内部使用 Unicode 但 MySQL does not support UTF16 for clients 并在 ODBC 连接字符串中指定“charset=utf8mb4”或先执行“SET CHARACTER SET utf8mb4”没有帮助,并且不支持“SET NAMES utf8mb4”; 如果我使用 INSERT IGNORE 而不是 INSERT,第一次执行似乎成功,但值实际上在“è”处被截断(因此只插入了“abcd”); MySQL ODBC 5.3.6 也会发生这种情况

我做错了什么还是 MySQL ODBC 驱动程序中的另一个错误?

【问题讨论】:

试试dbParams.Type = adVarWChar 而不是dbParams.Type = adVarChar @GordThompson:真的吗?只有一个字母?!你拯救了我的一天/一周/一个月!我正在尝试各种诸如 character-set-client-handshake=FALSE 之类的东西,因为我认为最初的握手可能失败了。如果您添加您的评论作为答案,我可以选择它作为最佳答案,也许我们可以帮助一些像我一样挣扎了数周的可怜草皮。 #ifeelstupid 但是第二次尝试成功还是很奇怪(我检查了但是dbParams.Type的值没有自动修改)。 我也不确定客户端字符集是否支持 UTF16。我现在在连接字符串中指定了“charset=utf16”,它被接受了,但确实有任何区别。 【参考方案1】:

声明...

dbParams.Type = adVarChar

... 告诉 ADODB.Parameter 对象它的值将是一串单字节字符。这些单字节字符将被传递给 ODBC 驱动程序,而后者又将它们传递给 MySQL 数据库引擎。如果数据库引擎需要 UTF-8 字符,则会发生错误,因为 0xE8(在许多“latin-1”类型的代码页中,如 Windows-1252 中的è)不是有效的 UTF-8 字节序列。

把上面的语句改成...

dbParams.Type = adVarWChar

... 告诉 ADODB.Parameter 对象它的值将是一个多字节(“宽”)字符的字符串。使用 VBA 字符串文字分配值时...

dbParams.Value = "dèf"

... ADODB 会将字符串从其单字节表示(基于当前的 Windows 语言环境)转换为 Unicode,并将其传递给 ODBC 驱动程序。 ODBC 驱动程序能够将原始 Unicode (U+0064 U+00E8 U+0066) 中的字符串“重新打包”为 UTF-8 编码 (0x64 0xC3 0xA8 0x66) 并将其传递给数据库引擎。

【讨论】:

以上是关于在 MS Access (VBA) 中使用 ADODB 将非 ASCII 插入 MySQL 数据库时出现“不正确的字符串值”,但重试有效的主要内容,如果未能解决你的问题,请参考以下文章

奇怪的情况,使用 ADO 在 Excel VBA 中定义连接到 Access .accdb 数据库的文件路径,但是它告诉我找不到 .mdb 文件

Excel VBA 导出到 Access:ADO 错误

如何使用 MS Access 作为 ADO.NET 实体框架的提供者?

MS Access/ADO AddNew 方法不附加记录

如何从 ADO 记录集字段将图片加载到 MS-Access Image 控件中?

MS Access - ADO 记录集,使用 SQL 语句检索数据和建表