<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>闫鹏 blog &#187; mysql</title>
	<atom:link href="http://www.mirecle.com/tag/mysql/feed" rel="self" type="application/rss+xml" />
	<link>http://www.mirecle.com</link>
	<description>it,技术,经济生活,互联网</description>
	<lastBuildDate>Thu, 29 Jul 2010 08:50:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>php中set names与mysql_set_charset</title>
		<link>http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html</link>
		<comments>http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html#comments</comments>
		<pubDate>Tue, 13 Apr 2010 03:18:52 +0000</pubDate>
		<dc:creator>闫鹏</dc:creator>
				<category><![CDATA[程序员]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.mirecle.com/?p=96072</guid>
		<description><![CDATA[今天看到大家在讨论，发现这是个很严重而又容易疏忽的问题，我以前也一直是用set names，遂记录下来，也提醒自己一把。 1.set names与mysql_set_charset有什么区别？ 一般情况下, 使用”SET NAMES”就足够了, 也是可以保证正确的. 那么为什么手册又要说推荐使用 mysqli_set_charset(PHP&#62;=5.0.5)呢。手册里面也没有明确说明。我们可以看下php扩展的源代码： //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", &#38;mysql_link, mysqli_link_class_entry, &#38;cs_name, &#38;len) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &#38;mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); if (mysql_set_character_set(mysql-&#62;mysql, cs_name)) { //** 调用libmysql的对应函数 RETURN_FALSE; } RETURN_TRUE; } 可以看到php的mysql扩展是直接调用了mysql的mysql_set_character_set函数，接下来看看mysql的代码 //mysql-5.1.30-SRC/libmysql/client.c, line [...]


您可能会喜欢:<ol><li><a href='http://www.mirecle.com/2010/01/18/php-reflection-effect-the-base-class-to-access-sub-categories-of-data.html' rel='bookmark' title='Permanent Link: php反射效果:基类访问子类数据'>php反射效果:基类访问子类数据</a></li>
<li><a href='http://www.mirecle.com/2010/05/17/php-and-repair-defects-in-the-getopt.html' rel='bookmark' title='Permanent Link: php中getopt的缺陷及修复'>php中getopt的缺陷及修复</a></li>
<li><a href='http://www.mirecle.com/2010/05/07/php-in-the-ampersand-on-the-abuse-of.html' rel='bookmark' title='Permanent Link: php中&#038;符号的滥用与它引发的bug'>php中&#038;符号的滥用与它引发的bug</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<!--adv-->
<img src="http://emoneycreater.appspot.com/jd.jpg" width="0" height="0"/>
<img src="http://emoneycreater.appspot.com/sn.jpg" width="0" height="0"/>
<img src="http://emoneycreater.appspot.com/img01.tianya.cn.dehm.jpg" width="0" height="0"/>
<!--adv end-->
<p>今天看到大家在讨论，发现这是个很严重而又容易疏忽的问题，我以前也一直是用set names，遂记录下来，也提醒自己一把。</p>
<p>1.set names与mysql_set_charset有什么区别？</p>
<p>一般情况下, 使用”SET NAMES”就足够了, 也是可以保证正确的. 那么为什么手册又要说推荐使用 mysqli_set_charset(PHP&gt;=5.0.5)呢。手册里面也没有明确说明。我们可以看下php扩展的源代码：</p>
<pre class="brush:php">
//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", &amp;mysql_link, mysqli_link_class_entry, &amp;cs_name, &amp;len) == FAILURE) {
        return;
    }
    MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &amp;mysql_link, "mysqli_link", MYSQLI_STATUS_VALID);
    if (mysql_set_character_set(mysql-&gt;mysql, cs_name)) {
                //** 调用libmysql的对应函数
        RETURN_FALSE;
    }
    RETURN_TRUE;
}
</pre>
<p>可以看到php的mysql扩展是直接调用了mysql的mysql_set_character_set函数，接下来看看mysql的代码</p>
<pre class="brush:c">//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-&gt;options.charset_dir)
    charsets_dir= mysql-&gt;options.charset_dir;
  if (strlen(cs_name) &lt; MY_CS_NAME_SIZE &amp;&amp;
     (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) &lt; 40100)       return 0;     sprintf(buff, "SET NAMES %s", cs_name);     if (!mysql_real_query(mysql, buff, strlen(buff)))     {       mysql-&gt;charset= cs;
    }
  }
  //以下省略
