以前测试的时候都没用汉字,今天客户端要显示昵称了才发现出现的是两个 ??,郁闷了。后来查了一下发现时服务器查询数据库的时候就出现问题,没有得到正确的结果,在网上找了一下,发现这样的一篇文章:

       mysql_set_character_set(myData,"gb2312");   //这个是用在linux 下的,
VC6.0下用这个: ret = mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gb2312");//来保证你字码, 要加重记住.没这个设置写到数据mysql里就是乱码了, 汉字就是乱码
源地址: http://hi.baidu.com/cuily/blog/item/e38f3ddd397d6f315982dd88.html


vc6.0连接mysql
2008年06月22日 星期日 05:06 P.M.
       周末,闲着的时候突然想起来所谓的数据库编程, 但是具体怎么操作确实全然不知。教学上用postresql,公司里估计是没有用处的吧,所以,就拿mysql来做试验了,哈哈
       其实,刚开始还是蛮难的,感觉。看网上的例子,就像丈二和尚-----摸不着头脑,突然有种回到了刚开始学习C语言那时候的感觉,什么都不懂,一个简单的编译错误也不想认真看,自己去想,就想找个人问,这个到底是怎么错了?呵呵,所幸,那会没有浮躁。
     mysql本身带了很多C API,所以操作起来很方便,直接调用API就好了,不过加入相应的库在刚开始就够难为人了,毕竟,这个是我第一次加入外来库。。
vc6.0添加mysql #include 头文件: 工程->设置->C/C++ Y分类那里选择Preprocessor,然后在附加包含路径里写上:C:\Program Files\MySQL\MySQL Server 5.0\include
就OK 了
在编写程序时添加进去相应的lib库,使用:#pragma comment(lib, "libmysql.lib")
.lib 对应的.dll也要拷贝到工程目录下。

完整的例子如下:
#include <iostream>
#include <windows.h>
#include <cstdlib>
#include <cstdio>
#include <mysql.h>
#pragma comment(lib, "libmysql.lib")
using namespace std;
MYSQL * conn;
int main()
{
char     host[] = "localhost";
char username[] = "root";
char password[] = "123";
     char database[] = "school";
MYSQL_RES * res_set;
MYSQL_ROW row;
unsigned int i, ret;
MYSQL_FIELD * field;
unsigned int num_fields;
//mysql_init(MYSQL *)
// return values: An initialized MYSQL* handle.
//NULL if there was insufficient memory to allocate a new object.    
conn = mysql_init(NULL);
if(conn != NULL)
   ;//cout << "mysql_init success!" << endl;
else printf("failed !\n");
ret = mysql_options(conn, MYSQL_SET_CHARSET_NAME, "gb2312");//来保证你字码, 要加重记住.没这个设置写到数据mysql里就是乱码了, 汉字就是乱码
     if(ret == 0)
   ;//cout << "mysql_options success!" << endl;
else printf("failed !\n");
if(mysql_real_connect(conn,
       host,
       username,
       password,
       database,
       0, NULL, 0) != NULL)
         ;//cout << "mysql_real_connect success!" << endl;
else printf("failed !\n");
//printf("char set %s\n", mysql_character_set_name(conn));
mysql_query(conn, "insert into teacher values(7, 'fifth', '插入汉字', '1986-6-6')"); //这到数据里就不是乱码了.
printf("insert affect %d sentences\n", mysql_affected_rows(conn));
if(mysql_query(conn,"SELECT * FROM teacher")) //查询成功返回0     failed here!
   printf("mysql_query failed!\n");
res_set = mysql_store_result(conn);           //失败返回NULL
if(res_set == NULL)
   printf("res_set is null\n");
/*
while((field = mysql_fetch_field(res_set)))
{
   printf("field name %s\n", field->name);
}
*/
num_fields = mysql_num_fields(res_set);
for(i = 0; i < num_fields; i++)
{
   field = mysql_fetch_field_direct(res_set, i);
   printf("%s\t\t", field->name);
}
printf("\n");
while ((row = mysql_fetch_row(res_set)) != NULL)
{
   for (i = 0; i < mysql_num_fields(res_set); i ++)
   {
     printf("%s\t\t",row[ i ] != NULL ? row[ i ] : "NULL");
   }
   printf("\n");
}
mysql_close(conn);
return 0;
}
函数我就不详细注释了,在mysql的帮助文档里有详细的注释。【原帖:http://www.cnitblog.com/guopingleee/archive/2009/02/13/54526.html
      
           看了它的方法,重点还是在mysql_options这个C API的身上。因为我创建数据库的时候选择的就是gb2312,因此这方面倒是没什么问题。只不过我数据库模块都是用mysql++做的,当时就在想是否 需要用C来重写注册服务器和游戏服务器的数据库模块,但是想着那工作量就不爽,所以只好到mysql++去找寻解决方案,由于mysql++本身的文档做 的很不好,因此要找资料实在是非常痛苦的一件事情,因此这时候只好看Mysql++的源码。最初的目的是想自己去改Mysql++的源码来提供这种支持, 后来在mysql++的源码中有了新的发现。
         首先第一步当然是查看mysqlpp::Connection的源码,在这个类的一个方法bool set_option(Option* o);吸引了我,对这个Option使用查看定义跳到了options.h中。然后在这个文件中查看到了下面这段代码:
  


