zoukankan      html  css  js  c++  java
  • 可遇不可求的Question之MySqlClient的Guid 类型的映射篇

    关于 Guid 类型的映射

    MySql 没有原生的 Guid 类型,一般使用 binary(16) 或者 char(36) 这两个类型。早期版本的 Connector/Net 将 binary(16) 自动映射成为 Guid 类型。从 Connector/Net 6.1.1 开始,binary(16) 不再被自动映射成为 Guid 类型,而选用 char(36)。通过连接字符串的 Old Guids = true 选项可使用旧的 binary(16) 映射,这个选项的缺省值是 false,即使用 char(36)。参考 21.2.6. Connector/NET Connection String Options Reference

    string connectionString = "server=localhost;user id=user;password=pwd;database=db;character set=utf8;Old Guids=true";

    遗憾的是,在最新的发布版本 Connector/Net 6.2.3 中,缺少像 Treat Tiny As Boolean=false 这样的开关,无法关闭从 char(36) 到 Old Guid 的自动映射。因此,当你的数据库中恰巧使用了 char(36) 这个类型且这个字段存了不是合法 Guid 格式的字符值(中间用短横线隔开的 32 个数字 ,即 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),那么你的程序就会报错。空字符是一个常见的情况,我们最近的一个系统就是被这个害惨了。虽然,我们明确这个 char(36) 类型字段是存应用程序生成的 Guid,而且加了 NOT NULL 约束,但在其他应用程序(PHP实现)中由于种种不可修复的原因,偶尔会向这个字段入了空字符,导致现有应用程序(.NET实现)读取失败。更要命的是,这个错误是在 MySqlDataReader.Read() 方法发生的,异常堆栈如下:

    System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xx
    xx-xxxx-xxxx-xxxxxxxxxxxx).
       at System.Guid..ctor(String g)
       at MySql.Data.Types.MySqlGuid.MySql.Data.Types.IMySqlValue.ReadValue(MySqlPac
    ket packet, Int64 length, Boolean nullVal) in E:MySQLmysql-connector-net-6.2.3
    -srcMySql.DataProviderSourceTypesMySqlGuid.cs:line 234
       at MySql.Data.MySqlClient.NativeDriver.ReadColumnValue(Int32 index, MySqlFiel
    d field, IMySqlValue valObject) in E:MySQLmysql-connector-net-6.2.3-srcMySql.
    DataProviderSourceNativeDriver.cs:line 648
       at MySql.Data.MySqlClient.Driver.ReadColumnValue(Int32 index, MySqlField fiel
    d, IMySqlValue value) in E:MySQLmysql-connector-net-6.2.3-srcMySql.DataProvi
    derSourceDriver.cs:line 415
       at MySql.Data.MySqlClient.ResultSet.ReadColumnData(Boolean outputParms) in E:
    MySQLmysql-connector-net-6.2.3-srcMySql.DataProviderSourceResultSet.cs:lin
    e 272
       at MySql.Data.MySqlClient.ResultSet.NextRow(CommandBehavior behavior) in E:M
    ySQLmysql-connector-net-6.2.3-srcMySql.DataProviderSourceResultSet.cs:line
    210
       at MySql.Data.MySqlClient.MySqlDataReader.Read() in E:MySQLmysql-connector-
    net-6.2.3-srcMySql.DataProviderSourcedatareader.cs:line 875
       at LeoLab.MySql.GuidChar36Test.Program.Main(String[] args) in E:LeoLab.MySql
    LeoLab.MySql.GuidChar36TestLeoLab.MySql.GuidChar36TestProgram.cs:line 30

    这个错误信息中没有包含是哪一列哪一行发生了错误,因此,当你的 SELECT 语言包含很多字段,结果集又比较大的时候,就晕菜了,不知道这个 char(36) 与 Guid 映射关系的就被搞得莫名其妙的了。

    目前最快速的解决方法,是“曲线救国”:通过设置 Old Guids=true 启用 binary(16) 到 guid 的映射来间接禁用 char(36) 到 Guid 的映射。

    此外,我修改了 Connector/Net 6.2.3 的源码,增加了一个类似 Treat Tiny As Boolean 的 Treat Char As Guid 选项类禁用 char(36) 到 Guid 的映射。大概修改如下:

    1. MySqlConnectionStringBuilder 中增加属性 TreatCharAsGuid

    01.[Category("Advanced")] 
    02.[DisplayName("Treat Char As Guid")] 
    03.[Description("Should the provider treat CHAR(36) columns as Guid.")] 
    04.[DefaultValue(true)] 
    05.[ValidKeywords("Treat Char As Guid")] 
    06.[RefreshProperties(RefreshProperties.All)] 
    07.public bool TreatCharAsGuid 
    08.
    09.    get { return (bool)values["Treat Char As Guid"]; } 
    10.    set { SetValue("Treat Char As Guid", value); } 
    11.}

    2. MySqlField 类的 SetTypeAndFlags 方法中的判断 if (Type == MySqlDbType.String && CharacterLength == 36 && !driver.Settings.OldGuids) 中增加TreatCharAsGuid的判断

    1.if (driver.Settings.TreatCharAsGuid && Type == MySqlDbType.String && CharacterLength == 36 && !driver.Settings.OldGuids) 
    2.            
    3.                mySqlDbType = MySqlDbType.Guid; 
    4.            }

    这样我们在连接字符串中指定 Treat Char As Guid=false,char(36) 就不会被映射成为 Guid 了,而是普通 String 。

    源码下载 MySqlConnectorNet6.2.3-TreatCharAsGuid.zip (308.80 kb)

  • 相关阅读:
    flink on yarn部分源码解析 (FLIP-6 new mode)
    flink on yarn部分源码解析
    flink window的early计算
    【flink training】 打车热点区域实时统计PopularPlaces
    troubshooting-sqoop 导出 TiDB表数据报com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
    Hive2.0常用函数(对编辑器很无语😓)
    Hive正则表达式
    troubleshooting-Container 'PHYSICAL' memory limit
    Hive-查询结果导入到 MySQL
    Hive-复制表
  • 原文地址:https://www.cnblogs.com/tigerjacky/p/1901853.html
Copyright © 2011-2022 走看看