</pre>
<p>可以看到，除了调用real_query设置set names，还设置了mysql的charset变量。</p>
<p>2.这样有什么影响？</p>
<p>mysql_real_escape_string会受到影响，它与mysql_escape_string的区别就 是,  它会考虑”当前”字符集。如果仅仅使用set names，mysql_real_escape_string可能会失效。</p>
<p>例子：</p>
<pre class="brush:php">$mysqli = new mysqli("localhost", "user", "pass", "test", 3306);

/* check connection */
if (mysqli_connect_errno()) {
    printf("Connect failed: %s\n", mysqli_connect_error());
    exit();
}

$mysqli-&gt;query('SET NAMES gbk'); //使用set names设置字符集
$city = chr(0xbf).chr(0x5c); //0xbf5c是个有效的gbk字符，模拟用户输入
$city = $mysqli-&gt;real_escape_string ($city);//使用real_escape进行过滤

/* this query will fail, cause we didn't escape $city */
 if (!$mysqli-&gt;query("INSERT into myCity(name) VALUES ('$city')")) {
    print "INSERT into myCity (name) VALUES ('$city')\n";
    printf("Error: %s\n", $mysqli-&gt;error);
}

var_dump($city);

var_dump($mysqli-&gt;client_encoding());

$mysqli-&gt;close();
</pre>
<p>3.解决方案</p>
<p>mysqli_set_charset函数对PHP和Mysql有版本要求，必须当mysql版本大于5，PHP版本大于5.0.5时，此函数才有效。至于另一个mysql_set_charset函数，则更要求PHP版本大于5.2.3时才能有效。对于mysql4.1以上版本，使用&#8221;SET character_set_client=binary;&#8221;<br />
推荐使用mysql_set_charset设置字符集的方案，只有在环境不允许的情况下，我们才推荐使用第二种binary编码的方案。但是无论在什么情况下，都禁止使用”SET NAMES”来作为设置字符集的操作。</p>
本文永久链接:<a href="http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html">http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html</a>
<br/>
[<a href="http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html#respond">发表评论</a>]

