问题描述:
问题一直出现的很怪异,通过例子来阐述。
环境:
mysql-5.1.62-win32 + otl + mysql-connector-odbc-5.1.11-win32 + navicat101_mysql_en
建立一张测试表:
CREATE TABLE `t_cntest` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`value` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
t_cntest表只有两个字段,一个是递增的ID号,一个是可以保存中文的value;
当用otl开始往该数据表里面插入值时,问题出现了
1. insert into t_cntest(value) values ('中文');(下文称为%s方式)
用navicat显示正常,但是再通过
select value from t_cntest
读出来,却是乱码;
2. insert into t_cntest(value) values (:f1<char[64]>); (下文称为流方式)
<p><span style="color:gray;">stream<<</span><span style="color:gray;">”</span><span style="color:gray;">中文</span><span style="color:gray;">”</span><span style="color:gray;">;</span></p>
用otl的这中流方式方式写入mysql,再用流方式来读取
select value from t_cntest where value=:f1<char[64]>
读出来中文正常,但是navicat查看却是乱码;
3、网络解决办法
网上十有八九都是:set names utf8云云,但是otl不允许这么做,执行异常;
于是一个一个的来设置吧:
Set character_set_client=’utf8’
Set character_set_connection=’utf8’
Set character_set_results=’utf8’
可能我人品不好,还是NO!
==========================================================================================
一顿摸索测试,后来觉得,应该是odbc在搞鬼,于是在数据源增加指定的数据源,便OK了。
在odbc数据源管理器中,用户DSN里面,添加一个数据源,名字任意,如下图:
在添加过程中,或者添加完再配置,点开“connection”扩展栏,选择字符集gbk。
然后就是要在代码中指定这个配置好的数据源了,这很重要。
可能你会发现,如果不增加DSN,默认是没有这个DSN的,那么OTL用的是哪里的DSN?谁能解释一下。。。。。。?
以前的登陆连接串是这样的:
Driver={MySQL ODBC 5.1 Driver};Server=localhost;DataBase=test_cn;Uid=root;Pwd=123456
现在必须是:
DSN=dsn_test_cn;Driver={MySQL ODBC 5.1 Driver};Server=localhost;DataBase=test_cn;Uid=root;Pwd=123456
对,就是多加了一个DSN=...,名字是你刚刚自己创建的。
享用结果:
这样怎么写,怎么读都OK了!!!
再次,用%s方式或者流方式写入,navicat都显示正常用%s方式或者流方式写入,打印也都正常
走不完的路:
有个疑问,能否在代码中配置这个DSN的字符集呢?否则每次换一台电脑,都必须配置一次数据源,多麻烦。。。
附件:
我的mysql测试字符集环境:
Mysql字符环境:
mysql> show variables like 'char%';
+--------------------------+---------------------------------------------------------+
| Variable_name | Value |
+--------------------------+---------------------------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | gbk |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | gbk |
| character_set_system | utf8 |
| character_sets_dir | C:\Program Files\MySQL\MySQL Server 5.1\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set
mysql> show variables like 'coll%';
+----------------------+-----------------+
| Variable_name | Value |
+----------------------+-----------------+
| collation_connection | utf8_general_ci |
| collation_database | gbk_chinese_ci |
| collation_server | gbk_chinese_ci |
+----------------------+-----------------+
3 rows in set
测试例子程序(主要是main以内的测试代码,头文件和宏定义看自己的otl情况而定):
// Test_Otl.cpp : 定义控制台应用程序的入口点。
//
#define OTL_ODBC_MSSQL_2005 // Compile OTL 4/ODBC, MS SQL 2005
#define OTL_ODBC // Compile OTL 4/ODBC. Uncomment this when used with MS SQL 7.0/ 2000
#define OTL_EXTENDED_EXCEPTION // Enable extended field in otl_exception
#define OTL_ORA11G
#include "stdafx.h"
#include "otlv4.h"
#include <time.h>
#include <iostream>
using namespace std;
#pragma comment(lib , "oci.lib")
int _tmain(int argc, _TCHAR* argv[])
{
//连接mysql
string strConnect;
strConnect += "DSN=";
strConnect += "dsn_test_cn;";
strConnect += "Driver=";
strConnect += "{MySQL ODBC 5.1 Driver}";
strConnect += ";Server=";
strConnect += "localhost";
strConnect += ";DataBase=";
strConnect += "test_cn";
strConnect += ";Uid=";
strConnect += "root";
strConnect += ";Pwd=";
strConnect += "123456";
//DSN=dsn_test_cn;Driver={MySQL ODBC 5.1 Driver};Server=localhost;DataBase=test_cn;Uid=root;Pwd=123456
odbc::otl_connect odbc_con;
try{
int nRet = odbc::otl_connect::otl_initialize(true); // initialize oracle environment
odbc_con.rlogon(strConnect.c_str());
if (!odbc_con.connected)
{
printf("未连接\n");
return -1;
}
long lRet = -1;
#define INSERT 0
#define SELECT 1
char szSql[1024]={0};
odbc::otl_stream stream;
string str1 = "this is 百分号s写入";
string str2 = "this is 流方式写入";
#if INSERT
//插入中文记录 %s方式
sprintf_s(szSql, sizeof(szSql),
"insert into t_cntest(value) values ('%s')",str1.c_str());
stream.open(1,szSql,odbc_con);
stream.close();
//插入中文记录 流方式
sprintf_s(szSql, sizeof(szSql),
"insert into t_cntest(value) values (:f1<char[64]>)");
stream.open(1,szSql,odbc_con);
stream<<str2.c_str();
stream.close();
#endif
#if SELECT
//查询数据
//sprintf_s(szSql, sizeof(szSql), "select value from t_cntest");//查全部
//%s方式读
//sprintf_s(szSql, sizeof(szSql), "select value from t_cntest where value='%s'",str1.c_str());//查str1
//sprintf_s(szSql, sizeof(szSql), "select value from t_cntest where value='%s'",str2.c_str());查str2
//stream.open(1,szSql,odbc_con);
//流方式读
sprintf_s(szSql, sizeof(szSql), "select value from t_cntest where value=:f1<char[64]>");
stream.open(1,szSql,odbc_con);
//stream<<str1.c_str();
stream<<str2.c_str();
//结果展示
char szValue[64]={0};
while (!stream.eof())
{
stream>>szValue;
printf("select value=%s\n",szValue);
}
stream.close();
#endif
//注销登录
odbc_con.commit();
odbc_con.logoff();
}
catch(odbc::otl_exception &e)
{
}
system("pause");
return 0;
}