<?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>Fwolf's Blog &#187; Database - Fwolf's Blog</title>
	<atom:link href="http://www.fwolf.com/blog/category/develop/database/feed" rel="self" type="application/rss+xml" />
	<link>http://www.fwolf.com/blog</link>
	<description>随心·随意·随缘·努力～</description>
	<lastBuildDate>Sun, 29 Aug 2010 14:52:23 +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>Mysql升级到5.1后库升级失败的问题</title>
		<link>http://www.fwolf.com/blog/post/440</link>
		<comments>http://www.fwolf.com/blog/post/440#comments</comments>
		<pubDate>Tue, 12 May 2009 17:32:39 +0000</pubDate>
		<dc:creator>Fwolf</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Problem]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[rename]]></category>
		<category><![CDATA[upgrade]]></category>
		<category><![CDATA[view]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/post/440</guid>
		<description><![CDATA[一台 mysql 5.0 服务器，升级到 5.1 后，发现原来有个 database 名字变成了 #mysql50#t-2008-zbb ，刚开始没在意想直接 RENAME DATABASE ，结果这个语法由于过渡危险已经取消了，改用ALTER DATABASE db_name UPGRADE DATA DIRECTORY NAME，结果执行错误： mysql&#62; ALTER DATABASE `#mysql50#db_name` UPGRADE DATA DIRECTORY NAME; ERROR 1450 (HY000): Changing schema from '#mysql50#db_name' to 'db_name' is not allowed. 原来这里面还有个 BUG ，刚刚修正过来，发行版中肯定还没有呢。幸好，从中得到了提示，因为 View 的存在导致库无法升级的，删掉所有视图后 UPGRADE 成功： mysql&#62; ALTER DATABASE `#mysql50#db_name` UPGRADE DATA DIRECTORY NAME; Query [...]]]></description>
			<content:encoded><![CDATA[<p>一台 mysql 5.0 服务器，升级到 5.1 后，发现原来有个 database 名字变成了 <code>#mysql50#t-2008-zbb</code> ，刚开始没在意想直接 <code>RENAME DATABASE</code> ，结果<a href="http://dev.mysql.com/doc/refman/5.1/en/rename-database.html">这个语法由于过渡危险已经取消了</a>，改用<a href="http://dev.mysql.com/doc/refman/5.1/en/alter-database.html">ALTER DATABASE db_name UPGRADE DATA DIRECTORY NAME</a>，结果执行错误：</p>

<pre><code>mysql&gt; ALTER DATABASE `#mysql50#db_name` UPGRADE DATA DIRECTORY NAME;
ERROR 1450 (HY000): Changing schema from '#mysql50#db_name' to 'db_name' is not allowed.
</code></pre>

<p>原来这里面还有个 <a href="http://bugs.mysql.com/bug.php?id=43385">BUG</a> ，刚刚修正过来，发行版中肯定还没有呢。幸好，从中得到了提示，因为 View 的存在导致库无法升级的，删掉所有视图后 UPGRADE 成功：</p>

<pre><code>mysql&gt; ALTER DATABASE `#mysql50#db_name` UPGRADE DATA DIRECTORY NAME;
Query OK, 0 rows affected (0.08 sec)
</code></pre>

<p>这台服务器还作了双向同步，我还得手工重置同步状态，又是麻烦一连串儿的事情，幸亏这次操作的是测试服务器，下次升级正式服务器之前，记得先把所有 View 删掉，升级完成后再重新创建。</p>

<p>另外 <code>RENAME DATABASE</code> 实在是危险，我执行过程中出错终止了，结果一部分表在新库里、一部分表在旧库中，不小心把未转完的目标库删掉了（不然后面的正常 ALTER DATABASE 无法继续），结果就丢失了这些表的数据。</p>

	Tags: <a href="http://www.fwolf.com/blog/post/tag/mysql" title="mysql" rel="tag">mysql</a>, <a href="http://www.fwolf.com/blog/post/tag/problem" title="Problem" rel="tag">Problem</a>, <a href="http://www.fwolf.com/blog/post/tag/rename" title="rename" rel="tag">rename</a>, <a href="http://www.fwolf.com/blog/post/tag/upgrade" title="upgrade" rel="tag">upgrade</a>, <a href="http://www.fwolf.com/blog/post/tag/view" title="view" rel="tag">view</a><br />

	<h4>Related posts</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.fwolf.com/blog/post/426" title="升级到8.10 intrepid过程中libc6依赖性死循环问题的解决 (2009-01-04)">升级到8.10 intrepid过程中libc6依赖性死循环问题的解决</a> (6)</li>
	<li><a href="http://www.fwolf.com/blog/post/5" title="Ubuntu 升级到 10.04 lucid (2010-07-07)">Ubuntu 升级到 10.04 lucid</a> (2)</li>
	<li><a href="http://www.fwolf.com/blog/post/417" title="机房搬家过程中的几件趣事 (2009-03-22)">机房搬家过程中的几件趣事</a> (0)</li>
	<li><a href="http://www.fwolf.com/blog/post/404" title="忙碌的5月 (2008-06-13)">忙碌的5月</a> (10)</li>
	<li><a href="http://www.fwolf.com/blog/post/369" title="在无线网络中使用RADIUS服务器+mysql进行用户认证 (2007-11-15)">在无线网络中使用RADIUS服务器+mysql进行用户认证</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.fwolf.com/blog/post/440/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>mysql的复制</title>
		<link>http://www.fwolf.com/blog/post/435</link>
		<comments>http://www.fwolf.com/blog/post/435#comments</comments>
		<pubDate>Sun, 15 Mar 2009 17:32:44 +0000</pubDate>
		<dc:creator>Fwolf</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[innodb]]></category>
		<category><![CDATA[migration]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[replication]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/?p=435</guid>
		<description><![CDATA[这篇算是我的学习笔记，主要内容都来自mysql官方文档，然后参考一些网上的文章自己实践了个例子，所以内容上前后也有些重复。 mysql支持从一个主服务器到多个从服务器的复制，并且复制是异步的，也就是说从服务器不用一直保持与主服务器的连接，这使得一些远程、临时性的节点也能进行同步。同时，还可以指定参与同步的数据库或者数据表。 同步目前主要用于以下几个方面： 架构扩容，一主写多从读的方式已经用得非常普遍了 数据安全，同步也是一种备份，而且还可以是实时的，多好啊 数据分析，大量的分析运算在从服务器上运行，不影响主系统的负载 远程数据发布，或者说远程备份 同步的基本设置 主服务器的my.cnf设置 同步是通过binlog来实现的，虽然主服务器不能决定哪些操作在binlog中记录（默认记录全部），但从服务器可以根据配置来有选择的执行。每个主、从服务器都要有一个唯一ID，从服务器还要记录主服务器的主机名、log文件名以及位置等信息（在master.info中），并保存一份收到的binlog，这样多台从服务器就可以有不同的同步状态或进度，并且下次连线的时候再以“续传”的方式继续同步进程。binlog的开启需要修改主服务器的my.cnf # 必须写在[mysqld]节里面 [mysqld] # mysql-bin是log文件的前缀，也可以使用其它的名字，比如服务器名 # 如果不带路径，会把log文件写到`/var/lib/mysql`下 log-bin=mysql-bin # serverid在一个同步体系中必须是唯一的，大于等于1且小于2^32-1的整数 server-id=1 如果使用InnoDb，为了保证稳定，还应设置如下两行： innodb_flush_log_at_trx_commit=1 sync_binlog=1 并且确保没有设置skip-networking，禁用网络自然无法同步。但是，innodb_flush_log_at_trx_commit=1在某些服务器上会导致写数据速度急剧下降，可尝试调整为2。 用户 每个从服务器都要使用标准的mysql用户来连接主服务器，对应的权限名称为REPLICATION SLAVE(这是一个和库无关的权限，属于服务器管理权限的一种)。虽然使用独立用户并不是必需的，但由于用户名和密码都将以明文方式存储在记录replication相关信息的master.info文件中，还是采用独立用户更安全一些。语法如下： mysql&#62; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.domain.tld' IDENTIFIED BY 'passwd'; 从服务器的my.cnf设置 server-id是必须设置的，binlog不用开。 获取主服务器的同步信息 从服务器必须知道要从主服务器binlog的哪个位置开始进行同步，相当于有一份数据、一份要执行的指令（binlog）以及一个当前执行哪一条指令，要获得这三个信息，必须临时暂停主服务器上的处理： mysql&#62; FLUSH TABLES WITH READ LOCK; （这个连InnoDB的commit都能停住），暂停状态下数据、指令就都不会变了，查询出当前记录的binlog的位置： mysql &#62; SHOW MASTER STATUS; [...]]]></description>
			<content:encoded><![CDATA[<p>这篇算是我的学习笔记，主要内容都来自<a href="http://dev.mysql.com/doc/refman/5.1/en/replication.html">mysql官方文档</a>，然后参考一些网上的文章自己实践了个例子，所以内容上前后也有些重复。</p>

<p>mysql支持从一个主服务器到多个从服务器的复制，并且复制是异步的，也就是说从服务器不用一直保持与主服务器的连接，这使得一些远程、临时性的节点也能进行同步。同时，还可以指定参与同步的数据库或者数据表。</p>

<p>同步目前主要用于以下几个方面：</p>

<ul>
<li>架构扩容，一主写多从读的方式已经用得非常普遍了</li>
<li>数据安全，同步也是一种备份，而且还可以是实时的，多好啊</li>
<li>数据分析，大量的分析运算在从服务器上运行，不影响主系统的负载</li>
<li>远程数据发布，或者说远程备份</li>
</ul>

<h2>同步的基本设置</h2>

<h3>主服务器的my.cnf设置</h3>

<p>同步是通过binlog来实现的，虽然主服务器不能决定哪些操作在binlog中记录（默认记录全部），但从服务器可以根据配置来有选择的执行。每个主、从服务器都要有一个唯一ID，从服务器还要记录主服务器的主机名、log文件名以及位置等信息（在master.info中），并保存一份收到的binlog，这样多台从服务器就可以有不同的同步状态或进度，并且下次连线的时候再以“续传”的方式继续同步进程。binlog的开启需要修改主服务器的<code>my.cnf</code></p>

<pre><code># 必须写在[mysqld]节里面
[mysqld]
# mysql-bin是log文件的前缀，也可以使用其它的名字，比如服务器名
# 如果不带路径，会把log文件写到`/var/lib/mysql`下
log-bin=mysql-bin
# serverid在一个同步体系中必须是唯一的，大于等于1且小于2^32-1的整数
server-id=1
</code></pre>

<p>如果使用InnoDb，为了保证稳定，还应设置如下两行：</p>

<pre><code>innodb_flush_log_at_trx_commit=1
sync_binlog=1
</code></pre>

<p>并且确保没有设置<code>skip-networking</code>，禁用网络自然无法同步。但是，<code>innodb_flush_log_at_trx_commit=1</code>在某些服务器上会导致写数据速度急剧下降，可尝试调整为2。</p>

<h3>用户</h3>

<p>每个从服务器都要使用标准的mysql用户来连接主服务器，对应的权限名称为<code>REPLICATION SLAVE</code>(这是一个和库无关的权限，属于服务器管理权限的一种)。虽然使用独立用户并不是必需的，但由于用户名和密码都将以明文方式存储在记录replication相关信息的<code>master.info</code>文件中，还是采用独立用户更安全一些。语法如下：</p>

<pre><code>mysql&gt; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.domain.tld' IDENTIFIED BY 'passwd';
</code></pre>

<h3>从服务器的my.cnf设置</h3>

<p><code>server-id</code>是必须设置的，binlog不用开。</p>

<h3>获取主服务器的同步信息</h3>

<p>从服务器必须知道要从主服务器binlog的哪个位置开始进行同步，相当于有一份数据、一份要执行的指令（binlog）以及一个当前执行哪一条指令，要获得这三个信息，必须临时暂停主服务器上的处理：</p>

<pre><code>mysql&gt; FLUSH TABLES WITH READ LOCK;
</code></pre>

<p>（这个连InnoDB的commit都能停住），暂停状态下数据、指令就都不会变了，查询出当前记录的binlog的位置：</p>

<pre><code>mysql &gt; SHOW MASTER STATUS;
</code></pre>

<p>得到的File列是当前的binlog记录文件名，Position就是日志记录，如果还没东西可记，File为空字符串而Position为4。后面设置从服务器的时候，<code>CHANGE MASTER TO</code>命令就要用到这些信息，比如：</p>

<pre><code>mysql&gt; CHANGE MASTER TO
    -&gt;     MASTER_HOST='master_hostname',
    -&gt;     MASTER_USER='repl_username',
    -&gt;     MASTER_PASSWORD='repl_password',
    -&gt;     MASTER_LOG_FILE='binlog_filename',
    -&gt;     MASTER_LOG_POS=binlog_position;
</code></pre>

<h3>复制主服务器的数据到从服务器</h3>

<p>保持主服务器的暂停处理状态，先把数据都弄到从服务器上去。导出可以用mysqldump：</p>

<pre><code>mysqldump -h db_host --add-drop-table --default-character-set=utf8 --user=root -pPASSWD --extended-insert=false db_name &gt; db_name.sql
</code></pre>

<p>带上<code>--all-databases</code>参数可以导出所有库，不过不想参与同步的库是没必要导的。如果带上<code>--master-data</code>参数，还能够把从服务器设置的一些sql一并导出来。</p>

<p>当然，直接拷贝数据库文件也是可以的，速度也更快，但如果在mysql服务启动的状态下拷贝，可能会存在缓存、日志不同步的情况，所以要停掉服务以后再拷贝，并且不要拷贝和目标库无关的日志等文件。</p>

<p>为了进一步保证数据的一致性，可以在导出数据前给所有数据加锁：</p>

<pre><code>mysql&gt; FLUSH TABLES WITH READ LOCK;
</code></pre>

<p>导出完成后再解开：</p>

<pre><code>mysql&gt; UNLOCK TABLES;
</code></pre>

<h2>同步的进阶说明</h2>

<h3>binlog的几种形式</h3>

<p>一种是记录所操作的“命令”（mysql 5.1.4前版本只能用这个），简称为命令复制SBR；另外一种是记录所有受影响的行，简称为行复制RBR。从mysql 5.1.8开始支持包含上述两种方式的混合型日志。命令复制的优点是：</p>

<ul>
<li>产生的日志小</li>
<li>不要求每个表都要有主键</li>
</ul>

<p>缺点是：</p>

<ul>
<li>某些函数的返回值是无法复制的（比如LOAD_FILE(), UUID(), UUID_SHORT(), USER(), FOUND_ROWS(), SYSDATE()，但RAND(), NOW()能正常复制）</li>
<li>写数据时用到的锁较多</li>
<li>主从服务器的表必须一样</li>
</ul>

<p>行复制的优点为：</p>

<ul>
<li>最安全，所有的操作都能记录和同步</li>
<li>写数据的时候使用到的锁较少</li>
</ul>

<p>缺点为：</p>

<ul>
<li>写大量数据时（比如全表UPDATE）日志里要写很多东西，日志锁定时间也相对更长，可能会带来一些并发问题</li>
<li>所有的表必须要有显式主键（一般情况下都会有主键的，除非超大数据量或特殊设计）</li>
<li>带有大文本的数据复制可能要慢一些，这个好理解，一个update操作，如果是行复制的话，肯定是更新了n行，复制传递的数据量就是n倍大小</li>
<li>查看更新传递和执行的进度不方便</li>
<li>无法用<code>WHERE @server_id &lt;&gt;  server-id</code>这个小技巧来临时指定只更新某台服务器</li>
</ul>

<p>在具体处理的时候，依然会有一些操作比如GRANT REVOKE之类是用命令方式同步的。总体来讲，经常要进行大量数据变更的情况下，命令复制似乎更合适一些。</p>

<h3>常用配置参数说明</h3>

<p>控制主服务器的：</p>

<ul>
<li>auto_increment_increment, auto_increment_offset 自增主键的跳号间隔和初始值，有什么用呢？有人作双向复制的时候，设置A服务器主键自增从1开始每次跳10，B服务器则从2开始每次跳10，这样双向复制的过程中就不会产生自增主键重号的问题了。这两个是全局而非针对某表的设置。不过我更倾向于用UUID实现。</li>
<li>slave_exec_mode 从服务器容错方式，5.1.24后版本才有。</li>
</ul>

<p>控制从服务器的：</p>

<ul>
<li>master.info中配置的优先级比my.cnf中的高。</li>
<li>log-slave-updates 从服务器的变更也记入日志，作链式复制时必须。</li>
<li>replicate-do-db=db_name 只复制指定数据库，可以写多行来指定复制多个库。注意在命令复制模式下mysql只认用<code>use db_name</code>选定的，不会从跨表操作的sql中自动判断；而行复制则是依照实际变更的数据属于哪个表来判断。</li>
<li>replicate-rewrite-db=&#8221;from_name->to_name&#8221; 主、从数据库名称不一样的时候，用此命令进行转换。</li>
</ul>

<p>控制日志的：</p>

<ul>
<li>binlog_format 日志类型，ROW或STATEMENT，新版中还可选MIXED。</li>
<li>log-bin[=base_name] 开启二进制日志（复制必须），可以指定日志文件名。</li>
<li>sync_binlog 什么时候写日志到磁盘，这个机制比较复杂，一般设为1相对较安全。</li>
</ul>

<h3>同步的管理</h3>

<p>有一些命令：</p>

<ul>
<li>SHOW SLAVE STATUS 在从服务器上查看状态。</li>
<li>SHOW SLAVE HOSTS 在主服务器上，启用了report-host以后，显式已连接的从服务器。</li>
<li>STOP/START SLAVE [IO_THREAD/SQL_THREAD] 在从服务器上，停止复制（的日志下载/SQL执行操作）。</li>
</ul>

<h2>同步实现实例</h2>

<p>复制还是在局域网内方便，尤其是双向复制，因为跨公网的话不光要连进去，还要从里面连出来。
综合考虑，M-M-Slaves的模式的一般适用性可能更强一些。下面以Master-Master简要举例：</p>

<p>首先分别修改M1/2的my.cnf：</p>

<pre><code>[mysqld]
# Replication
server-id=1/2
log-bin=/var/log/mysql/svr1/2
log-error=/var/log/mysql.err
relay-log=/var/log/mysql/svr1/2-relay
binlog_format='STATEMENT'
sync_binlog=1
log-slave-updates
innodb_flush_log_at_trx_commit=2
binlog-do-db=db_to_replicate

master-host=ip_of_M1/2
master-port=port_of_M1/2
master-user=rep
master-password=passwd
master-connect-retry = 60
replicate-do-db=db_to_replicate
</code></pre>

<p>然后在M1/2上创建同步用户：</p>

<pre><code>mysql&gt; grant replication slave on *.* to 'rep'@'%' identified by 'passwd';
</code></pre>

<p>重启M1/2的mysql服务,并停止slave：</p>

<pre><code>mysql&gt; stop slave;
</code></pre>

<p>下面，把数据从M1上复制到M2上，先在M1上：</p>

<pre><code>mysql&gt; use db_to_replicate;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql&gt; flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)

mysql&gt; show master status;
+-------------+----------+--------------+------------------+
| File        | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------+----------+--------------+------------------+
| svr5.000002 |       98 | db_to_replicate   |                  | 
+-------------+----------+--------------+------------------+
1 row in set (0.00 sec)
</code></pre>

<p>目的是锁上M1上所有表（为只读状态），并记下当前binlog的记录位置。然后不要退出mysql，另外开一个session，导出数据：</p>

<pre><code>$ mysqldump -h 127.0.0.1 --add-drop-table --default-character-set=utf8 --user=root -p --extended-insert=false --skip-lock-tables db_to_replicate &gt; db_to_replicate.sql
</code></pre>

<p>mysqldump时用参数指定不再次加锁，也可以采用直接拷贝数据库文件的方式（导入时更快，也得更小心一点）。导出完成后可以解锁，让M1正常运行了：</p>

<pre><code>mysql&gt; unlock tables;
</code></pre>

<p>现在到M2上去，用刚才导出的数据把库建起来（如果采用直接执行sql的方式，记得先停掉binlog），然后进行比较重要的一步，让M2从M1刚才导出数据的时候开始恢复同步：</p>

<pre><code>mysql&gt; stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql&gt; CHANGE MASTER TO MASTER_HOST='ip_of_M1', MASTER_PORT=port_of_M1, MASTER_USER='rep', MASTER_PASSWORD='passwd', MASTER_LOG_FILE='svr5.000002', MASTER_LOG_POS=98;
Query OK, 0 rows affected (0.01 sec)

mysql&gt; start slave;
Query OK, 0 rows affected (0.01 sec)
</code></pre>

<p>最后两个参数就是刚才在M1上用<code>show master status;</code>得到的数值。</p>

<p>同理，在M1上也作一次<code>CHANGE MASTER TO</code>操作，指向M2，两边的双向主主复制基本上就算是完成。</p>

<p>另外注意以后切换MASTER的时候，直接修改my.cnf是不行的，因为都存到优先级更高的master.info文件中去了，还是用<code>CHANGE MASTER TO</code>来操作更靠谱。</p>

<h2>通过ssh进行远程同步的连接方法</h2>

<p>以M2远程登录M1的方式为例，M2 ssh到M1，以便M2作为slave能连接master M1，使用的是ssh隧道：</p>

<pre><code>M2 $  ssh -p 8022 -L 127.0.0.1:3307:ip_of_M1:3306 -CfNg user@domain.tld -o ControlPath=/tmp/ssh-mysql-3307-M1-3306
</code></pre>

<p>双向同步时，M1还要连接到M2才行，依然是从M2上来打洞：</p>

<pre><code>M2 $ ssh -p 8022 -R 0.0.0.0:3307:localhost:3306 user@domain.tld -fN -o ControlPath=/tmp/ssh-mysql-3307-local-3306
</code></pre>

<p>注意在建立这些ssh隧道的时候，一般不能使用<a href="385">ssh的连接共享</a>。</p>

<h4>Update @ 2009-03-16</h4>

<p>马上就遇到了innodb启用了<code>innodb_file_per_table</code>之后，直接拷贝<code>.ibd</code>文件过来不生效的问题，并且是在建立好M-M复制之后，如此这般（M1是旧服务器，M2上把文件拷贝过来导入的服务器）（补注：依然失败）：</p>

<ul>
<li>M1: 确认所有同步内容已经处理完毕。</li>
<li>M1: stop slave;</li>
<li>M2: flush tables with read lock;</li>
<li>M2: 备份mysql data目录下相应库的所有文件（就是拷贝过来的那些），并且删除掉（db.opt不要删）。</li>
<li>M2: unlock tables; 不然下面的操作无法进行。</li>
<li>M2: 使用其它手段重新创建所有表，数据不需要。</li>
<li>M2: show master status; 得到位置后面要用到。</li>
<li>M2: flush tables with read lock; 准备用拷贝过来的ibd覆盖刚才用sql重新创建的表，这样数据就有了。</li>
<li>M2: 复制/拷贝/恢复刚才备份的所有<code>.frm, .ibd</code>文件。</li>
<li>M2: unlock tables; M2恢复正常。</li>
<li>M1: CHANGE MASTER TO MASTER_HOST=&#8217;ip_of_M2&#8242;, MASTER_PORT=port_of_M2, MASTER_USER=&#8217;rep&#8217;, MASTER_PASSWORD=&#8217;passwd&#8217;, MASTER_LOG_FILE=&#8217;fwolf-office.000101&#8242;, MASTER_LOG_POS=57943; 目的是跳过刚才那些重新建表的处理。</li>
<li>M1: start slave; M1恢复正常。</li>
</ul>

<p>至于原因嘛，因为拷贝过来的都是ibd文件，而innodb的schema信息都存在系统表INFORMATION_SCHEMA里，偏偏这个系统表又是只读的，所以只能重新建一遍库了。</p>

<p>还遇到了特定名称的库无法创建的情况，会提示<code>.frm</code>无法创建之类的，可以这样处理：创建失败后，从其它库中建一个名称相同的，然后把<code>.frm, .ibd</code>文件拷贝过来，然后执行<code>drop table XXX</code>，然后就能正常创建、删除了。</p>

<p>&#8230;&#8230;慢，表都能看到了，可哪个里面都没有数据，还是不行，看来innodb迁移到其它服务器，尤其是配置不同、使用状态不同的情况下，还真不是一般的麻烦，我还是老老实实改用mysqldump得了，删库重建再导入，慢也就慢这一次而已。大体过程：</p>

<ul>
<li>M1: stop slave;</li>
<li>M1: dump all data:
mysqldump -h ip_of_M1 &#8211;add-drop-table &#8211;default-character-set=utf8 &#8211;user=root -p &#8211;extended-insert=true &#8211;net_buffer_length=600k&#8211;skip-lock-tables db_to_replicate > db_to_replicate.sql</li>
<li>M2: delete database &amp; recreate it</li>
<li>M2: 执行刚才的sql，导入数据，最好先关闭binlog</li>
<li>M2: stop slave;</li>
<li>M1/2上分别<code>change master to, start slave;</code></li>
</ul>

<p>如果遇到这样的错误：</p>

<pre><code>ERROR 1201 (HY000): Could not initialize master info structure; more error messages can be found in the MySQL error log
</code></pre>

<p>可以在<code>CHANGE MASTER TO</code>之前先<code>RESET SLAVE;</code>。</p>

<h4>参考</h4>

<ul>
<li><a href="http://java.dzone.com/articles/better-mysql-replication">A Better MySQL Replication Heartbeat(利用SYSDATE和NOW在同步时不同的处理机制，实现主从服务器延迟的心跳检查)</a></li>
<li><a href="http://www.onlamp.com/pub/a/onlamp/2006/04/20/advanced-mysql-replication.html?page=1">Advanced MySQL Replication Techniques（环式多主复制）</a></li>
<li><a href="http://www.howtoforge.com/setting-up-master-master-replication-on-four-nodes-with-mysql-5-on-debian-etch">Setting Up Master-Master Replication On Four Nodes With MySQL 5 On Debian Etch</a></li>
<li><a href="http://www.xaprb.com/blog/2007/01/20/how-to-make-mysql-replication-reliable/">How to make MySQL replication reliable</a></li>
<li><a href="http://capttofu.livejournal.com/1752.html">MySQL Multi-Master Replication</a></li>
<li><a href="http://imysql.cn/node/314">[MySQL 5.1 体验]MySQL 复制</a></li>
<li><a href="http://www.howtoforge.com/mysql_master_master_replication">MySQL Master Master Repliction Tutorial </a></li>
<li><a href="http://imysql.cn/2008_12_17_migrate_innodb_tablespace_smoothly">InnoDB数据表空间文件平滑迁移</a></li>
<li><a href="http://www.chriscalender.com/?p=28">Recovering an InnoDB table from only an .ibd file.(介绍了手工修改ibd文件编号的方法，危险，我试了不成功)</a></li>
</ul>

	Tags: <a href="http://www.fwolf.com/blog/post/tag/innodb" title="innodb" rel="tag">innodb</a>, <a href="http://www.fwolf.com/blog/post/tag/migration" title="migration" rel="tag">migration</a>, <a href="http://www.fwolf.com/blog/post/tag/mysql" title="mysql" rel="tag">mysql</a>, <a href="http://www.fwolf.com/blog/post/tag/replication" title="replication" rel="tag">replication</a><br />

	<h4>Related posts</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.fwolf.com/blog/post/428" title="升级到Ubuntu Intrepid后感觉到的一些变化 (2009-01-06)">升级到Ubuntu Intrepid后感觉到的一些变化</a> (0)</li>
	<li><a href="http://www.fwolf.com/blog/post/404" title="忙碌的5月 (2008-06-13)">忙碌的5月</a> (10)</li>
	<li><a href="http://www.fwolf.com/blog/post/369" title="在无线网络中使用RADIUS服务器+mysql进行用户认证 (2007-11-15)">在无线网络中使用RADIUS服务器+mysql进行用户认证</a> (0)</li>
	<li><a href="http://www.fwolf.com/blog/post/383" title="[MediaTemple]虚拟主机内存优化的一点心得 (2008-02-19)">[MediaTemple]虚拟主机内存优化的一点心得</a> (2)</li>
	<li><a href="http://www.fwolf.com/blog/post/412" title="[MediaTemple]从(dv)3.0升级到3.5 (2008-07-13)">[MediaTemple]从(dv)3.0升级到3.5</a> (1)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.fwolf.com/blog/post/435/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Firefox3书签中的Tags存哪儿了？</title>
		<link>http://www.fwolf.com/blog/post/398</link>
		<comments>http://www.fwolf.com/blog/post/398#comments</comments>
		<pubDate>Mon, 21 Apr 2008 16:02:02 +0000</pubDate>
		<dc:creator>Fwolf</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[schema]]></category>
		<category><![CDATA[sqlite]]></category>
		<category><![CDATA[tag]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/?p=398</guid>
		<description><![CDATA[电脑岁数大了是不行，即使装上了号称速度有很大改观的Firefox3，我的老爷机也没快到哪儿去，这还是在一大票插件都由于不兼容被咔嚓了之后，唉。 不过Firefox3还是有些不错的新功能的，比如网址栏中的“星星”，和Gmail里面的哪个很像吧，不知道是谁家的专利，这个星星挺有意思，当你浏览到觉得不错的网站时，点一下星星就可以收藏起来了，默认是在书签的Unfiled Bookmarks文件夹中，以后可以慢慢整理；点两下星星会弹出窗口让你选保存位置，并可以输Tag。 Tag可以说是Web 2.0的标志性特征了，也是组织和查找信息的一种有效方式，所以我就很感兴趣，这个Tags被Firefox3存到哪个文件里去了？Tag的存储方式和Tag Cloud的算法我很感兴趣，也想看看FF的解决方式。 一般Firefox会把书签保存在bookmarks.html文件当中，不过Firefox3改进了，把书签放到了sqlite数据库中，文件名就叫做places.sqlite。这个文件在Firefox3运行时会以独占方式打开，关闭FF后才能用sqlite3打开。 起初没想到有什么难处，直接看schema，结果仔细的读了一遍也没发现哪些地方有tag的踪影： moz_anno_attributes 注释的属性，没几行数据，不知道干啥的 moz_annos 目前是空的，应该是什么的注释 moz_bookmarks 书签项目 moz_bookmarks_roots 书签项目的根网站集合，新安装FF的还没数据呢 moz_favicons 网站图标favicon的位置 moz_historyvisits 哪个网站你浏览了多少次，偶的隐私啊。。。 moz_inputhistory 输入历史？暂无数据 moz_items_annos 书签的注释，也就是那个“Description:” moz_keywords 关键字，和“Description:”在一个界面输入，没啥用处 moz_places 所有浏览的地址历史 看吧，没哪个表是和tag有什么关联的，可用grep一查，我标记的tag确实是在这个文件中，只好出绝招： sqlite3 places.sqlite ".dump" &#62; t.sql 然后在t.sql里面一查找，终于明白了： INSERT INTO "moz_bookmarks" VALUES(346,2,NULL,4,2,'testtag',NULL,'',1208788891265751,1208788891362043); INSERT INTO "moz_bookmarks" VALUES(347,1,638,346,0,NULL,NULL,NULL,1208788891361294,NULL); tag就是存在了moz_bookmarks这个表中，和书签的记录混在一起。像上面这种情况，每个tag除了自身占一行记录之外，如果有几个书签被标记了这个tag，那么就还会多出几条记录tag-书签关联关系的记录。 窃以为这并不是存储tag的最佳方式，而且FF在tag的使用上也太简单了，目前看到的就是一个Smart Bookmarks里能按常用tag查网站，连Tag Cloud也没有。一是不知道以后的tag数据格式是否会改变，二是应该会有扩展来完善这块功能，期待吧。 Tags: Database, Firefox, schema, sqlite, tag Related posts [...]]]></description>
			<content:encoded><![CDATA[<p>电脑岁数大了是不行，即使装上了号称速度有很大改观的Firefox3，我的老爷机也没快到哪儿去，这还是在一大票插件都由于不兼容被咔嚓了之后，唉。</p>

<p>不过Firefox3还是有些不错的新功能的，比如网址栏中的“星星”，和Gmail里面的哪个很像吧，不知道是谁家的专利，这个星星挺有意思，当你浏览到觉得不错的网站时，点一下星星就可以收藏起来了，默认是在书签的<code>Unfiled Bookmarks</code>文件夹中，以后可以慢慢整理；点两下星星会弹出窗口让你选保存位置，并可以输Tag。</p>

<p>Tag可以说是Web 2.0的标志性特征了，也是组织和查找信息的一种有效方式，所以我就很感兴趣，这个Tags被Firefox3存到哪个文件里去了？Tag的存储方式和Tag Cloud的算法我很感兴趣，也想看看FF的解决方式。</p>

<p>一般Firefox会把书签保存在bookmarks.html文件当中，不过Firefox3改进了，把书签放到了sqlite数据库中，文件名就叫做<code>places.sqlite</code>。这个文件在Firefox3运行时会以独占方式打开，关闭FF后才能用sqlite3打开。</p>

<p>起初没想到有什么难处，直接看schema，结果仔细的读了一遍也没发现哪些地方有tag的踪影：</p>

<ul>
<li>moz_anno_attributes 注释的属性，没几行数据，不知道干啥的</li>
<li>moz_annos 目前是空的，应该是什么的注释</li>
<li>moz_bookmarks 书签项目</li>
<li>moz_bookmarks_roots 书签项目的根网站集合，新安装FF的还没数据呢</li>
<li>moz_favicons 网站图标favicon的位置</li>
<li>moz_historyvisits 哪个网站你浏览了多少次，偶的隐私啊。。。</li>
<li>moz_inputhistory 输入历史？暂无数据</li>
<li>moz_items_annos 书签的注释，也就是那个“Description:”</li>
<li>moz_keywords 关键字，和“Description:”在一个界面输入，没啥用处</li>
<li>moz_places 所有浏览的地址历史</li>
</ul>

<p>看吧，没哪个表是和tag有什么关联的，可用grep一查，我标记的tag确实是在这个文件中，只好出绝招：</p>

<pre><code>sqlite3 places.sqlite ".dump" &gt; t.sql
</code></pre>

<p>然后在t.sql里面一查找，终于明白了：</p>

<pre><code>INSERT INTO "moz_bookmarks" VALUES(346,2,NULL,4,2,'testtag',NULL,'',1208788891265751,1208788891362043);
INSERT INTO "moz_bookmarks" VALUES(347,1,638,346,0,NULL,NULL,NULL,1208788891361294,NULL);
</code></pre>

<p>tag就是存在了<code>moz_bookmarks</code>这个表中，和书签的记录混在一起。像上面这种情况，每个tag除了自身占一行记录之外，如果有几个书签被标记了这个tag，那么就还会多出几条记录tag-书签关联关系的记录。</p>

<p>窃以为这并不是存储tag的最佳方式，而且FF在tag的使用上也太简单了，目前看到的就是一个<code>Smart Bookmarks</code>里能按常用tag查网站，连Tag Cloud也没有。一是不知道以后的tag数据格式是否会改变，二是应该会有扩展来完善这块功能，期待吧。</p>

	Tags: <a href="http://www.fwolf.com/blog/post/tag/database" title="Database" rel="tag">Database</a>, <a href="http://www.fwolf.com/blog/post/tag/firefox" title="Firefox" rel="tag">Firefox</a>, <a href="http://www.fwolf.com/blog/post/tag/schema" title="schema" rel="tag">schema</a>, <a href="http://www.fwolf.com/blog/post/tag/sqlite" title="sqlite" rel="tag">sqlite</a>, <a href="http://www.fwolf.com/blog/post/tag/tag" title="tag" rel="tag">tag</a><br />

	<h4>Related posts</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.fwolf.com/blog/post/396" title="ADOdb的数据字典功能及其它 (2008-04-13)">ADOdb的数据字典功能及其它</a> (0)</li>
	<li><a href="http://www.fwolf.com/blog/post/428" title="升级到Ubuntu Intrepid后感觉到的一些变化 (2009-01-06)">升级到Ubuntu Intrepid后感觉到的一些变化</a> (0)</li>
	<li><a href="http://www.fwolf.com/blog/post/402" title="升级WP旧模板，让它支持Widgets (2008-05-11)">升级WP旧模板，让它支持Widgets</a> (4)</li>
	<li><a href="http://www.fwolf.com/blog/post/152" title="[Ubuntu]使用点滴 (2006-07-08)">[Ubuntu]使用点滴</a> (7)</li>
	<li><a href="http://www.fwolf.com/blog/post/366" title="WordPress升级到2.3.1 (2007-11-02)">WordPress升级到2.3.1</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.fwolf.com/blog/post/398/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ADOdb的数据字典功能及其它</title>
		<link>http://www.fwolf.com/blog/post/396</link>
		<comments>http://www.fwolf.com/blog/post/396#comments</comments>
		<pubDate>Sat, 12 Apr 2008 16:19:03 +0000</pubDate>
		<dc:creator>Fwolf</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[adodb]]></category>
		<category><![CDATA[axmls]]></category>
		<category><![CDATA[dict]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[record]]></category>
		<category><![CDATA[schema]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/?p=396</guid>
		<description><![CDATA[在新项目中继续使用ADOdb，这个是没什么悬念的了，尝试过php5自带的pdo，感觉一般，对某些数据库的支持更一般。但是数据库结构如何维护这块放不下心，从以往的开发中看，系统开发维护期超过半年之后，如果在数据库schema管理上不下点功夫，在生产服务器和多个测试服务器以及sql结构之间，难免会产生schema不一致的情况，管理情况再差的，连最后一稿schema是哪个、以及schema注释都能丢失。所以，无意中瞥到ADOdb还有一个ADOdb Data Dictionary Library for PHP以后，就想看看这个能否用在多环境数据库schema同步方面，连同自己了解的一些其它情况，记录在这里。 ADOdb Data Dictionary Library for PHP 可以用简单的字符串或者数组的方式记录数据表的结构，然后调用相关功能来生成修改数据库的sql语句，并执行之。应该是在创建数据表方面还是非常方便的，虽然数据类型简单了一些，执行和调用也略显麻烦（抱歉我的确是这么认为的），但在简单的应用中，尤其是数据表修改不是很多的情况下，应该会很好用。 ADOdb XML Schema (AXMLS) 这个其实也是包含在ADOdb中的，其介绍也是直接列在了ADOdb Data Dictionary Library for PHP同一页的下方。在仔细把这段并不多的内容读完之后，我是半喜半忧，喜的是AXMLS这个东西可真好啊，相当于能够把整个数据库的schema xml化了，然后对实体数据库进行更新；忧的方面一是，在最新的ADOdb5.04当中，依然没有完全实现AXMLS中的全部功能，我建了一个简单的xml，其中带有一句： &#60;opt platform="mysql"&#62;TYPE=INNODB&#60;/opt&#62; 然后在一个空的数据库上执行，输出sql，发现CREATE TABLE的sql中并没有带上ENGINE=InnoDB，所以就停止了尝试；忧的方面二是这么好的东西，它的官方网站上最新的消息却是2004年6月17号的，一个软件不可能在4年中一点都没有改动，况且那时候还没有php5呢吧。在互联网其它方面来搜索这个AXMLS，发现只是在adodb中有，并没有在其它项目中得到运用，可惜了了。 一些商业软件的实现 很多商业软件的数据库schema管理一般都在case工具中，也有生成sql甚至直接对数据库应用schema变更的功能，比如我以前使用的PowerDesigner，不仅是最好的数据库实体模型设计工具，而且设计完成后，直接连上数据库进行更新。也可以反过来，从实体数据库中分析出数据库模型。 东西是好东西，可用了一段时间不再想用下去了，原因是多方面的，一是Sybase的东西bug总是很多，有时候莫名其妙的错误提示很头疼，二是数据库大了以后，每次连线diff的时候都很慢，最要命的是，它在更改column时喜欢用临时表，然后删除原表建新表，再从临时表中把数据读回来，一旦这个过程由于数据库兼容问题或者其它原因被中断，下次再同步的时候，很有可能数据库结构更新了，而数据却丢失了，因为它有自动删除临时表的选项，并且一般大家还都需要打开这个选项；最后一个原因，这玩意儿既没有Linux版本，我也没有正版的授权，所以能下岗就下岗了。 自己用简单的脚本来实现 其实在实际的应用开发中，数据库相关要修改的地方会很多，不仅有表、索引、视图等数据库本身的元素，还可能会有一些数据的调整和处理，比如将表中的A、B字段去掉，他们的值相加存储在一个新的C字段中，如果说前者应该会有成型的工具能够实现的话，像后面所说的这种数据库，或者更准确一点说是数据调整在任何工具中都不会涉及到的。 反过来想，无论是对数据库如何进行操作，无外乎就是DDL数据库定义语言和DML数据库管理语言，也就是通过大家常说的SQL语句来操作，那么把这些简化为一个SQL语句集合，就可以将开发过程中所有的数据库变动转化为这一系列SQL语句的管理和执行，设计这样一个工具不就得了么？ 我现在就是这么作的，在svn中除了有保存数据库最终状态的schema sql文件之外，还专门有一个php文件，用数组记录每一次需要对数据库调整的SQL，然后有一个执行记录表，记录哪些SQL执行过而哪些没有。这个执行记录表在每个数据库实例中都会创建，这样，我只需要简单的调整数据库连接参数，然后就可以通过执行php代码，依次逐个的执行每个SQL了。 有一个缺点，就是SQL语法太依赖具体的数据库类型了，没办法，好在更换数据库的情形并不多，平时尽量写标准的语法吧。另外真要转换数据库的时候，还可以另起炉灶嘛。 其它的开源软件都是怎么实现的呢？ 我阅读过的开源软件源码并不多，但软件还是用了一些，在有些软件升级的时候，就会自动将数据库也升级了，他们都是怎么实现的呢？难道说只是在1.0升级到2.0的升级程序upgrade.php中，固定的、一次性执行数据库修改么？ 关于同类数据备份和迁移 以前一个朋友用oracle数据库的时候，特别喜欢用tora（他管它叫蛤蟆，因为软件的about页上有只蛤蟆），但我却认为，在同类数据库，尤其是版本、配置相同的数据库之间进行数据转移，方便一点的方法是利用数据库的导出、导入功能，这样不会有DML覆盖范围以外的内容拉下，简单一点的，自己写个小程序，连上两个数据库，这边读来那边写，也不会慢到哪里去，想提前删个索引什么的也好控制。tora一类的工具，应该是在灌初始字典库的时候用最合适。另外，不是还有bcp么？ 参考 用 AWK 实现 DB2 数据库 Schema 的同步 ClearQuest问题及其解决办法 使用impdp复制oracle的schema数据迁移 CQ数据库的备份与恢复[心得] Tags: adodb, axmls, [...]]]></description>
			<content:encoded><![CDATA[<p>在新项目中继续使用<a href="http://adodb.sourceforge.net/">ADOdb</a>，这个是没什么悬念的了，尝试过php5自带的pdo，感觉一般，对某些数据库的支持更一般。但是数据库结构如何维护这块放不下心，从以往的开发中看，系统开发维护期超过半年之后，如果在数据库schema管理上不下点功夫，在生产服务器和多个测试服务器以及sql结构之间，难免会产生schema不一致的情况，管理情况再差的，连最后一稿schema是哪个、以及schema注释都能丢失。所以，无意中瞥到<a href="http://adodb.sourceforge.net/">ADOdb</a>还有一个<a href="http://phplens.com/lens/adodb/docs-datadict.htm">ADOdb Data Dictionary Library for PHP</a>以后，就想看看这个能否用在多环境数据库schema同步方面，连同自己了解的一些其它情况，记录在这里。</p>

<h3>ADOdb Data Dictionary Library for PHP</h3>

<p>可以用简单的字符串或者数组的方式记录数据表的结构，然后调用相关功能来生成修改数据库的sql语句，并执行之。应该是在创建数据表方面还是非常方便的，虽然数据类型简单了一些，执行和调用也略显麻烦（抱歉我的确是这么认为的），但在简单的应用中，尤其是数据表修改不是很多的情况下，应该会很好用。</p>

<h3>ADOdb XML Schema (AXMLS)</h3>

<p>这个其实也是包含在<a href="http://adodb.sourceforge.net/">ADOdb</a>中的，其介绍也是直接列在了<a href="http://phplens.com/lens/adodb/docs-datadict.htm">ADOdb Data Dictionary Library for PHP</a>同一页的下方。在仔细把这段并不多的内容读完之后，我是半喜半忧，喜的是AXMLS这个东西可真好啊，相当于能够把整个数据库的schema xml化了，然后对实体数据库进行更新；忧的方面一是，在最新的<a href="http://adodb.sourceforge.net/">ADOdb</a>5.04当中，依然没有完全实现AXMLS中的全部功能，我建了一个简单的xml，其中带有一句：</p>

<pre><code>&lt;opt platform="mysql"&gt;TYPE=INNODB&lt;/opt&gt;
</code></pre>

<p>然后在一个空的数据库上执行，输出sql，发现<code>CREATE TABLE</code>的sql中并没有带上<code>ENGINE=InnoDB</code>，所以就停止了尝试；忧的方面二是这么好的东西，它的<a href="http://adodb-xmlschema.sourceforge.net/">官方网站</a>上最新的消息却是2004年6月17号的，一个软件不可能在4年中一点都没有改动，况且那时候还没有php5呢吧。在互联网其它方面来搜索这个AXMLS，发现只是在adodb中有，并没有在其它项目中得到运用，可惜了了。</p>

<h3>一些商业软件的实现</h3>

<p>很多商业软件的数据库schema管理一般都在case工具中，也有生成sql甚至直接对数据库应用schema变更的功能，比如我以前使用的PowerDesigner，不仅是最好的数据库实体模型设计工具，而且设计完成后，直接连上数据库进行更新。也可以反过来，从实体数据库中分析出数据库模型。</p>

<p>东西是好东西，可用了一段时间不再想用下去了，原因是多方面的，一是Sybase的东西bug总是很多，有时候莫名其妙的错误提示很头疼，二是数据库大了以后，每次连线diff的时候都很慢，最要命的是，它在更改column时喜欢用临时表，然后删除原表建新表，再从临时表中把数据读回来，一旦这个过程由于数据库兼容问题或者其它原因被中断，下次再同步的时候，很有可能数据库结构更新了，而数据却丢失了，因为它有自动删除临时表的选项，并且一般大家还都需要打开这个选项；最后一个原因，这玩意儿既没有Linux版本，我也没有正版的授权，所以能下岗就下岗了。</p>

<h3>自己用简单的脚本来实现</h3>

<p>其实在实际的应用开发中，数据库相关要修改的地方会很多，不仅有表、索引、视图等数据库本身的元素，还可能会有一些数据的调整和处理，比如将表中的A、B字段去掉，他们的值相加存储在一个新的C字段中，如果说前者应该会有成型的工具能够实现的话，像后面所说的这种数据库，或者更准确一点说是数据调整在任何工具中都不会涉及到的。</p>

<p>反过来想，无论是对数据库如何进行操作，无外乎就是DDL数据库定义语言和DML数据库管理语言，也就是通过大家常说的SQL语句来操作，那么把这些简化为一个SQL语句集合，就可以将开发过程中所有的数据库变动转化为这一系列SQL语句的管理和执行，设计这样一个工具不就得了么？</p>

<p>我现在就是这么作的，在svn中除了有保存数据库最终状态的schema sql文件之外，还专门有一个php文件，用数组记录每一次需要对数据库调整的SQL，然后有一个执行记录表，记录哪些SQL执行过而哪些没有。这个执行记录表在每个数据库实例中都会创建，这样，我只需要简单的调整数据库连接参数，然后就可以通过执行php代码，依次逐个的执行每个SQL了。</p>

<p>有一个缺点，就是SQL语法太依赖具体的数据库类型了，没办法，好在更换数据库的情形并不多，平时尽量写标准的语法吧。另外真要转换数据库的时候，还可以另起炉灶嘛。</p>

<h3>其它的开源软件都是怎么实现的呢？</h3>

<p>我阅读过的开源软件源码并不多，但软件还是用了一些，在有些软件升级的时候，就会自动将数据库也升级了，他们都是怎么实现的呢？难道说只是在1.0升级到2.0的升级程序upgrade.php中，固定的、一次性执行数据库修改么？</p>

<h3>关于同类数据备份和迁移</h3>

<p>以前一个朋友用oracle数据库的时候，特别喜欢用tora（他管它叫蛤蟆，因为软件的about页上有只蛤蟆），但我却认为，在同类数据库，尤其是版本、配置相同的数据库之间进行数据转移，方便一点的方法是利用数据库的导出、导入功能，这样不会有DML覆盖范围以外的内容拉下，简单一点的，自己写个小程序，连上两个数据库，这边读来那边写，也不会慢到哪里去，想提前删个索引什么的也好控制。tora一类的工具，应该是在灌初始字典库的时候用最合适。另外，不是还有bcp么？</p>

<h4>参考</h4>

<ul>
<li><a href="http://www.ibm.com/developerworks/cn/aix/library/au-cn-awkschema/">用 AWK 实现 DB2 数据库 Schema 的同步</a></li>
<li><a href="http://www.cnblogs.com/skyline/archive/2006/11/02/548420.html">ClearQuest问题及其解决办法</a></li>
<li><a href="http://bbs.nou.com.cn/viewthread.php?tid=128436">使用impdp复制oracle的schema数据迁移</a></li>
<li><a href="http://www.scmlife.com/pagetype-bbsthread-a-tid-30-a-page-4.html">CQ数据库的备份与恢复[心得]</a></li>
</ul>

	Tags: <a href="http://www.fwolf.com/blog/post/tag/adodb" title="adodb" rel="tag">adodb</a>, <a href="http://www.fwolf.com/blog/post/tag/axmls" title="axmls" rel="tag">axmls</a>, <a href="http://www.fwolf.com/blog/post/tag/database" title="Database" rel="tag">Database</a>, <a href="http://www.fwolf.com/blog/post/tag/dict" title="dict" rel="tag">dict</a>, <a href="http://www.fwolf.com/blog/post/tag/php" title="PHP" rel="tag">PHP</a>, <a href="http://www.fwolf.com/blog/post/tag/record" title="record" rel="tag">record</a>, <a href="http://www.fwolf.com/blog/post/tag/schema" title="schema" rel="tag">schema</a>, <a href="http://www.fwolf.com/blog/post/tag/sql" title="sql" rel="tag">sql</a>, <a href="http://www.fwolf.com/blog/post/tag/xml" title="xml" rel="tag">xml</a><br />

	<h4>Related posts</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.fwolf.com/blog/post/404" title="忙碌的5月 (2008-06-13)">忙碌的5月</a> (10)</li>
	<li><a href="http://www.fwolf.com/blog/post/384" title="PDO和sqlite的一点体会 (2008-02-22)">PDO和sqlite的一点体会</a> (1)</li>
	<li><a href="http://www.fwolf.com/blog/post/427" title="Intrepid中的php-sybase凑合能用了 (2009-01-04)">Intrepid中的php-sybase凑合能用了</a> (0)</li>
	<li><a href="http://www.fwolf.com/blog/post/398" title="Firefox3书签中的Tags存哪儿了？ (2008-04-22)">Firefox3书签中的Tags存哪儿了？</a> (0)</li>
	<li><a href="http://www.fwolf.com/blog/post/391" title="adodb5连接sybase的一个错误 (2008-03-25)">adodb5连接sybase的一个错误</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.fwolf.com/blog/post/396/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress升级后分类乱码的原因及解决</title>
		<link>http://www.fwolf.com/blog/post/394</link>
		<comments>http://www.fwolf.com/blog/post/394#comments</comments>
		<pubDate>Fri, 04 Apr 2008 17:41:15 +0000</pubDate>
		<dc:creator>Fwolf</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[Database]]></category>
		<category><![CDATA[charset]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.fwolf.com/blog/?p=394</guid>
		<description><![CDATA[另外一个网站WordPress很久没有升级了，主要是嫌网站太慢，ssh上去操作麻烦，加上主人也很少更新。不过当WordPress Automatic upgrade出现之后这一切都简单多了我只要在页面上点点鼠标就能升级了，顺便还能把WP的文件和数据库打包下载到本地。同时，WP的新版2.5还支持插件的自动升级，以后无论是升级WP还是升级插件，基本上就不用ssh了。 WordPress Automatic upgrade的安装和WP的升级基本顺利，不过中间执行完upgrade.php升级数据库后，返回wpau有一个错误，没什么提示信息，直接retry后说升级不成功，清除结果再次运行就没问题了。 升级成功之后，blog标题成了？？问号，我知道这是字符集的问题，看了看wp-include/wp-db.php中已经可以自动识别字符集（原来都是自己hack这个文件），就在wp-config.php中添加了两句配置： define('DB_CHARSET', 'utf8'); define('DB_COLLATE', ''); 乱码问题解决。以为这就没什么事，又分类的名称怎么都成了“？？”了，到分类管理里面一看还是问号，编辑修改成中文保存后依然是问号，如果改成英文的就没事了，其它的内容比如文章什么的中文都正常，怎么回事呢？ 左思右想，觉得还是和升级时候的那个错误有关，我是从比较旧版本的WP升级过来的，以前是通过hack wp-include/wp-db.php文件设置数据库用utf8编码连接，升级过程中这个文件被新版文件覆盖了，而wp-config.php中添加相应设置之前有一个空档，而升级数据库恰恰是在这个空档时进行的。WP 2.3添加了tag功能，后来查看分类的数据表发现分类和tag是保存在一起的，所以可以确认这些被修改了的数据表在创建时，程序并不是使用utf8编码连接的数据库服务器，而是默认的latin1_swedish_ci字符集。在这样字符集的数据表中，自然是无法保存中文的，所以原来的中文、新输入的中文就都变成了问号。 解决方法有些麻烦，因为没有用phpMyAdmin，都是直接编辑好sql命令在mysql中执行的，好在涉及到的表不多： wp_term_relationships wp_term_taxonomy wp_terms wpau_active_plugins_info wpau_upgrade_log 修改表的字符集语法如下： ALTER TABLE [table_name] DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; 这还没完，还得把每个表中的字符型字段的编码转换过来，这个就略微多一点了： # 查看表中各列的详细情况，包括字符集： show full columns from wp_term_relationships; # 更改列的字符集或类型、长度 alter table wp_term_taxonomy change taxonomy taxonomy varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL; [...]]]></description>
			<content:encoded><![CDATA[<p>另外一个网站WordPress很久没有升级了，主要是嫌网站太慢，ssh上去操作麻烦，加上主人也很少更新。不过当<a href="http://wordpress.org/extend/plugins/wordpress-automatic-upgrade/">WordPress Automatic upgrade</a>出现之后这一切都简单多了我只要在页面上点点鼠标就能升级了，顺便还能把WP的文件和数据库打包下载到本地。同时，WP的新版2.5还支持插件的自动升级，以后无论是升级WP还是升级插件，基本上就不用ssh了。</p>

<p><a href="http://wordpress.org/extend/plugins/wordpress-automatic-upgrade/">WordPress Automatic upgrade</a>的安装和WP的升级基本顺利，不过中间执行完<code>upgrade.php</code>升级数据库后，返回wpau有一个错误，没什么提示信息，直接retry后说升级不成功，清除结果再次运行就没问题了。</p>

<p>升级成功之后，blog标题成了？？问号，我知道这是字符集的问题，看了看<code>wp-include/wp-db.php</code>中已经可以自动识别字符集（原来都是自己hack这个文件），就在<code>wp-config.php</code>中添加了两句配置：</p>

<pre><code>define('DB_CHARSET', 'utf8');
define('DB_COLLATE', '');
</code></pre>

<p>乱码问题解决。以为这就没什么事，又分类的名称怎么都成了“？？”了，到分类管理里面一看还是问号，编辑修改成中文保存后依然是问号，如果改成英文的就没事了，其它的内容比如文章什么的中文都正常，怎么回事呢？</p>

<p>左思右想，觉得还是和升级时候的那个错误有关，我是从比较旧版本的WP升级过来的，以前是通过hack <code>wp-include/wp-db.php</code>文件设置数据库用utf8编码连接，升级过程中这个文件被新版文件覆盖了，而<code>wp-config.php</code>中添加相应设置之前有一个空档，而升级数据库恰恰是在这个空档时进行的。WP 2.3添加了tag功能，后来查看分类的数据表发现分类和tag是保存在一起的，所以可以确认这些被修改了的数据表在创建时，程序并不是使用utf8编码连接的数据库服务器，而是默认的latin1_swedish_ci字符集。在这样字符集的数据表中，自然是无法保存中文的，所以原来的中文、新输入的中文就都变成了问号。</p>

<p>解决方法有些麻烦，因为没有用phpMyAdmin，都是直接编辑好sql命令在mysql中执行的，好在涉及到的表不多：</p>

<ul>
<li>wp_term_relationships</li>
<li>wp_term_taxonomy</li>
<li>wp_terms</li>
<li>wpau_active_plugins_info</li>
<li>wpau_upgrade_log</li>
</ul>

<p>修改表的字符集语法如下：</p>

<pre><code>ALTER TABLE [table_name]  DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
</code></pre>

<p>这还没完，还得把每个表中的字符型字段的编码转换过来，这个就略微多一点了：</p>

<pre><code># 查看表中各列的详细情况，包括字符集：
show full columns from wp_term_relationships;

# 更改列的字符集或类型、长度
alter table  wp_term_taxonomy change taxonomy taxonomy varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table  wp_term_taxonomy change description description longtext CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

alter table  wp_terms change name name varchar(55) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table  wp_terms change slug slug varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

alter table  wpau_active_plugins_info change plugin_name plugin_name varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table  wpau_active_plugins_info change plugin_status plugin_status varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;

alter table wpau_upgrade_log change task_name task_name varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table wpau_upgrade_log change task_status task_status varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table wpau_upgrade_log change task_description task_description varchar(150) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
alter table wpau_upgrade_log change task_log task_log text CHARACTER SET utf8 COLLATE utf8_general_ci NULL;
</code></pre>

<p>其实wpau的两个表不用改的，老外设计的程序一般不会写中文进去，改过来只是好看一些。</p>

<p>另外WP 2.5把slug弄没了很不舒服，虽然现在我只用id作permanent link，但还是原意有个整齐一点的slug更好看，所以用上了<a href="http://blog.2i2j.com/being-humble-opinion/wp-plugins-slug-show-in-post-of-wordpress25.html">slugshow插件</a>，希望WP啥时候把那个貌似智能其实很傻的功能改过来。</p>

<h4>Update @ 2008-04-05</h4>

<p>差点忘记了还有一个<a href="http://www.gracecode.com/Archive/Display/1298">css裸奔节</a>，顺便贴一下我blog首页穿衣服和不穿衣服的样子，首先是穿衣服的：</p>

<p><a href="http://img509.imageshack.us/my.php?image=sblog1207408366991gs3.png" target="_blank"><img src="http://img509.imageshack.us/img509/7793/sblog1207408366991gs3.th.png" border="0" alt="Free Image Hosting at www.ImageShack.us" /></a></p>

<p>然后是不穿衣服的：</p>

<p><a href="http://img87.imageshack.us/my.php?image=fwolfsblog1207408413561bm7.png" target="_blank"><img src="http://img87.imageshack.us/img87/3391/fwolfsblog1207408413561bm7.th.png" border="0" alt="Free Image Hosting at www.ImageShack.us" /></a></p>

<p>我的<a href="312">脱衣脚本</a>还是很好用的嘛。</p>

	Tags: <a href="http://www.fwolf.com/blog/post/tag/charset" title="charset" rel="tag">charset</a>, <a href="http://www.fwolf.com/blog/post/tag/css" title="css" rel="tag">css</a>, <a href="http://www.fwolf.com/blog/post/tag/mysql" title="mysql" rel="tag">mysql</a>, <a href="http://www.fwolf.com/blog/post/tag/wordpress" title="WordPress" rel="tag">WordPress</a><br />

	<h4>Related posts</h4>
	<ul class="st-related-posts">
	<li><a href="http://www.fwolf.com/blog/post/102" title="更改 WordPress 自动生成摘要的方式 (2005-12-19)">更改 WordPress 自动生成摘要的方式</a> (19)</li>
	<li><a href="http://www.fwolf.com/blog/post/87" title="搞定WordPress的Permalinks (2005-11-07)">搞定WordPress的Permalinks</a> (6)</li>
	<li><a href="http://www.fwolf.com/blog/post/404" title="忙碌的5月 (2008-06-13)">忙碌的5月</a> (10)</li>
	<li><a href="http://www.fwolf.com/blog/post/241" title="如何为网站添加sitemap文件 (2006-10-17)">如何为网站添加sitemap文件</a> (3)</li>
	<li><a href="http://www.fwolf.com/blog/post/369" title="在无线网络中使用RADIUS服务器+mysql进行用户认证 (2007-11-15)">在无线网络中使用RADIUS服务器+mysql进行用户认证</a> (0)</li>
</ul>

]]></content:encoded>
			<wfw:commentRss>http://www.fwolf.com/blog/post/394/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
