Neil Developer

直接导入帖子到Discuz 论坛数据库.

2013-04-30
Neil

因为我的一个网站需要升级成 discuz系统. 所以需要把以前的帖子都导入到discuz中,  当然也包括以前的注册用户也需要导入到discuz中.  导入用户的事情, 待会写另一篇帖子说.  先说导入帖子的事.

以前完全不了解discuz 的数据库结构.  帖子到底怎么存的,完全不知道.  从哪下手呢?

先准备环境.

1. 当让先本地安装php环境, 以便调试. 推荐 WampServer Version . 自己上网搜一下就知道了, 傻瓜操作,一路next安装.

2. 安装discuz 到本地. 过程略.

重点来了,  从哪下手?  (当然可以去找discuz的文档, 但是我没有找到.)

当然是从数据库本身下手最直接.   想法非常简单.   就是手动发一个帖子,  然后对比发帖前后数据库的差异, 就知道要发一个帖子,需要修改哪些数据了.

但是怎么才能知道数据库前后的差异呢.  简单, 发帖前把数据库备份下来, 发完贴再备份一次, 比较这两次的差异.

备份数据库的方法很多, 但是那种方式最简单直接, 最能让人发现其中的差异呢?

我们知道phpmyadmin 这个神器,有一个功能就是导出数据库(或者导出其中的某些表).  而且导出的是 sql文件, 所有的内容都是文本的明文. 这样我们只需要一个文本比较工具,就能对比差异了.

为了完整起见, 其实我也不知道要导出哪些表, 所以就选择导出整个数据库.  先导出一份, origional.sql,   手动去发个帖子, 再导出一份, post.sql, 注意都是导出整个数据库.  还要注意的就是导出的时候, 不能用快速导出, 要点开自定义选项, 找到最下面的 "转储数据时所使用的函数", 改成 replace,  默认是insert.  至于为什么, 等会你就懂了.

 

 

然后请出文本比较神器, beyond Compare.

其中差异不多, 出了一些更新用户积分之类的操作之外,  很快就定位到这两个表:

pre_forum_post 和 pre_forum_thread

细看这两个表的字段不难发现.
post表应该指的是帖子, 其中包含了帖子所有字段,包括标题,内容,时间,作者等等.   thread表表示的是所有主题帖子,  但是thread表并不包含帖子的内容等详细信息, 值包含一个pid. 这个pid就是post表的id.

所以, 所有的帖子, 包括主题帖子以及主题帖子下面的回复应该都是作为一个post放在pre_forum_post表中的.  而 pre_forum_thread 只记录主题帖子的信息, 以及主题帖子对应的post的id.

到这里, 我们就知道了.  我只需要导入帖子到 post表中, 并且, 更新 thread表. 因为我每个帖子都是作为一个主题帖子导入的, 不需要考虑 回复的问题.

其中的pid 和tid 都是一一对应的.   所以更新着两个表就行了.  细节就不说了.

直接导入.

导入很顺利, 但是 导入之后论坛打开,首页, 发现一个帖子也没有. 但是各个板块点开里面有帖子  呃,  说明我们还有数据没有更新对.  怎么办, 再次仔细比较差异.

发现这样一个差异, 在pre_forum_forum表中:

这个表貌似是包含了, 每个版块的概要信息, 就是论坛首页要显示的信息.

比如每个版块的名字, 每个版块总的发帖数, 版块的设置.  以及这个版块最后一个帖子的详细信息. 包括帖子标题, 发帖时间等等.

就是这里用到的信息:

 

知道了这个,就好办了. 我们把帖子导入到post和thread表之后, 在来这里更新 版块的信息就好了.

这里要更新几个具体的字段,

threads: 版块内的主题数.

posts: 版块内的帖子数.

todayposts: 版块内, 今日发帖的个数. 这个是post的个数, 不是thread的个数.

lastpost: 这个字段比较奇葩,  看名字它是表示本版块最新一个帖子.   但它的值比较有意思, 这是一个字符串,  由四部分组成, 每部分之间用 \t 制表符分割.  第一部分是这个帖子的pid,  第二部分是帖子的标题, 第三部分是帖子的发帖时间, 第四部分是帖子的作者名.   这个字段可能是为了提高论坛首页的性能, 有了他之后,首页就负担轻了很多.

其他的字段就不说了.

按这个再来一次.   首先需要把数据库还原到最开始没有导过的样子,  怎么做?   记得刚开始备份的 origional.sql 文件吗? 把他导入到数据库中就好了啊.  刚才让选replase 还记得吗, 如果没有选replace的话, 你现在导入时会失败的,不信你试试.

言归正传.  还原数据库-> 成功.  再次导入帖子(需要更新 pre_forum_post , pre_forum_thread 以及 pre_forum_forum 这三个表.), 一路调试过程自不必说.  如果其中有失败了, 请重新还原数据库, 再视. 经过数次调试之后. 终于成功了.

这个时候打开论坛首页,  每个版块都能正确显示最后发帖信息, 点开每个版块里面的帖子也都正常.  都点几次也都没有问题.   大功告成.....

好了,上线. 等等, 我手一抖, 咱发个帖子玩玩吧. 点发帖.  opps.......

失败啦.....................  肿么办.  难道是我们把数据库改坏了?  ..........不会吧........................

不要慌张, 看看它说什么先.

它在向post表中插入新帖子的时候出错了. 说主键重复.  它插入的时候用的pid主键是1,  但是我刚才已经导入了很多帖子了. 1这个值在post表中早就被占了啊. 当然会出错了.    但是奇怪的是, pid本来就是自增的, 为什么它在插入新帖的时候还要强行指定一个pid呢?   那这个强行指定的pid又是从哪来的呢.  如果能知道从哪来的, 我就能把它改对了.

它有堆栈信息,  程序员的最爱. 一路打开相应的文件. 一探究竟.

在堆栈的第四层, 就是 function_form.php 的941行找到了如下代码:

看样子, 它就是在这指定pid的.

这里应该是在做分表, 我们知道discuz有分表功能, 就是帖子可以分表存放,  因为帖子太多的话, 一个表就会降低性能.

其实了解这个分表不重要.  重要的是看 pid从哪取的.

这里有个表 forum_post_tableid.  这个表比较有意思.  它只有一列pid, 而且还是自增的.   上面的逻辑显示, 当用户添加新帖子时, 会先从这个表中自增一个pid作为帖子的id,  然后再把帖子连带这个pid一起插入到post表中.  了解了这个, 就明白了.  我们刚才导入帖子的时候, pid用的是自增的值.  这是不对的,  应该先从forum_post_tableid表中自增一个pid,  然后连同这个pid和帖子的内容一起插入到post表中, 而不应该直接用post表的自增值.

知道了这个,  改程序,再来.

先还原数据库, 不用说了吧. 然后导入,  经过数次调试之后. 终于通过了. 导入完成.

哈哈, 等等, 我发个帖子先.

 

等等, 我再发一个试试. .............................

发帖成功.

到此, 导入帖子的问题就解决了.

打完收工.

稍后, 再分享一篇,  如何把已经注册的用户 也导入到discuz中.

欢迎大家多多交流.


Comments

Content