关于C#(ASP.net)存取MySQL LongText字段的心得
1.LongText字段是MySQL用于存储超长字符串的数据库类型,有点类似MSSQL的memo。
2.Connector/NET读取LongText的内部实现过程:
1) Connector/NET内部将LongText看作字符串,对外以字符串的方式进行读写,不运行调用getBytes的方法。
2) 根据MySQL的配置信息,获得MySQL的字符集,并根据字符集信息生成System.Text.Encode对象
3) 以byte[]的方式从MySQL数据库里将LongText字段信息读取出
4) 使用System.Text.Encode的GetString方法对字符串进行解码,并返回给用户
3.Connector/NET写LongText的内部实现(猜测,没有看过代码)
1) 根据MySQL的配置信息,获得MySQL的字符集,并根据字符集信息生成System.Text.Encode对象
2) System.Text.Encode对象的GetBytes方法对字符串进行编码,转换为byte[]
3) 将byte[]以二进制流的方式写入数据库对应的LongText字段
4.Connector/NET对MySQL数据库默认的字符集
1) MySQL 4.1以前的版本(这里特指MySQL 4.0),如果字符集是latin1(拉丁文),则.net 内部的System.Text.Encode对象为Latin1Encoding(.net内部私有对象)。CodePage=28591(EncodingName = Western European (ISO))
2) MySQL 4.1 的版本,如果字符集是latin1,则内部的System.Text.Encode对象为CodePageEncoding。CodePage=1252(EncodingName = Western European (Windows))
3) 如果是MySQL的字符集定义为GB2312,或者UTF8(MySQL 4.0不支持),.net内部的编码方式则会根据MySQL的字符集确定。
5.Connector/NET读取MySQL的LongText字段时产生乱码的原因
Connector/NET内部将LongText字段看作字符串,而LongText字段在存取得时候,内部是按照byte[]方式进行处理的,因此,在存储LongText字段的时候,需要对传入的LongText支点的字符串(.net字符串,其内部采用unicode方式编码)进行编码,并将得到的byte[]存储到数据库里。相反,读取LongText字段的时候,需要将从数据库里读出的byte[]进行解码,还原为.net字符串。
在这个编码/解码的过程中,需要指定byte[]的编码类型(字符集类型)。字符集类型可以从MySQL获得。MySQL在安装的时候,将字符集默认为latin1。(MSSQL则会在安装的时候检查操作系统的字符集设置,并将字符集设置与当前操作系统一致)因此Connector/NET组件在存取LongText字段的时候,就会将字符串按照latin1字符集的方式进行处理,凡是出现中文的地方,都会因为字符集编码不一致,而用错误的字符串替换。而如果MySQL被其它程序按照当前用户字符集方式编码(中文的GB2312)写入,在MySQL读取的时候,也就会出现解码错误,得到乱码。
总之一句话,因为MySQL的字符集设置错误就会造成Connector/NET存取的时候出现乱码。
6.如何从MySQL 4.0数据库读取LongText信息(非MySQL定义字符集信息)
这里假设原来存储到MySQL数据的时候是按照GB2312方式存储,并且当前系统默认得字符集也是GB2312,MySQL的字符集未修改为latin1。
byte[] buf = new byte[1024 * 10];
// 向按照错误的字符集读取字符串
string s= dr.GetString(0);
// 按照错误的字符集,将字符串还原为byte数组
System.Text.Encoding.GetEncoding(28591).GetBytes(s, 0, s.Length, buf, 0);
// 重新按照正确的字符集生成字符串
s=System.Text.Encoding.Default.GetString(buf);
7.如何种MySQL 4.1数据库读取LongText信息(非MySQL定义字符集信息)
代码和上面的一样,所不同的只是将28591替换为1252
8.如何将字符串写入LongText里(非MySQL定义字符集信息)
首先,如果通过以往的写字符方法写数据库的话,字符串里非英文字符会因为错误的编码(默认的latin1)而丢失(如果MySQL的字符集是GB2312或者UTF8则不会出现该问题),这样无论后面我们如何正确的解码,都不可能得到正确的字符串。所以,如果要写入非英文字符的字符串,就不能走正常的路线,而需要把LongText看作二进制字段,以bit流方式写入。写入方式和blob字段写入方式一样,详细方法参考bruse的文章。
MySql.Data.MySqlClient.MySqlCommand cmm = null;
cmm = new MySql.Data.MySqlClient.MySqlCommand("insert into test(name) values(?name)", connect);
// 以将该字段看作二进制流
MySql.Data.MySqlClient.MySqlParameter param = null;
param = new MySql.Data.MySqlClient.MySqlParameter("?name", System.Data.DbType.Binary);
// 对输入的字符串使用GB2312进行编码
param.Value = System.Text.Encoding.Default.GetBytes("aa中文测试");
cmm.Parameters.Add(param);
cmm.ExecuteNonQuery();
9.以UTF-8、UTF16(Unicode)、BigUnicode的方式将字符串写入LongText里
基本方法同“7.如何将字符串写入LongText”,不同之处在于编码方式由Default改为UTF8、Unicode、BigUnicode。
10.如何兼容MySQL 4.0、4.1的读取方法(读取UTF-16)
读取LongText的关键在于如何将LongText得到的字符串解码为byte数组,并重新编码。而Connector/NET控件在两个MySQL版本之间,对默认的编码采用了两种不同的编码/解码方式,从而导致乱码,解决的方案有:
1) 修改Connector/NET控件,提供一个获得当前Connector/NET控件(MySQL)的字符集的方法。
2) 修改Connector/NET控件,对MySQL所有版本的默认字符集都采用统一的解码方式,即如果字符集为latin1将统一采用CodePage=28591或者CodePage=1252的方式进行解码。(缺点:如果MySQL的字符集改变,则读取代码在创建System.Text.Encode对象也需要改变)
3) 修改应用程序,针对2个不同版本的MySQL数据库采用2套解决方案(缺点同2。而且需要修改的地方更多)。
4) 在MySQL连接字符串里确定字符集(在连接字符串里添加charset=gb2312),并修改程序,按照gb2312的方式还原编码(推荐使用)。
p.s.
1.Connector/NET是一个.net访问MySQL的组件,本文使用的版本是1.0.0.7,MySQL使用的版本是4.0 和 4.1。.net版本1.1
2.本文针对LongText采用如此特殊的字符集编码转换过程,是因为其它应用往MySQL数据库里写数据的时候是按照UTF-16(Unicode或BigUnicode)进行编码的,MySQL4.0和4.1都不直接支持UTF-16的字符集。
3.如果只有一个应用访问MySQL数据库,可直接将MySQL的字符集改为GB2312或者UTF-8,不需按照本文这种婉转的编码方式进行字符集转换。