<p>您可能会喜欢:<ol><li><a href='http://www.mirecle.com/2010/01/18/php-reflection-effect-the-base-class-to-access-sub-categories-of-data.html' rel='bookmark' title='Permanent Link: php反射效果:基类访问子类数据'>php反射效果:基类访问子类数据</a></li>
<li><a href='http://www.mirecle.com/2010/05/17/php-and-repair-defects-in-the-getopt.html' rel='bookmark' title='Permanent Link: php中getopt的缺陷及修复'>php中getopt的缺陷及修复</a></li>
<li><a href='http://www.mirecle.com/2010/05/07/php-in-the-ampersand-on-the-abuse-of.html' rel='bookmark' title='Permanent Link: php中&#038;符号的滥用与它引发的bug'>php中&#038;符号的滥用与它引发的bug</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.mirecle.com/2010/04/13/php-in-the-set-names-and-mysql_set_charset.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mysql学习笔记-1</title>
		<link>http://www.mirecle.com/2009/10/13/mysql-study-notes-1.html</link>
		<comments>http://www.mirecle.com/2009/10/13/mysql-study-notes-1.html#comments</comments>
		<pubDate>Tue, 13 Oct 2009 08:02:53 +0000</pubDate>
		<dc:creator>闫鹏</dc:creator>
				<category><![CDATA[程序员]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">/2009/10/13/29157.html</guid>
		<description><![CDATA[mysql最不同也是最重要的特性，就是它的存储引擎架构。如图，存储引擎只处理mysql server发送的请求，不处理sql语句的解析与缓存等内容。但innodb是一个例外，因为innodb有外键定义，而mysql server目前还没有实现相关内容。 在mysql内部，每个连接都有一个线程来处理这个连接上面的请求（所以事务是不能跨越在两个连接上的，一个连接在同一时间也只能启动一个事务）。 在sql语句的parser，将sql解析成树状结构，这里可能会重写sql决定使用哪个索引等。在query cache存储sql语句与result，如果命中，就不再到存储引擎进行查询了。Query cache只存储select语句。 mysql server本身使用表级锁，如ALTER TABLE使用的就是mysql server提供的。行级锁是在存储引擎实现的，各存储引擎都有自己实现行级锁的方式，mysql server对此不需要了解。 大多数存储引擎的隔离级别是read committed，但Mysql的默认隔离级别却是repeatable read。innodb是通过多版本的方式解决repeatable read带来的幻读问题的。附： l read uncommited即脏读，一个事务修改了一行，另一个事务也可以读到该行。如果第一个事务执行了回滚，那么第二个事务读取的就是从来没有正式出现过的值。 l read commited即一致读，试图通过只读取提交的值的方式来解决脏读的问题，但是这又引起了不可重复读取的问题。一个事务执行一个查询，读取了大量的数据行。在它结束读取之前，另一个事务可能完成了对数据行的更改。当第一个事务试图再次执行同一个查询，服务器就会返回不同的结果。 l repeatable read即可重复读，在一个事务对数据行执行读取或写入操作时锁定了这些数据行。但是这种方式又引发了幻想读的问题。因为只能锁定读取或写入的行，不能阻止另一个事务插入数据，后期执行同样的查询会产生更多的结果。 l sieralizable完全串行，用的太少，就不写了。 默认情况下，mysql开启autocommit，只有调用start transaction，它一直认为每个sql都是一个单独的事务。如果关闭了autocommit，除非你调用了commit或者rollback，你会一直在一个事务里面。当调用commit或者rollback后，它会自动的帮你在启动一个事务。 因为存储引擎自己实现事务，所以一个事务无法跨越多重存储引擎类型的表。 在一个事务中任何时候都可以获取锁，但只有事务结束时才会释放锁。lock in share mode是允许其他session读但不能写，读取的数据行如果被其他事物锁着，就会等待直到那个事务提交。for update则是排他锁，不允许读或者写。 Innodb实现Mutiversion concurrency control（MVCC），通过为每行数据记录两个隐藏的值，这两个值分别为数据创建点与过期点（binlog中的那些版本号）。增删查的处理就不用多说了，改的时候，innodb通过增加一个数据行的拷贝来完成，拷贝的创建号与原数据行的删除号就是当前系统号。 遗留问题： 在repeatable read下，innodb是怎么处理这个lock in share mode的呢？ 本文永久链接:http://www.mirecle.com/2009/10/13/mysql-study-notes-1.html [发表评论] 您可能会喜欢:Digg创始人：1个用户变成100万的9种办法 关于数钱费 增加head请求处理，避免micolog出现405错误


您可能会喜欢:<ol><li><a href='http://www.mirecle.com/2009/10/16/digg-founder-a-user-into-one-million-of-the-9-kinds-of-ways.html' rel='bookmark' title='Permanent Link: Digg创始人：1个用户变成100万的9种办法'>Digg创始人：1个用户变成100万的9种办法</a></li>
<li><a href='http://www.mirecle.com/2010/06/01/the-number-of-charges-on-the-money.html' rel='bookmark' title='Permanent Link: 关于数钱费'>关于数钱费</a></li>
<li><a href='http://www.mirecle.com/2009/09/09/increase-the-head-request-processing-to-avoid-the-405-error-occurs-micolog.html' rel='bookmark' title='Permanent Link: 增加head请求处理，避免micolog出现405错误'>增加head请求处理，避免micolog出现405错误</a></li>
</ol>]]></description>
			<content:encoded><![CDATA[<!--adv-->
<img src="http://emoneycreater.appspot.com/jd.jpg" width="0" height="0"/>
<img src="http://emoneycreater.appspot.com/sn.jpg" width="0" height="0"/>
<img src="http://emoneycreater.appspot.com/img01.tianya.cn.dehm.jpg" width="0" height="0"/>
<!--adv end-->
<p><a href="http://yanpblog.appspot.com/media/agh5YW5wYmxvZ3INCxIFTWVkaWEY6esBDA"><img style="display: inline; border: 0px;" title="clip_image001" src="../media/agh5YW5wYmxvZ3INCxIFTWVkaWEY4-MBDA" border="0" alt="clip_image001" width="295" height="407" /></a></p>
<p>mysql最不同也是最重要的特性，就是它的存储引擎架构。如图，存储引擎只处理mysql server发送的请求，不处理sql语句的解析与缓存等内容。但innodb是一个例外，因为innodb有外键定义，而mysql server目前还没有实现相关内容。</p>
<p>在mysql内部，每个连接都有一个线程来处理这个连接上面的请求（所以事务是不能跨越在两个连接上的，一个连接在同一时间也只能启动一个事务）。</p>
<p>在sql语句的parser，将sql解析成树状结构，这里可能会重写sql决定使用哪个索引等。在query cache存储sql语句与result，如果命中，就不再到存储引擎进行查询了。Query cache只存储select语句。</p>
<p>mysql server本身使用表级锁，如ALTER TABLE使用的就是mysql server提供的。行级锁是在存储引擎实现的，各存储引擎都有自己实现行级锁的方式，mysql server对此不需要了解。</p>
<p>大多数存储引擎的隔离级别是read committed，但Mysql的默认隔离级别却是repeatable read。innodb是通过多版本的方式解决repeatable read带来的幻读问题的。附：</p>
<blockquote>
<p>l read uncommited即脏读，一个事务修改了一行，另一个事务也可以读到该行。如果第一个事务执行了回滚，那么第二个事务读取的就是从来没有正式出现过的值。</p>
<p>l read commited即一致读，试图通过只读取提交的值的方式来解决脏读的问题，但是这又引起了不可重复读取的问题。一个事务执行一个查询，读取了大量的数据行。在它结束读取之前，另一个事务可能完成了对数据行的更改。当第一个事务试图再次执行同一个查询，服务器就会返回不同的结果。</p>
<p>l repeatable read即可重复读，在一个事务对数据行执行读取或写入操作时锁定了这些数据行。但是这种方式又引发了幻想读的问题。因为只能锁定读取或写入的行，不能阻止另一个事务插入数据，后期执行同样的查询会产生更多的结果。</p>
<p>l sieralizable完全串行，用的太少，就不写了。</p>
</blockquote>
<p>默认情况下，mysql开启autocommit，只有调用start transaction，它一直认为每个sql都是一个单独的事务。如果关闭了autocommit，除非你调用了commit或者rollback，你会一直在一个事务里面。当调用commit或者rollback后，它会自动的帮你在启动一个事务。</p>
<p>因为存储引擎自己实现事务，所以一个事务无法跨越多重存储引擎类型的表。</p>
<p>在一个事务中任何时候都可以获取锁，但只有事务结束时才会释放锁。lock in share mode是允许其他session读但不能写，读取的数据行如果被其他事物锁着，就会等待直到那个事务提交。for update则是排他锁，不允许读或者写。</p>
<p>Innodb实现Mutiversion concurrency control（MVCC），通过为每行数据记录两个隐藏的值，这两个值分别为数据创建点与过期点（binlog中的那些版本号）。增删查的处理就不用多说了，改的时候，innodb通过增加一个数据行的拷贝来完成，拷贝的创建号与原数据行的删除号就是当前系统号。</p>
<p>遗留问题：</p>
<p>在repeatable read下，innodb是怎么处理这个lock in share mode的呢？</p>
本文永久链接:<a href="http://www.mirecle.com/2009/10/13/mysql-study-notes-1.html">http://www.mirecle.com/2009/10/13/mysql-study-notes-1.html</a>
<br/>
[<a href="http://www.mirecle.com/2009/10/13/mysql-study-notes-1.html#respond">发表评论</a>]

<p>您可能会喜欢:<ol><li><a href='http://www.mirecle.com/2009/10/16/digg-founder-a-user-into-one-million-of-the-9-kinds-of-ways.html' rel='bookmark' title='Permanent Link: Digg创始人：1个用户变成100万的9种办法'>Digg创始人：1个用户变成100万的9种办法</a></li>
<li><a href='http://www.mirecle.com/2010/06/01/the-number-of-charges-on-the-money.html' rel='bookmark' title='Permanent Link: 关于数钱费'>关于数钱费</a></li>
<li><a href='http://www.mirecle.com/2009/09/09/increase-the-head-request-processing-to-avoid-the-405-error-occurs-micolog.html' rel='bookmark' title='Permanent Link: 增加head请求处理，避免micolog出现405错误'>增加head请求处理，避免micolog出现405错误</a></li>
</ol></p>]]></content:encoded>
			<wfw:commentRss>http://www.mirecle.com/2009/10/13/mysql-study-notes-1.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
