盐城市城南新区建设局网站,论文答辩ppt模板免费下载 素材,移动应用开发公司网站模板,整站seo排名外包「mysql是怎样运行的」第24章 一条记录的多幅面孔—事务的隔离级别与MVCC 文章目录「mysql是怎样运行的」第24章 一条记录的多幅面孔---事务的隔离级别与MVCC一、事前准备二、事务的隔离级别事务并发执行遇到的问题SQL标准中的四种隔离级别MySQL中支持的四种隔离级别三、MVCC原…「mysql是怎样运行的」第24章 一条记录的多幅面孔—事务的隔离级别与MVCC 文章目录「mysql是怎样运行的」第24章 一条记录的多幅面孔---事务的隔离级别与MVCC一、事前准备二、事务的隔离级别事务并发执行遇到的问题SQL标准中的四种隔离级别MySQL中支持的四种隔离级别三、MVCC原理版本链ReadViewMVCC小结四、关于purge一、事前准备
为了故事的顺利发展我们需要创建一个表: CREATE TABLE hero (number INT,name VARCHAR(100),country varchar(100),PRIMARY KEY (number)) EngineInnoDB CHARSETutf8;小贴士: 注意我们把这个hero表的主键命名为number而不是id主要是想和后边要用到的事务id做区别大家 不用大惊小怪哈~ 然后向这个表里插入一条数据:
INSERT INTO hero VALUES(1, 刘备, 蜀);现在表里的数据就是这样的: 二、事务的隔离级别
我们知道 MySQL 是一个 客户端/服务器 架构的软件对于同一个服务器来说可以有若干个客户端与之连接 每个客户端与服务器连接上之后就可以称之为一个会话( Session )。每个客户端都可以在自己的会话中向服务器发出请求语句一个请求语句可能是某个事务的一部分也就是对于服务器来说可能同时处理多个事务。在事务简介的章节中我们说过事务有一个称之为 隔离性 的特性理论上在某个事务对某个数据进行访问时其他事务应该进行排队当该事务提交之后其他事务才可以继续访问这个数据。但是这样子的话对性能影响太大 我们既想保持事务的隔离性 又想让服务器在处理访问同一数据的多个事务时性能尽量高些鱼和熊掌不可得兼舍一部分隔离性而取性能者也。 事务并发执行遇到的问题
怎么个舍弃法呢?我们先得看一下访问相同数据的事务在不保证串行执行(也就是执行完一个再执行另一个)的情况下可能会出现哪些问题:
脏写( Dirty Write )
如果一个事务修改了另一个未提交事务修改过的数据那就意味着发生了 脏写 示意图如下: 如上图 Session A 和 Session B 各开启了一个事务 Session B 中的事务先将 number 列为 1 的记录的 name 列更新为 ‘关羽’ 然后 Session A 中的事务接着又把这条 number 列为 1 的记录的 name 列更新为 张飞 。如果之后 Session B 中的事务进行了回滚那么 Session A 中的更新也将不复存在这种现象就称之为 脏写 。这时 Session A 中的事务就很懵逼我明明把数据更新了最后也提交事务了怎么到最后说自己啥也没干呢? 脏读( Dirty Read )
如果一个事务读到了另一个未提交事务修改过的数据那就意味着发生了 脏读 示意图如下: 如上图 Session A 和 Session B 各开启了一个事务 Session B 中的事务先将 number 列为 1 的记录的 name 列更新为 ‘关羽’ 然后 Session A 中的事务再去查询这条 number 为 1 的记录如果du到列 name 的值为 ‘关羽’ 而 Session B 中的事务稍后进行了回滚那么 Session A 中的事务相当于读到了一个不存在的数据这种现象就称之为 脏读 。 不可重复读(Non-Repeatable Read)
如果一个事务只能读到另一个已经提交的事务修改过的数据并且其他事务每对该数据进行一次修改并提交后该事务都能查询得到最新值那就意味着发生了不可重复读 示意图如下: 如上图我们在 Session B 中提交了几个隐式事务(注意是隐式事务意味着语句结束事务就提交了)这些事务都修改了 number 列为 1 的记录的列 name 的值每次事务提交之后如果 Session A 中的事务都可以查看到最新的值这种现象也被称之为 不可重复读 。 幻读(Phantom)
如果一个事务先根据某些条件查询出一些记录之后另一个事务又向表中插入了符合这些条件的记录原先的事务再次按照该条件查询时能把另一个事务插入的记录也读出来那就意味着发生了 幻读 示意图如 下: 如上图 Session A 中的事务先根据条件 number 0 这个条件查询表 hero 得到了 name 列值为 ‘刘 备’ 的记录;之后Session B 中提交了一个隐式事务该事务向表 hero 中插入了一条新记录;之后Session A 中的事务再根据相同的条件 number 0 查询表 hero 得到的结果集中包含Session B 中的事 务新插入的那条记录这种现象也被称之为 幻读 。
有的同学会有疑问那如果 Session B 中是删除了一些符合 number 0 的记录而不是插入新记录那 Session A 中之后再根据 number 0 的条件读取的记录变少了这种现象算不算 幻读 呢?明确说一下这种现象不属于幻读 幻读强调的是一个事务按照某个相同条件多次读取记录时后读取时读到了之前没有读到的记录。 小贴士: 那对于先前已经读到的记录之后又读取不到这种情况算啥呢?其实这相当于对每一条记录都发生了不可重复读的现象。幻读只是重点强调了读取到了之前读取没有获取到的记录。 SQL标准中的四种隔离级别
我们上边介绍了几种并发事务执行过程中可能遇到的一些问题这些问题也有轻重缓急之分我们给这些问题按照严重性来排一下序:
脏写 脏读 不可重复读 幻读
我们上边所说的舍弃一部分隔离性来换取一部分性能在这里就体现在:设立一些隔离级别隔离级别越低越严 重的问题就越可能发生。有一帮人(并不是设计 MySQL 的大叔们)制定了一个所谓的 SQL标准 在标准中设立了 4个 隔离级别 :
READ UNCOMMITTED :未提交读。READ COMMITTED :已提交读。REPEATABLE READ :可重复读。SERIALIZABLE :可串行化。
SQL标准 中规定针对不同的隔离级别并发事务可以发生不同严重程度的问题具体情况如下: 也就是说:
READ UNCOMMITTED 隔离级别下可能发生脏读 、 不可重复读 和 幻读 问题。READ COMMITTED 隔离级别下可能发生 不可重复读 和 幻读 问题但是不可以发生 脏读 问题。REPEATABLE READ 隔离级别下可能发生 幻读 问题但是不可以发生 脏读 和 不可重复读 的问题。SERIALIZABLE 隔离级别下各种问题都不可以发生。
脏写 是怎么回事儿?怎么里边都没写呢?这是因为脏写这个问题太严重了不论是哪种隔离级别都不允许脏写的情况发生。 MySQL中支持的四种隔离级别
不同的数据库厂商对 SQL标准 中规定的四种隔离级别支持不一样比方说 Oracle 就只支持 READ COMMITTED 和 SERIALIZABLE 隔离级别。本书中所讨论的 MySQL 虽然支持4种隔离级别但与 SQL标准 中所规定的各级隔离级 别允许发生的问题却有些出入MySQL在REPEATABLE READ隔离级别下是可以禁止幻读问题的发生的(关于如何禁止我们之后会详细说明的)。 MySQL 的默认隔离级别为 REPEATABLE READ 我们可以手动修改一下事务的隔离级别。 三、MVCC原理
版本链
我们前边说过对于使用 InnoDB 存储引擎的表来说它的聚簇索引记录中都包含两个必要的隐藏列( row_id 并不是必要的我们创建的表中有主键或者非NULL的UNIQUE键时都不会包含 row_id 列):
trx_id :每次一个事务对某条聚簇索引记录进行改动时都会把该事务的 事务id 赋值给 trx_id 隐藏列。roll_pointer :每次对某条聚簇索引记录进行改动时都会把旧的版本写入到 undo日志 中然后这个隐藏列就相当于一个指针可以通过它来找到该记录修改前的信息。
比方说我们的表 hero 现在只包含一条记录: 假设插入该记录的 事务id 为 80 那么此刻该条记录的示意图如下所示: 小贴士: 实际上insert undo只在事务回滚时起作用当事务提交后该类型的undo日志就没用了它占用的Undo Log Segment也会被系统回收(也就是该undo日志占用的Undo页面链表要么被重用要么被释放)。 虽然真正的insert undo日志占用的存储空间被释放了但是roll_pointer的值并不会被清除roll_pointer属性占用7个字节第一个比特位就标记着它指向的undo日志的类型如果该比特位的值为1时就代表着它指向的undo日志类型为insert undo。所以我们之后在画图时都会把insert undo给去掉 大家留意一下就好了。 假设之后两个事务id 分别为 100 、 200 的事务对这条记录进行 UPDATE 操作操作流程如下: 小贴士: 能不能在两个事务中交叉更新同一条记录呢?哈哈这不就是一个事务修改了另一个未提交事务修改过的数据沦为了脏写了么?InnoDB使用锁来保证不会有脏写情况的发生也就是在第一个事务更新了某条记录后就会给这条记录加锁另一个事务再次更新时就需要等待第一个事务提交了把锁释放之后才可以继续更新。关于锁的更多细节我们后续的文章中再唠叨哈~ 每次对记录进行改动都会记录一条 undo日志 每条 undo日志 也都有一个 roll_pointer 属性( INSERT 操作 对应的 undo日志 没有该属性因为该记录并没有更早的版本)可以将这些 undo日志 都连起来串成一个链表所以现在的情况就像下图一样: 对该记录每次更新后都会将旧值放到一条 undo日志 中就算是该记录的一个旧版本随着更新次数的增多 所有的版本都会被 roll_pointer 属性连接成一个链表我们把这个链表称之为 版本链 版本链的头节点就是当前记录最新的值。另外每个版本中还包含生成该版本时对应的 事务id 这个信息很重要我们稍后就会用到。 ReadView
对于使用 READ UNCOMMITTED 隔离级别的事务来说由于可以读到未提交事务修改过的记录所以直接读取记录的最新版本就好了;对于使用 SERIALIZABLE 隔离级别的事务来说设计 InnoDB 的大叔规定使用加锁的方式来访 问记录(加锁是啥我们后续文章中说哈);对于使用 READ COMMITTED 和 REPEATABLE READ 隔离级别的事务来 说都必须保证读到已经提交了的事务修改过的记录也就是说假如另一个事务已经修改了记录但是尚未提交 是不能直接读取最新版本的记录的核心问题就是:需要判断一下版本链中的哪个版本是当前事务可见的。为此设计 InnoDB 的大叔提出了一个 ReadView 的概念这个 ReadView 中主要包含4个比较重要的内容:
m_ids :表示在生成 ReadView 时当前系统中活跃的读写事务的 事务id 列表。min_trx_id :表示在生成 ReadView 时当前系统中活跃的读写事务中最小的事务id 也就是 m_ids 中的最小值。max_trx_id :表示生成 ReadView 时系统中应该分配给下一个事务的id 值。 小贴士: 注意max_trx_id并不是m_ids中的最大值事务id是递增分配的。比方说现在有id为123这三 个事务之后id为3的事务提交了。那么一个新的读事务在生成ReadView时m_ids就包括1和2mi n_trx_id的值就是1max_trx_id的值就是4。 creator_trx_id :表示生成该 ReadView 的事务的 事务id 。 小贴士: 我们前边说过只有在对表中的记录做改动时(执行INSERT、DELETE、UPDATE这些语句时)才会 为事务分配事务id否则在一个只读事务中的事务id值都默认为0。 有了这个 ReadView 这样在访问某条记录时只需要按照下边的步骤判断记录的某个版本是否可见:
如果被访问版本的 trx_id 属性值与 ReadView 中的 creator_trx_id 值相同意味着当前事务在访问它自己修改过的记录所以该版本可以被当前事务访问。如果被访问版本的 trx_id 属性值小于 ReadView 中的 min_trx_id 值表明生成该版本的事务在当前事务生 成 ReadView 前已经提交所以该版本可以被当前事务访问。如果被访问版本的 trx_id 属性值大于 ReadView 中的 max_trx_id 值表明生成该版本的事务在当前事务生 成 ReadView 后才开启所以该版本不可以被当前事务访问。如果被访问版本的 trx_id 属性值在 ReadView 的 min_trx_id 和 max_trx_id 之间那就需要判断一下 trx_id 属性值是不是在 m_ids 列表中如果在说明创建 ReadView 时生成该版本的事务还是活跃的该版本不可以被访问;如果不在说明创建 ReadView 时生成该版本的事务已经被提交该版本可以被访问。
如果某个版本的数据对当前事务不可见的话那就顺着版本链找到下一个版本的数据继续按照上边的步骤判断可见性依此类推直到版本链中的最后一个版本。如果最后一个版本也不可见的话那么就意味着该条记录对该事务完全不可见查询结果就不包含该记录。
在 MySQL 中 READ COMMITTED 和 REPEATABLE READ 隔离级别的的一个非常大的区别就是它们生成ReadView的 时机不同。我们还是以表 hero 为例来假设现在表 hero 中只有一条由 事务id 为 80 的事务插入的一条记录: 接下来看一下READ COMMITTED 和 REPEATABLE READ所谓的生成ReadView的时机不同到底不同在哪里。 EAD COMMITTED ——每次读取数据前都生成一个ReadView 比方说现在系统里有两个 事务id 分别为 100 、 200 的事务在执行:
# Transaction 100
BEGIN;
UPDATE hero SET name 关羽 WHERE number 1;
UPDATE hero SET name 张飞 WHERE number 1;# Transaction 200BEGIN;
# 更新了一些别的表的记录 ...小贴士: 再次强调一遍事务执行过程中只有在第一次真正修改记录时(比如使用INSERT、DELETE、UPDATE语 句)才会被分配一个单独的事务id这个事务id是递增的。所以我们才在Transaction 200中更新一 些别的表的记录目的是让它分配事务id。 此刻表 hero 中 number 为 1 的记录得到的版本链表如下所示: 假设现在有一个使用 READ COMMITTED 隔离级别的事务开始执行:
# 使用READ COMMITTED隔离级别的事务
BEGIN;
# SELECT1:Transaction 100、200未提交
SELECT * FROM hero WHERE number 1; # 得到的列name的值为刘备这个 SELECT1 的执行过程如下:
在执行 SELECT 语句时会先生成一个 ReadView ReadView 的 m_ids 列表的内容就是 [100, 200] min_trx_id 为 100 max_trx_id 为 201 creator_trx_id 为 0 。然后从版本链中挑选可见的记录从图中可以看出最新版本的列 name 的内容是 ‘张飞’ 该版本的 trx_id 值为 100 在 m_ids 列表内所以不符合可见性要求根据 roll_pointer 跳到下一个版本。下一个版本的列 name 的内容是 ‘关羽’ 该版本的 trx_id 值也为 100 也在 m_ids 列表内所以也不符合要求继续跳到下一个版本。下一个版本的列 name 的内容是 ‘刘备’ 该版本的 trx_id 值为 80 小于 ReadView 中的 min_trx_id 值100 所以这个版本是符合要求的最后返回给用户的版本就是这条列 name 为 ‘刘备’ 的记录。
之后我们把 事务id 为 100 的事务提交一下就像这样: # Transaction 100
BEGIN;
UPDATE hero SET name 关羽 WHERE number 1;
UPDATE hero SET name 张飞 WHERE number 1;
COMMIT;然后再到 事务id 为 200 的事务中更新一下表 hero 中 number 为 1 的记录:
# Transaction 200
BEGIN;
# 更新了一些别的表的记录 ...
UPDATE hero SET name 赵云 WHERE number 1; UPDATE hero SET name 诸葛亮 WHERE number 1;此刻表 hero 中 number 为 1 的记录的版本链就长这样: 然后再到刚才使用 READ COMMITTED 隔离级别的事务中继续查找这个 number 为 1 的记录如下:
# 使用READ COMMITTED隔离级别的事务
BEGIN;
# SELECT1:Transaction 100、200均未提交
SELECT * FROM hero WHERE number 1; # 得到的列name的值为刘备
# SELECT2:Transaction 100提交Transaction 200未提交
SELECT * FROM hero WHERE number 1; # 得到的列name的值为张飞这个 SELECT2 的执行过程如下:
在执行 SELECT 语句时会又会单独生成一个 ReadView 该 ReadView 的 m_ids 列表的内容就是 [200] ( 事 务id 为 100 的那个事务已经提交了所以再次生成快照时就没有它了) min_trx_id 为 200 max_trx_id 为 201 creator_trx_id 为 0 。 然后从版本链中挑选可见的记录从图中可以看出最新版本的列 name 的内容是 ‘诸葛亮’ 该版本的trx_id 值为 200 在 m_ids 列表内所以不符合可见性要求根据 roll_pointer 跳到下一个版本。下一个版本的列 name 的内容是 ‘赵云’ 该版本的 trx_id 值为 200 也在 m_ids 列表内所以也不符合 要求继续跳到下一个版本。下一个版本的列 name 的内容是 ‘张飞’ 该版本的 trx_id 值为 100 小于 ReadView 中的 min_trx_id 值200 所以这个版本是符合要求的最后返回给用户的版本就是这条列 name 为 ‘张飞’ 的记录。
以此类推如果之后 事务id 为 200 的记录也提交了再此在使用 READ COMMITTED 隔离级别的事务中查询表 hero 中 number 值为 1 的记录时得到的结果就是 ‘诸葛亮’ 了具体流程我们就不分析了。总结一下就是:使用READ COMMITTED隔离级别的事务在每次查询开始时都会生成一个独立的ReadView。 REPEATABLE READ —— 在第一次读取数据时生成一个ReadView 对于使用 REPEATABLE READ 隔离级别的事务来说只会在第一次执行查询语句时生成一个 ReadView 之后的查询就不会重复生成了。我们还是用例子看一下是什么效果。
比方说现在系统里有两个 事务id 分别为 100 、 200 的事务在执行:
# Transaction 100
BEGIN;
UPDATE hero SET name 关羽 WHERE number 1;
UPDATE hero SET name 张飞 WHERE number 1;
# Transaction 200
BEGIN;
# 更新了一些别的表的记录 ...此刻表 hero 中 number 为 1 的记录得到的版本链表如下所示: 假设现在有一个使用 REPEATABLE READ 隔离级别的事务开始执行:
# 使用REPEATABLE READ隔离级别的事务
BEGIN;
# SELECT1:Transaction 100、200未提交
SELECT * FROM hero WHERE number 1; # 得到的列name的值为刘备 这个 SELECT1 的执行过程如下:
在执行 SELECT 语句时会先生成一个 ReadView ReadView 的 m_ids 列表的内容就是 [100, 200] min_trx_id 为 100 max_trx_id 为 201 creator_trx_id 为 0 。然后从版本链中挑选可见的记录从图中可以看出最新版本的列 name 的内容是 ‘张飞’ 该版本的 trx_id 值为 100 在 m_ids 列表内所以不符合可见性要求根据 roll_pointer 跳到下一个版本。下一个版本的列 name 的内容是 ‘关羽’ 该版本的 trx_id 值也为 100 也在 m_ids 列表内所以也不符 合要求继续跳到下一个版本。下一个版本的列 name 的内容是 ‘刘备’ 该版本的 trx_id 值为 80 小于 ReadView 中的 min_trx_id 值100 所以这个版本是符合要求的最后返回给用户的版本就是这条列 name 为 ‘刘备’ 的记录。
之后我们把 事务id 为 100 的事务提交一下就像这样:
# Transaction 100
BEGIN;
UPDATE hero SET name 关羽 WHERE number 1;
UPDATE hero SET name 张飞 WHERE number 1;
COMMIT;然后再到 事务id 为 200 的事务中更新一下表 hero 中 number 为 1 的记录:
# Transaction 200
BEGIN;
# 更新了一些别的表的记录 ...
UPDATE hero SET name 赵云 WHERE number 1; UPDATE hero SET name 诸葛亮 WHERE number 1;此刻表 hero 中 number 为 1 的记录的版本链就长这样: 然后再到刚才使用 REPEATABLE READ 隔离级别的事务中继续查找这个 number 为 1 的记录如下:
# 使用REPEATABLE READ隔离级别的事务
BEGIN;
# SELECT1:Transaction 100、200均未提交
SELECT * FROM hero WHERE number 1; # 得到的列name的值为刘备
# SELECT2:Transaction 100提交Transaction 200未提交
SELECT * FROM hero WHERE number 1; # 得到的列name的值仍为刘备这个 SELECT2 的执行过程如下:
因为当前事务的隔离级别为 REPEATABLE READ 而之前在执行 SELECT1 时已经生成过 ReadView 了所以此 时直接复用之前的 ReadView 之前的 ReadView 的 m_ids 列表的内容就是 [100, 200] min_trx_id 为100 max_trx_id 为 201 creator_trx_id 为 0 。然后从版本链中挑选可见的记录从图中可以看出最新版本的列 name 的内容是 ‘诸葛亮’ 该版本的trx_id 值为 200 在 m_ids 列表内所以不符合可见性要求根据 roll_pointer 跳到下一个版本。下一个版本的列 name 的内容是 ‘赵云’ 该版本的 trx_id 值为 200 也在 m_ids 列表内所以也不符合 要求继续跳到下一个版本。下一个版本的列 name 的内容是 ‘张飞’ 该版本的 trx_id 值为 100 而 m_ids 列表中是包含值为 100 的事务id 的所以该版本也不符合要求同理下一个列 name 的内容是 ‘关羽’ 的版本也不符合要求。继续跳 到下一个版本。下一个版本的列 name 的内容是 ‘刘备’ 该版本的 trx_id 值为 80 小于 ReadView 中的 min_trx_id 值100 所以这个版本是符合要求的最后返回给用户的版本就是这条列 c 为 ‘刘备’ 的记录。
也就是说两次 SELECT 查询得到的结果是重复的记录的列 c 值都是 ‘刘备’ 这就是 可重复读 的含义。如果我们之后再把 事务id 为 200 的记录提交了然后再到刚才使用 REPEATABLE READ 隔离级别的事务中继续查找这 个 number 为 1 的记录得到的结果还是 ‘刘备’ 具体执行过程大家可以自己分析一下。 MVCC小结
从上边的描述中我们可以看出来所谓的 **MVCC (Multi-Version Concurrency Control 多版本并发控制)**指的就 是在使用 READ COMMITTD 、 REPEATABLE READ 这两种隔离级别的事务在执行普通的 SEELCT 操作时访问记录的版 本链的过程这样子可以使不同事务的读-写 、 写-读操作并发执行从而提升系统性能。 READ COMMITTD 、
REPEATABLE READ 这两个隔离级别的一个很大不同就是:生成ReadView的时机不同READ COMMITTD在每一 次进行普通SELECT操作前都会生成一个ReadView而REPEATABLE READ只在第一次进行普通SELECT操作 前生成一个ReadView之后的查询操作都重复使用这个ReadView就好了。 小贴士: 我们之前说执行DELETE语句或者更新主键的UPDATE语句并不会立即把对应的记录完全从页面中删除而是执行一个所谓的delete mark操作相当于只是对记录打上了一个删除标志位这主要就是为MVCC服务的大家可以对比上边举的例子自己试想一下怎么使用。 另外所谓的MVCC只是在我们进行普通的SEELCT查询时才生效截止到目前我们所见的所有SELECT语句都算是普通的查询至于啥是个不普通的查询我们稍后再说哈~ 四、关于purge
大家有没有发现两件事儿:
我们说 insert undo 在事务提交之后就可以被释放掉了而 update undo 由于还需要支持 MVCC 不能立即删除掉。为了支持 MVCC 对于 delete mark 操作来说仅仅是在记录上打一个删除标记并没有真正将它删除掉。
随着系统的运行在确定系统中包含最早产生的那个 ReadView 的事务不会再访问某些 update undo日志以及被打了删除标记的记录后有一个后台运行的 purge线程会把它们真正的删除掉。关于更多的purge细节我们将放到纸质书中进行详细唠叨不见不散哈~ 笔记整理 mysql是怎样运行的
文章转载自: http://www.morning.wtxdp.cn.gov.cn.wtxdp.cn http://www.morning.fmtfj.cn.gov.cn.fmtfj.cn http://www.morning.rfpxq.cn.gov.cn.rfpxq.cn http://www.morning.sqdjn.cn.gov.cn.sqdjn.cn http://www.morning.mkfr.cn.gov.cn.mkfr.cn http://www.morning.qlpyn.cn.gov.cn.qlpyn.cn http://www.morning.qggm.cn.gov.cn.qggm.cn http://www.morning.wnzgm.cn.gov.cn.wnzgm.cn http://www.morning.jlqn.cn.gov.cn.jlqn.cn http://www.morning.fnwny.cn.gov.cn.fnwny.cn http://www.morning.rddlz.cn.gov.cn.rddlz.cn http://www.morning.stsnf.cn.gov.cn.stsnf.cn http://www.morning.fkflc.cn.gov.cn.fkflc.cn http://www.morning.wslr.cn.gov.cn.wslr.cn http://www.morning.nwynx.cn.gov.cn.nwynx.cn http://www.morning.fbqr.cn.gov.cn.fbqr.cn http://www.morning.gqtw.cn.gov.cn.gqtw.cn http://www.morning.rxgnn.cn.gov.cn.rxgnn.cn http://www.morning.kcsx.cn.gov.cn.kcsx.cn http://www.morning.tscsd.cn.gov.cn.tscsd.cn http://www.morning.gqfks.cn.gov.cn.gqfks.cn http://www.morning.npgwb.cn.gov.cn.npgwb.cn http://www.morning.c7495.cn.gov.cn.c7495.cn http://www.morning.yrfxb.cn.gov.cn.yrfxb.cn http://www.morning.zlzpz.cn.gov.cn.zlzpz.cn http://www.morning.bhjyh.cn.gov.cn.bhjyh.cn http://www.morning.gqjqf.cn.gov.cn.gqjqf.cn http://www.morning.srzhm.cn.gov.cn.srzhm.cn http://www.morning.swdnr.cn.gov.cn.swdnr.cn http://www.morning.lmfmd.cn.gov.cn.lmfmd.cn http://www.morning.shuangxizhongxin.cn.gov.cn.shuangxizhongxin.cn http://www.morning.rjmd.cn.gov.cn.rjmd.cn http://www.morning.nrzbq.cn.gov.cn.nrzbq.cn http://www.morning.tstkr.cn.gov.cn.tstkr.cn http://www.morning.drggr.cn.gov.cn.drggr.cn http://www.morning.ljdhj.cn.gov.cn.ljdhj.cn http://www.morning.tlpgp.cn.gov.cn.tlpgp.cn http://www.morning.lslin.com.gov.cn.lslin.com http://www.morning.mkpkz.cn.gov.cn.mkpkz.cn http://www.morning.plpqf.cn.gov.cn.plpqf.cn http://www.morning.zdmrf.cn.gov.cn.zdmrf.cn http://www.morning.hpcpp.cn.gov.cn.hpcpp.cn http://www.morning.wwwghs.com.gov.cn.wwwghs.com http://www.morning.zdtfr.cn.gov.cn.zdtfr.cn http://www.morning.lcjw.cn.gov.cn.lcjw.cn http://www.morning.llcsd.cn.gov.cn.llcsd.cn http://www.morning.kcbml.cn.gov.cn.kcbml.cn http://www.morning.kwjyt.cn.gov.cn.kwjyt.cn http://www.morning.wdhlc.cn.gov.cn.wdhlc.cn http://www.morning.yrblz.cn.gov.cn.yrblz.cn http://www.morning.gwtgt.cn.gov.cn.gwtgt.cn http://www.morning.qrcsb.cn.gov.cn.qrcsb.cn http://www.morning.yrjfb.cn.gov.cn.yrjfb.cn http://www.morning.tddrh.cn.gov.cn.tddrh.cn http://www.morning.mdgb.cn.gov.cn.mdgb.cn http://www.morning.chxsn.cn.gov.cn.chxsn.cn http://www.morning.wyctq.cn.gov.cn.wyctq.cn http://www.morning.fxzgw.com.gov.cn.fxzgw.com http://www.morning.skbbt.cn.gov.cn.skbbt.cn http://www.morning.nkcfh.cn.gov.cn.nkcfh.cn http://www.morning.qwwhs.cn.gov.cn.qwwhs.cn http://www.morning.dxsyp.cn.gov.cn.dxsyp.cn http://www.morning.skbkq.cn.gov.cn.skbkq.cn http://www.morning.kcdts.cn.gov.cn.kcdts.cn http://www.morning.lkgqb.cn.gov.cn.lkgqb.cn http://www.morning.lhhkp.cn.gov.cn.lhhkp.cn http://www.morning.qytpt.cn.gov.cn.qytpt.cn http://www.morning.brscd.cn.gov.cn.brscd.cn http://www.morning.yfrbn.cn.gov.cn.yfrbn.cn http://www.morning.xkzmz.cn.gov.cn.xkzmz.cn http://www.morning.ygkk.cn.gov.cn.ygkk.cn http://www.morning.zzgtdz.cn.gov.cn.zzgtdz.cn http://www.morning.xrpwk.cn.gov.cn.xrpwk.cn http://www.morning.hwnqg.cn.gov.cn.hwnqg.cn http://www.morning.jxgyg.cn.gov.cn.jxgyg.cn http://www.morning.tfzjl.cn.gov.cn.tfzjl.cn http://www.morning.ztrht.cn.gov.cn.ztrht.cn http://www.morning.pmsl.cn.gov.cn.pmsl.cn http://www.morning.kxwsn.cn.gov.cn.kxwsn.cn http://www.morning.kjkml.cn.gov.cn.kjkml.cn