视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
深入理解mysqlSETNAMES和mysql(i)_set_charset的区别_MySQL
2020-11-09 19:00:24 责编:小采
文档


bitsCN.com 说到, 尽量使用mysqli_set_charset(mysqli:set_charset)而不是”SET NAMES”, 当然, 这个内容在PHP手册中也有叙及, 但是却没有解释为什么.
  最近有好几个朋友问我这个问题, 到底为什么?
  问的人多了, 我也就觉得可以写篇blog, 专门介绍下这部分的内容了.
  首先, 很多人都不知道”SET NAMES”到底是做了什么,
  我之前的文章深入MySQL字符集设置中, 曾经介绍过character_set_client/character_set_connection/character_set_results这三个MySQL的”环境变量”, 这里再简单介绍下,
  这三个变量, 分别告诉MySQL服务器, 客户端的编码集, 在传输给MySQL服务器的时候的编码集, 以及期望MySQL返回的结果的编码集.
  比如, 通过使用”SET NAMES utf8″, 就告诉服务器, 我用的是utf-8编码, 我希望你也给我返回utf-8编码的查询结果.
  一般情况下, 使用”SET NAMES”就足够了, 也是可以保证正确的. 那么为什么手册又要说推荐使用mysqli_set_charset(PHP>=5.0.5)呢?
  首先, 我们看看mysqli_set_charset到底做了什么(注意星号注释处, mysql_set_charset类似):

  //php-5.2.11-SRC/ext/mysqli/mysqli_nonapi.c line 342
  PHP_FUNCTION(mysqli_set_charset)
  {
  MY_MYSQL *mysql;
  zval *mysql_link;
  char *cs_name = NULL;
  unsigned int len;
  if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis()
  , "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &len) == FAILURE) {
  return;
  }
  MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &mysql_link, "mysqli_link"
  , MYSQLI_STATUS_VALID);
  if (mysql_set_character_set(mysql->mysql, cs_name)) {
  //** 调用libmysql的对应函数
  RETURN_FALSE;
  }
  RETURN_TRUE;
  }

  那mysql_set_character_set又做了什么呢?

  //mysql-5.1.30-SRC/libmysql/client.c, line 3166:
  int STDCALL mysql_set_character_set(MYSQL *mysql, const char *cs_name)
  {
  struct charset_info_st *cs;
  const char *save_csdir= charsets_dir;
  if (mysql->options.charset_dir)
  charsets_dir= mysql->options.charset_dir;
  if (strlen(cs_name) < MY_CS_NAME_SIZE &&
  (cs= get_charset_by_csname(cs_name, MY_CS_PRIMARY, MYF(0))))
  {
  char buff[MY_CS_NAME_SIZE + 10];
  charsets_dir= save_csdir;
  /* Skip execution of "SET NAMES" for pre-4.1 servers */
  if (mysql_get_server_version(mysql) < 40100)
  return 0;
  sprintf(buff, "SET NAMES %s", cs_name);
  if (!mysql_real_query(mysql, buff, strlen(buff)))
  {
  mysql->charset= cs;
  }
  }
  //以下省略

  我们可以看到, mysqli_set_charset除了做了”SET NAMES”以外, 还多做了一步:

  sprintf(buff, "SET NAMES %s", cs_name);
  if (!mysql_real_query(mysql, buff, strlen(buff)))
  {
  mysql->charset= cs;
  }

  而对于mysql这个核心结构的成员charset又有什么作用呢?
  这就要说说mysql_real_escape_string()了, 这个函数和mysql_escape_string的区别就是, 它会考虑”当前”字符集. 那么这个当前字符集从哪里来呢?
  对了, 你猜的没错, 就是mysql->charset.
  mysql_real_string在判断宽字符集的字符的时候, 就根据这个成员变量来分别采用不同的策略, 比如如果是utf-8, 那么就会采用libmysql/ctype-utf8.c.
  看个实例, 默认mysql连接字符集是latin-1, (经典的5c问题):

    $db = mysql_connect('localhost:3737', 'root' ,'123456');
  mysql_select_db("test");
  $a = "/x91/x5c";//"

下载本文
显示全文
专题