class MYSQLPP_EXPORT Option
{
public:
/// \brief Types of option setting errors we can diagnose
enum Error {
   err_NONE,   ///< option was set successfully
   err_api_limit, ///< option not supported by underlying C API
   err_api_reject, ///< underlying C API returned error when setting option
   err_connected ///< can't set the given option while connected
};

virtual ~Option() { }     ///< Destroy object
virtual Error set(DBDriver* dbd) = 0; ///< Apply option
};

/// \brief Define abstract interface for all *Options that take a
/// lone scalar as an argument.
template <typename T>
class MYSQLPP_EXPORT DataOption : public Option
{
public:
typedef T ArgType;       ///< Alias for template param
protected:
DataOption(const T& arg) : arg_(arg) { }///< Construct object
T arg_;         ///< The argument value
};
typedef DataOption<unsigned> IntegerOption;   ///< Option w/ int argument
typedef DataOption<bool> BooleanOption;   ///< Option w/ bool argument
typedef DataOption<std::string> StringOption; ///< Option w/ string argument
         因此我断定如果有这样的字符集选择支持的Option类的话一定是StringOption的派生类,因此我在这个文件中搜索StringOption,没过几下就搜索到了这个东西:
class MYSQLPP_EXPORT SetCharsetDirOption : public StringOption
{
#if !defined(DOXYGEN_IGNORE)
public:
SetCharsetDirOption(ArgType arg) : StringOption(arg) { }
private:
Error set(DBDriver* dbd);
#endif
};
         当时我欣喜若狂,哈哈。。。模仿上面的文章用Mysql++写了一个:
#include <mysql++.h>
#include <iostream>
using namespace std;
using namespace mysqlpp;
#pragma comment( lib, "mysqlpp_d.lib")
int main()
{
mysqlpp::Connection con;
   if( !con.set_option( new SetCharsetNameOption( "gb2312") ) )  // 这里是在multiquery那个例子里面发现的用法!
   {
   cout<< " error !"<<endl;
   return -1;
   }
if( !con.connect( "school", "localhost", "root", "123456" ) )
{
   cout<<"连接失败!"<< endl;
   return -1;
}
try
{
   Query query = con.query( "select * from teacher" );
  
   mysqlpp::StoreQueryResult res = query.store();
   if( res && res.size() > 0 )
   {
   cout<< res[0]["name"] << endl;
   cout<< res[0]["gratuation"]<< endl;
   }
}
catch( mysqlpp::BadQuery& e )
{
   cout<< e.what() << endl;
}

return 0;
}

输出:
fifth
插入汉字
请按任意键继续. . .

         正常了,接下来就只需要去修改一下原来模块中的初始化代码即可修正不能支持汉字的缺陷:
bool DBGameDataBase::Initialize()
{
   if( !m_ini.Initialize() )
   {
   GDBLogInfo( "初始化数据库配置文件失败" );
   return false;
   }
   m_strHost = m_ini.GetValue( "Host", "database" );
   m_strDatabaseName = m_ini.GetValue( "DataBaseName", "database" );
   m_strUserName = m_ini.GetValue( "UserName", "database" );
   m_strPassword = m_ini.GetValue( "Password", "database" );
  // 董波 2009.6.2 添加 FOR 汉字支持
   if( !m_connection.set_option( new mysqlpp::SetCharsetNameOption( "gb2312") ) )
   {
   GDBLogInfo( "设置数据库字符集失败!" );
   return false;
   }

   if( !m_connection.connect(
   m_strDatabaseName.c_str(),
   m_strHost.c_str(),
   m_strUserName.c_str(),
   m_strPassword.c_str() ) )
   {
   GDBLogInfo( "连接数据库失败" );
   return false;
   }
  
   return true;
}
           另外一个收获是在检查服务器的时候发现的,也是由于一个小小的疏忽造成的,其结果就是每个客户端在需要数据更新的时候都只能更新自己的部分,然而实际上游戏服务器以及数据库的数据都已经被修改过了,下面是有人出完牌之后的胜利处理函数:

bool DBTable::OnWin( int iSeat )
{
   // 是春天吗?
   if( m_bSpring )
   {
   m_uRate *=2;
   }
   // 是反春吗?
   if( m_uLairdBringOutCount == 1 )
   {
   m_uRate *=2;
   }
   // 保存游戏信息到数据库哦
   if( this->m_iLairdPos == iSeat )
   {
   // 地主赢了,那么就应该扣大家的分
   for( size_t i=0; i<m_ayPlayers.size(); ++i )
   {
     if( i == iSeat )
     {
     m_ayPlayers[ i ]->OnWin( true, m_uRate );
     }
     else
     {
     m_ayPlayers[ i ]->OnFailure( false, m_uRate );
     }
     // 保存到数据库
     m_pDataBase->SavePlayerInfo( &(m_ayPlayers[ i ]->GetPlayerInfo() ) );
   }  
   }
   else
   {
   // 赢家不是地主
   for( size_t i=0; i<m_ayPlayers.size(); ++i )
   {
     if( i==iSeat )
     {
     m_ayPlayers[ i ]->OnWin( false, m_uRate );
     }
     else
     {
     if( i==m_iLairdPos )
     {
       m_ayPlayers[ i ]->OnFailure( true, m_uRate );
     }
     else
     {
       m_ayPlayers[ i ]->OnWin( false, m_uRate );
     }
     }
     // 保存到数据库
     m_pDataBase->SavePlayerInfo( &(m_ayPlayers[ i ]->GetPlayerInfo() ) );
   }  
   }
   // 发送结果出去撒
   DBMAKEMSG( DBMSG_SCDDZ_GAMEOVER, DBID_SCDDZ_GAMEOVER, msg );
   msg.iCompleteSeat = iSeat;
   if( !this->BroadCast( (PDBMSG_HEADER)&msg ) )
   {
   return false;
   }  
   // 再把每个人的个人信息发送下去以更新客户端
   for( size_t i=0; i<m_ayPlayers.size(); ++i )
   {
   if( m_ayPlayers[ i ] )
   {
     DBMAKEMSG( DBMSG_SCDDZ_PLAYERINFO, DBID_SCDDZ_PLAYERINFO, msgOfPI );
     CopyPIToMsg( m_ayPlayers[ i ]->GetPlayerInfo(), &msgOfPI );
     msgOfPI.iSeat = i;
     // m_ayPlayers[ i ]->SendMsg( (PDBMSG_HEADER)&msgOfPI );
    this->BroadCast( (PDBMSG_HEADER)&msgOfPI );
   }
   }
   this->ResetGameState();
   return true;
}


posted on 2011-02-22 17:03  kangwang1988  阅读(1737)  评论(0编辑  收藏  举报