<?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>运维和开发 &#187; mysql</title>
	<atom:link href="http://www.hoterran.info/tag/mysql/feed" rel="self" type="application/rss+xml" />
	<link>http://www.hoterran.info</link>
	<description>十万小时之旅</description>
	<lastBuildDate>Fri, 22 Mar 2013 15:58:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>MySQL协议分析</title>
		<link>http://www.hoterran.info/mysql-protocol-soucecode-2</link>
		<comments>http://www.hoterran.info/mysql-protocol-soucecode-2#comments</comments>
		<pubDate>Thu, 21 Jun 2012 08:41:00 +0000</pubDate>
		<dc:creator>hoterran</dc:creator>
				<category><![CDATA[explore mysql sourcecode]]></category>
		<category><![CDATA[sourcecode]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[protocol]]></category>

		<guid isPermaLink="false">http://www.hoterran.info/?p=774</guid>
		<description><![CDATA[MySQL协议分析,主要参考MySQL Forge上的wiki和源码.协议的全图见这里, 给同事分享的ppt见这里,下载见这里 MySQL协议分析 View more presentations from ruoyi ruan packet number 在做proxy的时候在这里迷糊过,翻了几遍代码才搞明白，细节如下： 客户端服务端的net-&#62;pkt_nr都从0开始.接受包时比较packet number 和net-&#62;pkt_nr是否相等,否则报packet number乱序,连接报错;相等则pkt_nr自增.发送包时把net-&#62;pkt_nr作为packet number发送,然后对net-&#62;pkt_nr进行自增保持和对端的同步. 接收包 sql/net_serv.c:my_real_read 898 if (net-&#62;buff[net-&#62;where_b + 3] != (uchar) net-&#62;pkt_nr) 发送包 sql/net_serv.c:my_net_write 392 int3store(buff,len); 393 buff[3]= (uchar) net-&#62;pkt_nr++; 我们来几个具体场景的packet number, net-&#62;pkt_nr的变化 连接 0 c &#8212;&#8212;&#8212;&#8211;&#62; s 0  connect 0 c &#60;&#8212;-0&#8212;&#8212;s 1  handshake 2 c &#8212;&#8211;1&#8212;&#8211;&#62;s 1 [...]]]></description>
			<content:encoded><![CDATA[<p>MySQL协议分析,主要参考MySQL Forge上的<a href="http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol">wiki</a>和源码.协议的全图见<a href="http://huaban.com/pins/8262295/zoom/">这里</a>, 给同事分享的ppt见<a href="https://docs.google.com/presentation/pub?id=1vGZkiZUDHVLye5_WdAT3dV2LHOoB2cLRl6g36x8nnHQ&amp;start=false&amp;loop=false&amp;delayms=3000">这里</a>,下载见<a href="http://vdisk.weibo.com/s/7lpaF">这里</a></p>
<h3><span id="more-774"></span></h3>
<div id="__ss_13400392" style="width: 595px;"><strong style="display: block; margin: 12px 0 4px;"><a title="MySQL协议分析" href="http://www.slideshare.net/hoterran/mysql-13400392" target="_blank">MySQL协议分析</a></strong> <iframe style="border: 1px solid #CCC; border-width: 1px 1px 0;" src="http://www.slideshare.net/slideshow/embed_code/13400392" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" width="595" height="497"></iframe></p>
<div style="padding: 5px 0 12px;">View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/hoterran" target="_blank">ruoyi ruan</a></div>
</div>
<h3>packet number</h3>
<p>在做proxy的时候在这里迷糊过,翻了几遍代码才搞明白，细节如下：<br />
客户端服务端的net-&gt;pkt_nr都从0开始.接受包时比较packet number 和net-&gt;pkt_nr是否相等,否则报packet number乱序,连接报错;相等则pkt_nr自增.发送包时把net-&gt;pkt_nr作为packet number发送,然后对net-&gt;pkt_nr进行自增保持和对端的同步.</p>
<h4>接收包</h4>
<p>sql/net_serv.c:my_real_read</p>
<pre>898     if (net-&gt;buff[net-&gt;where_b + 3] != (uchar) net-&gt;pkt_nr)</pre>
<h4>发送包</h4>
<p>sql/net_serv.c:my_net_write</p>
<pre>
392   int3store(buff,len);
393   buff[3]= (uchar) net-&gt;pkt_nr++;</pre>
<p>我们来几个具体场景的packet number, net-&gt;pkt_nr的变化</p>
<p><span class="Apple-style-span" style="font-weight: bold;">连接</span></p>
<p>0 c &#8212;&#8212;&#8212;&#8211;&gt; s 0  connect</p>
<p>0 c &lt;&#8212;-0&#8212;&#8212;s 1  handshake</p>
<p>2 c &#8212;&#8211;1&#8212;&#8211;&gt;s 1 auth</p>
<p>2c &lt;&#8212;&#8211;2&#8212;&#8212;s 0 ok</p>
<p>开始两方都为0,服务端发送handshake packet(pkt=0)之后自增为1,然后等待对端发送过来pkt=1的包</p>
<p>&nbsp;</p>
<h4>查询</h4>
<p>每次查询,服务客户端都会对net-&gt;pkt_nr进行清零</p>
<pre>
include/mysql_com.h
388 #define net_new_transaction(net) ((net)-&gt;pkt_nr=0)</pre>
<pre>
sql/sql_parse.cc:do_command
805   net_new_transaction(net);</pre>
<p>sql/client.c:cli_advanced_command</p>
<pre>800   net_clear(&amp;mysql-&gt;net, (command != COM_QUIT));</pre>
<p>开始两方net-&gt;pkt_nr皆为0, 命令发送后客户端端为1,服务端开始发送分包,分包的pkt_nr的依次递增,客户端的net-&gt;pkt_nr也随之增加.</p>
<p>1 c &#8212;&#8212;0&#8212;&#8211;&gt; s 0  query</p>
<p>1 c &lt;&#8212;-1&#8212;&#8212;s 2  resultset</p>
<p>2 c &lt;&#8212;-2&#8212;&#8212;s 3  resultset</p>
<h3> 解包的细节</h3>
<p>my_net_read负责解包，首先读取4个字节，判断packet number是否等于net-&gt;pkt_nr然后再次读取packet_number长度的包体。</p>
<p>伪代码如下：</p>
<pre>remain=4
for(i = 0; i &lt; 2; i++) {
    //数据是否读完
    while (remain&gt;0)  {
        length = read(fd, net-&gt;buff, remain)
        remain = remain - length
    }
    //第一次
    if (i=0) {
        remain = uint3korr(net-&gt;buff+net-&gt;where_b);
    }
}</pre>
<h3>网络层优化</h3>
<p>从ppt里可以看到,一个resultset packet由多个包组成,如果每次读写包都导致系统调用那肯定是不合理,常规优化方法:写大包加预读</p>
<h4>net-&gt;buff</h4>
<p>每个包发送到网络或者从网络读包都会先把数据包保存在net-&gt;buff里,待到net-&gt;buff满了或者一次命令结束才会通过socket发出给对端.net-&gt;buff有个初始大小(net-&gt;max_packet),会随读取数据的增多而扩展.</p>
<h4>vio-&gt;read_buffer</h4>
<p>每次从网络读包,并不是按包的大小读取,而是会尽量读取2048个字节,这样一个resultset包的读取不会再引起多次的系统调用了.header packet读取完毕后, 接下来的field,eof, row apcket读取仅仅需要从vio-read_buffer拷贝指定字节的数据即可.</p>
<h3>MySQL api说明</h3>
<p>api和MySQL客户端都会使用sql/client.c这个文件,解包的过程都是使用sql/client.c:cli_read_query_result.</p>
<p>mysql_store_result来解析row packet,并把数据存储到res-&gt;data里,此时所有数据都存内存里了.</p>
<p>mysql_fetch_row仅仅是使用内部的游标,遍历result-&gt;data里的数据</p>
<pre>3052     if (!res-&gt;data_cursor)
3053     {
3054       DBUG_PRINT("info",("end of data"));
3055       DBUG_RETURN(res-&gt;current_row=(MYSQL_ROW) NULL);
3056     }
3057     tmp = res-&gt;data_cursor-&gt;data;
3058     res-&gt;data_cursor = res-&gt;data_cursor-&gt;next;
3059     DBUG_RETURN(res-&gt;current_row=tmp);</pre>
<p>mysql_free_result是把result-&gt;data指定的行数据释放掉.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hoterran.info/mysql-protocol-soucecode-2/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>mydumper的使用和源代码分析</title>
		<link>http://www.hoterran.info/mydumper_usage</link>
		<comments>http://www.hoterran.info/mydumper_usage#comments</comments>
		<pubDate>Mon, 25 Jul 2011 03:47:01 +0000</pubDate>
		<dc:creator>hoterran</dc:creator>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[mydumper]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.hoterran.info/?p=395</guid>
		<description><![CDATA[mydumper是一个多线程、高性能的数据逻辑备份、恢复的工具，相比MySQL自带的mysqldump提速不少。我下载了0.23的稳定版本，阅读了源码并总结了一些使用的心得。 mysqldump是个单线程的逻辑备份工具，依次一个个导出多个表，没有一个并行的机制。mydumper弥补了这方面的缺陷可以并行的多线程的从表中读入数据并同时写到不同的文件里。项目的作者是由一群在sun、fb、skysql的工程师完成的。类似的工具还有mk-parallel-dump。 编译安装 cmake . make sudo make install 源码分析 根据流程图解释一下mydumper的工作步骤。 解析参数 使用glib的g_option_context_parse，比libc里的getopt_long简单多了。 连接目标数据库。 通过show processlist来判断是否有长查询，如果有长查询则退出dump，可以通过&#8211;long-query-guard加长时间，或者使用&#8211;kill-long-queries杀掉长查询。 锁定myisam表。 针对innodb table开启事务。 产生3个消息队列(线程ready队列、任务队列、myisam表处理完毕队列)。 conf.queue = g_async_queue_new(); conf.ready = g_async_queue_new(); conf.unlock_tables= g_async_queue_new(); 产生指定的线程个数，&#8211;threads可以指定，默认是4个。 GThread **threads = g_new(GThread*,num_threads); struct thread_data *td= g_new(struct thread_data, num_threads); for (n=0; n&#60;num_threads; n++) { td[n].conf= &#38;conf; td[n].thread_id= n+1; threads[n] = g_thread_create((GThreadFunc)process_queue,&#38;td[n],TRUE,NULL); g_async_queue_pop(conf.ready); } dump_database，从DATA_DICTIONARY.TABLES读取所有表，通过&#8211;ignore, &#8211;tables-list, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.mydumper.org/">mydumper</a>是一个多线程、高性能的数据逻辑备份、恢复的工具，相比MySQL自带的mysqldump提速不少。我下载了<a href="http://launchpad.net/mydumper/0.2/0.2.3/+download/mydumper-0.2.3.tar.gz">0.23的稳定版本</a>，阅读了源码并总结了一些使用的心得。</p>
<p>mysqldump是个单线程的逻辑备份工具，依次一个个导出多个表，没有一个并行的机制。mydumper弥补了这方面的缺陷可以并行的多线程的从表中读入数据并同时写到不同的文件里。项目的作者是由一群在sun、fb、skysql的工程师完成的。类似的工具还有<a href="http://www.maatkit.org/doc/mk-parallel-dump.html">mk-parallel-dump</a>。</p>
<h3>编译安装</h3>
<pre>
cmake .
make
sudo make install
</pre>
<h3>源码分析</h3>
<p>根据流程图解释一下mydumper的工作步骤。<br />
<a href="http://www.hoterran.info/wp-content/uploads/2011/07/mydumper.png"><img src="http://www.hoterran.info/wp-content/uploads/2011/07/mydumper-1024x890.png" alt="" title="mydumper" width="1024" height="890" class="aligncenter size-large wp-image-402" /></a><br />
解析参数<br />
使用glib的g_option_context_parse，比libc里的getopt_long简单多了。</p>
<p>连接目标数据库。</p>
<p>通过show processlist来判断是否有长查询，如果有长查询则退出dump，可以通过&#8211;long-query-guard加长时间，或者使用&#8211;kill-long-queries杀掉长查询。</p>
<p>锁定myisam表。</p>
<p>针对innodb table开启事务。</p>
<p>产生3个消息队列(线程ready队列、任务队列、myisam表处理完毕队列)。</p>
<pre>
conf.queue = g_async_queue_new();
conf.ready = g_async_queue_new();
conf.unlock_tables= g_async_queue_new();
</pre>
<p>产生指定的线程个数，&#8211;threads可以指定，默认是4个。</p>
<pre>
GThread **threads = g_new(GThread*,num_threads);
struct thread_data *td= g_new(struct thread_data, num_threads);
for (n=0; n&lt;num_threads; n++) {
    td[n].conf= &amp;conf;
    td[n].thread_id= n+1;
    threads[n] = g_thread_create((GThreadFunc)process_queue,&amp;td[n],TRUE,NULL);
    g_async_queue_pop(conf.ready);
}
</pre>
<p>dump_database，从DATA_DICTIONARY.TABLES读取所有表，通过&#8211;ignore, &#8211;tables-list, regex等过滤条件，产生需要dump的目标表列表，分别插入innodb_tables、non_innodb_table、table_schemas三个链表。</p>
<pre>
    query= g_strdup_printf("SELECT TABLE_NAME, ENGINE, TABLE_TYPE as COMMENT FROM DATA_DICTIONARY.TABLES WHERE TABLE_SCHEMA='%s'", database);
    ....
    innodb_tables= g_list_append(innodb_tables, dbt);
    ....
    non_innodb_table= g_list_append(non_innodb_table, dbt);
    ....
    table_schemas= g_list_append(table_schemas, dbt);
</pre>
<p>dump non-innodb table 把需要导出myisam表加入到任务队列。</p>
<pre>
        for (non_innodb_table= g_list_first(non_innodb_table); non_innodb_table; non_innodb_table= g_list_next(non_innodb_table)) {
                dbt= (struct db_table*) non_innodb_table->data;
                dump_table(conn, dbt->database, dbt->table, &#038;conf, FALSE);
                g_atomic_int_inc(&#038;non_innodb_table_counter);
        }
</pre>
<p>dump innodb table把需要导出innodb表加入任务队列。</p>
<pre>
        for (innodb_tables= g_list_first(innodb_tables); innodb_tables; innodb_tables= g_list_next(innodb_tables)) {
                dbt= (struct db_table*) innodb_tables->data;
                dump_table(conn, dbt->database, dbt->table, &#038;conf, TRUE);
        }
</pre>
<p>dump schema 把需要导出表结构任务加入到任务队列。</p>
<pre>
        for (table_schemas= g_list_first(table_schemas); table_schemas; table_schemas= g_list_next(table_schemas)) {
                dbt= (struct db_table*) table_schemas->data;
                dump_schema(dbt->database, dbt->table, &#038;conf);
                g_free(dbt->table);
                g_free(dbt->database);
                g_free(dbt);
        }
</pre>
<p>典型的生产者（主线程）消费者（子线程）模式，子线程会从任务队列里读取需要处理的表名字和表类型，再通过select * from table_name 读入数据各自写入到各自的文件。</p>
<pre>
for(;;) {
    ....
    job=(struct job *)g_async_queue_pop(conf->queue);
    ....
    switch (job->type) {
        case JOB_DUMP:
            ....
            dump_table_data_file(thrconn, tj->database, tj->table, tj->where, tj->filename);
            ....
        case JOB_DUMP_NON_INNODB:
            ....
            dump_table_data_file(thrconn, tj->database, tj->table, tj->where, tj->filename);
        case JOB_SCHEMA:
            ....
            dump_schema_data(thrconn, sj->database, sj->table, sj->filename);
}
</pre>
<p>所有导数据的任务加入任务队列之后，会再加入让线程退出的任务，让线程自然退出。</p>
<pre>
case JOB_SHUTDOWN:
    g_message("Thread %d shutting down", td-&gt;thread_id);
    if (thrconn)
        mysql_close(thrconn);
    g_free(job);
    mysql_thread_end();
    return NULL;
    break;
</pre>
<p>解除myisam表锁。</p>
<p>等待子线程退出。</p>
<h3>使用</h3>
<p>导出test database的数据</p>
<pre>
 mydumper -h 127.0.0.1 -u root --database test
</pre>
<p>指定某个目录</p>
<pre>
 mydumper -h 127.0.0.1 -u root --outputdir=.
</pre>
<p>不导出表结构</p>
<pre>
 mydumper -h 127.0.0.1 -u root --no-schema
</pre>
<p>如果表数据是空，还是产生一个空文件（默认无数据则只有表结构文件）</p>
<pre>
 mydumper -h 127.0.0.1 -u root --build-empty-files
</pre>
<p>设置长查询的上限，如果存在比这个还长的查询则退出mydumper，也可以设置杀掉这个长查询</p>
<pre>
 mydumper -h 127.0.0.1 -u root --long-query-guard 200 --kill-long-queries
</pre>
<p>设置要dump的列表&#8211;tables-list，不需要设置db名字，逗号分割</p>
<pre>
 mydumper -h 127.0.0.1 -u root --tables-list=ddd,zzz
</pre>
<p>通过regex也设置正则表达，需要设置db名字</p>
<pre>
 mydumper -h 127.0.0.1 -u root --regex=test.z
</pre>
<p>把单表分成多个chunks，这个后面会讲分割的原理</p>
<pre>
 mydumper -h 127.0.0.1 -u root --rows 10000
</pre>
<p>过滤某个引擎的表</p>
<pre>
 mydumper -h 127.0.0.1 -u root -B test --ignore-engines=innodb
</pre>
<p>详细日志</p>
<pre>
 mydumper -h 127.0.0.1 -u root -B test -v 3
</pre>
<h3>几个注意点</h3>
<p>各自线程都要自己连接到数据库，因为libmysql是线程不安全的。<br />
因为对myisam表有有表锁，所有先处理myisam表，记录myisam表个数，每处理一个myisam都原子操作数量减一。并在myisam表都处理完毕后，立即解锁，尽量减少锁定的时间，而不是在导出innodb表数据的时候还在lock myisam表。</p>
<p>main_thread</p>
<pre>
for (non_innodb_table= g_list_first(non_innodb_table); non_innodb_table; non_innodb_table= g_list_next(non_innodb_table)) {
        dbt= (struct db_table*) non_innodb_table->data;
        dump_table(conn, dbt->database, dbt->table, &#038;conf, FALSE);
        g_atomic_int_inc(&#038;non_innodb_table_counter);
}
</pre>
<p>child_thread</p>
<pre>
if (g_atomic_int_dec_and_test(&#038;non_innodb_table_counter) &#038;&#038; g_atomic_int_get(&#038;non_innodb_done)) {
        g_async_queue_push(conf->unlock_tables, GINT_TO_POINTER(1));
}
</pre>
<p>main_thread</p>
<pre>
g_async_queue_pop(conf.unlock_tables);
g_message("Non-InnoDB dump complete, unlocking tables");
mysql_query(conn, "UNLOCK TABLES");
</pre>
<p>&#8211;regex的处理在&#8211;tables-list后， 先满足&#8211;tables-list再满足&#8211;regex，如下只会dump表z1</p>
<pre>
mydumper -h 127.0.0.1 -u root --regex=test.z1 --outputdir=. --rows=10000 -v 3 -e --tables-list=z2,z1
** Message: Thread 1 dumping data for `test`.`z1`
** Message: Thread 2 dumping schema for `test`.`z1`
</pre>
<p>&#8211;rows的使用，设置&#8211;rows可以把一个表分成多个文件。分块的原则并不是根据&#8211;rows设定的行数来决定生成文件里包含的函数，而是通过rows和表的总行数计算出要生成的文件个数，尽量保证每个文件的大小一致。</p>
<p>表的总行数是如何获得的？<br />
首先mydumper会选择一个索引，顺序是pk、uk或者show index from table里Cardinality最高的一个索引，再通过explain select index from table的rows字段获得总行数total_nums（可能不准确），于是第一个文件就是从select * from table where index >=1  and index < total_nums/ (int(total_nums/ rows) &#8211; 1) + 1。每个分块可以分到不同的线程，所以即便同一个表dump都可以很快加速。</p>
<p>ps：这个项目大量使用glib（gnome）比较少见，看了一下glib doc觉得glib设计的挺好的用起来很方便，否则实现一个消息队列加多线程还是要几百行代码的。接下来要看mydumper0.50的代码。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hoterran.info/mydumper_usage/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>给Python的MySQLdb模块加功能</title>
		<link>http://www.hoterran.info/mysqldb_add_option</link>
		<comments>http://www.hoterran.info/mysqldb_add_option#comments</comments>
		<pubDate>Mon, 21 Mar 2011 07:57:04 +0000</pubDate>
		<dc:creator>hoterran</dc:creator>
				<category><![CDATA[pymodule]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://www.hoterran.info/?p=216</guid>
		<description><![CDATA[使用Python操作MySQL数据库的时候常使用MySQLdb这个模块。 今天在开发的过程发现MySQLdb.connect有些参数没法设置。通过这个页面我们可以看到在connect的时候，可以设置的option和client_flags和MySQL c api相比差不少。 一个很重要的参数 MYSQL_OPT_READ_TIMEOUT没法设置，这个参数如果不设置，极致状况MySQL处于hang住，自动切换IP漂移，客户端无法重连到新MySQL。 给MySQLdb加Option很简单，只要修改_mysql.c这个把Python对象映射到MySQL操作的文件，添加参数，再加一段mysql_option即可。 下面是修改后的git diff 文件 diff --git a/_mysql.c b/_mysql.c index d42cc54..61a9b34 100644 --- a/_mysql.c +++ b/_mysql.c @@ -489,9 +489,10 @@ _mysql_ConnectionObject_Initialize( "named_pipe", "init_command", "read_default_file", "read_default_group", "client_flag", "ssl", -                                 "local_infile", +                                 "local_infile", "read_timeout", NULL } ; int connect_timeout = 0; +       int read_timeout = 0; int compress = -1, named_pipe = [...]]]></description>
			<content:encoded><![CDATA[<p>使用Python操作MySQL数据库的时候常使用<a href="http://mysql-python.sourceforge.net">MySQLdb</a>这个模块。</p>
<p>今天在开发的过程发现MySQLdb.connect有些参数没法设置。通过<a href="http://mysql-python.sourceforge.net/MySQLdb-1.2.2/public/MySQLdb.connections.Connection-class.html#__init__">这个页面</a>我们可以看到在connect的时候，可以设置的option和client_flags和MySQL c api相比差不少。</p>
<p>一个很重要的参数 MYSQL_OPT_READ_TIMEOUT没法设置，这个参数如果不设置，极致状况MySQL处于hang住，自动切换IP漂移，客户端无法重连到新MySQL。</p>
<p>给MySQLdb加Option很简单，只要修改_mysql.c这个把Python对象映射到MySQL操作的文件，添加参数，再加一段mysql_option即可。</p>
<p>下面是修改后的git diff 文件</p>
<pre lang=bash>
diff --git a/_mysql.c b/_mysql.c
index d42cc54..61a9b34 100644
--- a/_mysql.c
+++ b/_mysql.c
@@ -489,9 +489,10 @@ _mysql_ConnectionObject_Initialize(
"named_pipe", "init_command",
"read_default_file", "read_default_group",
"client_flag", "ssl",
-                                 "local_infile",
+                                 "local_infile", "read_timeout",
NULL } ;
int connect_timeout = 0;
+       int read_timeout = 0;
int compress = -1, named_pipe = -1, local_infile = -1;
char *init_command=NULL,
*read_default_file=NULL,
@@ -500,7 +501,7 @@ _mysql_ConnectionObject_Initialize(
self-&gt;converter = NULL;
self-&gt;open = 0;
check_server_init(-1);
-       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssssisOiiisssiOi:connect",
+       if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ssssisOiiisssiOii:connect",
kwlist,
&amp;host, &amp;user, &amp;passwd, &amp;db,
&amp;port, &amp;unix_socket, &amp;conv,
@@ -509,7 +510,8 @@ _mysql_ConnectionObject_Initialize(
&amp;init_command, &amp;read_default_file,
&amp;read_default_group,
&amp;client_flag, &amp;ssl,
-                                        &amp;local_infile /* DO NOT PATCH FOR RECONNECT, IDIOTS
+                                        &amp;local_infile, &amp;read_timeout
+                                        /* DO NOT PATCH FOR RECONNECT, IDIOTS
IF YOU DO THIS, I WILL NOT SUPPORT YOUR PACKAGES. */
))
return -1;
@@ -540,6 +542,12 @@ _mysql_ConnectionObject_Initialize(
mysql_options(&amp;(self-&gt;connection), MYSQL_OPT_CONNECT_TIMEOUT,
(char *)&amp;timeout);
}
+
+        if (read_timeout) {
+                unsigned int timeout = read_timeout;
+                mysql_options(&amp;(self-&gt;connection), MYSQL_OPT_READ_TIMEOUT, (char *)&amp;timeout);
+        }
+
if (compress != -1) {
mysql_options(&amp;(self-&gt;connection), MYSQL_OPT_COMPRESS, 0);
client_flag |= CLIENT_COMPRESS;
</pre>
<p>代码修改完毕，python setup.py install 即可，如果出现mysql_config找不到的问题。你还要修改setup_posix.py文件。</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">hoterran<span style="color: #000000; font-weight: bold;">@</span>hoterran-laptop:~<span style="color: #000000; font-weight: bold;">/</span>Projects<span style="color: #000000; font-weight: bold;">/</span>MySQL-python-1.2.3$ <span style="color: #c20cb9; font-weight: bold;">git</span> <span style="color: #c20cb9; font-weight: bold;">diff</span> setup_posix.py
<span style="color: #c20cb9; font-weight: bold;">diff</span> <span style="color: #660033;">--git</span> a<span style="color: #000000; font-weight: bold;">/</span>setup_posix.py b<span style="color: #000000; font-weight: bold;">/</span>setup_posix.py
index 86432f5..f4f08f1 <span style="color: #000000;">100644</span>
<span style="color: #660033;">---</span> a<span style="color: #000000; font-weight: bold;">/</span>setup_posix.py
+++ b<span style="color: #000000; font-weight: bold;">/</span>setup_posix.py
<span style="color: #000000; font-weight: bold;">@@</span> -<span style="color: #000000;">23</span>,<span style="color: #000000;">7</span> +<span style="color: #000000;">23</span>,<span style="color: #000000;">7</span> <span style="color: #000000; font-weight: bold;">@@</span> def mysql_config<span style="color: #7a0874; font-weight: bold;">&#40;</span>what<span style="color: #7a0874; font-weight: bold;">&#41;</span>:
         <span style="color: #000000; font-weight: bold;">if</span> ret<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">256</span> <span style="color: #000000; font-weight: bold;">&amp;</span>gt; <span style="color: #000000;">1</span>:
             raise EnvironmentError<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;%s not found&quot;</span> <span style="color: #000000; font-weight: bold;">%</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mysql_config.path,<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
     <span style="color: #7a0874; font-weight: bold;">return</span> data
-mysql_config.path = <span style="color: #ff0000;">&quot;mysql_config&quot;</span>
+mysql_config.path = <span style="color: #ff0000;">&quot;/usr/local/mysql/bin/mysql_config&quot;</span>
&nbsp;
 def get_config<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>:
     import os, sys</pre></div></div>

<p>编译通过，我们来试试添加的read_timeout这个参数。</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">conn = MySQLdb.<span style="color: black;">connect</span><span style="color: black;">&#40;</span>host = DB_SERVER,<span style="color: #dc143c;">user</span> = DB_USERNAME,passwd = DB_PASSWORD,db = DB_NAME, port=<span style="color: #008000;">int</span><span style="color: black;">&#40;</span>DB_PORT<span style="color: black;">&#41;</span>, client_flag = <span style="color: #ff4500;">2</span>, read_timeout = <span style="color: #ff4500;">10</span><span style="color: black;">&#41;</span></pre></div></div>

<p>然后执行语句前，你试着把mysql用gdb hang住10s后，python就会异常抛错</p>

<div class="wp_syntax"><div class="code"><pre class="python" style="font-family:monospace;">OperationalError: <span style="color: black;">&#40;</span><span style="color: #ff4500;">2013</span>, <span style="color: #483d8b;">'Lost connection to MySQL server during query'</span><span style="color: black;">&#41;</span>
 <span style="color: #66cc66;">&gt;</span>/home/hoterran/Projects/dbaas/trunk/dbtest.<span style="color: black;">py</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">18</span><span style="color: black;">&#41;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>
 <span style="color: #66cc66;">&gt;</span>mydb.<span style="color: black;">execute_sql</span><span style="color: black;">&#40;</span>conn, sql<span style="color: black;">&#41;</span>
<span style="color: black;">&#40;</span>Pdb<span style="color: black;">&#41;</span>
--Return--
<span style="color: #66cc66;">&gt;</span> /home/hoterran/Projects/dbaas/trunk/dbtest.<span style="color: black;">py</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">18</span><span style="color: black;">&#41;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>-<span style="color: #66cc66;">&amp;</span>gt<span style="color: #66cc66;">;</span>None
<span style="color: #66cc66;">&gt;</span> mydb.<span style="color: black;">execute_sql</span><span style="color: black;">&#40;</span>conn, sql<span style="color: black;">&#41;</span>
<span style="color: black;">&#40;</span>Pdb<span style="color: black;">&#41;</span>
OperationalError: <span style="color: black;">&#40;</span><span style="color: #ff4500;">2013</span>, <span style="color: #483d8b;">'Lost connection to MySQL server during query'</span><span style="color: black;">&#41;</span>
<span style="color: #66cc66;">&gt;</span> <span style="color: #66cc66;">&lt;</span>string<span style="color: #66cc66;">&gt;</span><span style="color: black;">&#40;</span><span style="color: #ff4500;">1</span><span style="color: black;">&#41;</span><span style="color: #66cc66;">&lt;</span>module<span style="color: #66cc66;">&gt;</span><span style="color: black;">&#40;</span><span style="color: black;">&#41;</span>-<span style="color: #66cc66;">&gt;</span>None</pre></div></div>

<p>ps: 在_mysql.c找到一句很搞的话</p>

<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">/* DO NOT PATCH FOR RECONNECT, IDIOTS
IF YOU DO THIS, I WILL NOT SUPPORT YOUR PACKAGES. */</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://www.hoterran.info/mysqldb_add_option/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
