thinkphp3.2的mysql数据库迁达梦数据库 TP3.2+DM数据库改造

最近有个项目,要改用达梦数据库,记录一下操作步骤,供大家参考

1,安装达梦数据库

    这个直接到达梦数据库官网下载,开发者注册一下,免费下载学习用,商用的自己购买版权。

    根据提示安装,这里用WIN7测试的。安全完后打开,创建数据库,一切顺利。操作与mssql或mysql差不多。

2,迁移数据

    将MySQL数据迁移进达梦,达梦软件自带了迁移工具,支持各数数据的迁移;

    期间遇到各种问题:

    1,直连腾讯云数据库做迁移,能链接上,但是迁数据时报错,显示表分析出错,预览时能查看数据,执行时报错,不知是什么原因。然后更换方法2

    2,把腾讯云mysql数据导出为sql文件,然后用迁移工具导入,又报错,应该是数据格式不兼容的问题,然后换方法3

    3,在本地再搭了个mysql数据库,通过sql文件导入数据,然后再用迁移工具连本地数据库做迁移,成功。这里建议用root用户,之前尝试新建用户去执行竟然连接不上本地mysql数据库。


3,本地PHP环境加达梦驱动

    本地win7安装phpStudy测试;

    达梦数据库安装目录里面提供了文件 pdo73nts_dm.dll  php73nts_dm.dll(根据自己的php版本选择)

    图片.png


        复制到php扩展目录ext下


图片.png


用编辑工具打开php.ini
php.ini中在末尾添加
extension=pdo73nts_dm
extension=php73nts_dm

重启Apache服务,运行 php -m ,测试dm数据库驱动加载成功

如果加载失败报“PHP Fatal error:  Unable to start DM module in Unknown on line 0”,

则将将达梦数据库安装目录bin下的以下dll文件拷贝至C:\Windows\SysWOW64C:\Windows\System32,重新启动Apache。

图片.png



phpinfo里面可以看到下图则表示成功


图片.png


4,PHP链接数据库是否成功

    以下代码网上复制的。参考

date_default_timezone_set("Asia/Shanghai");header("Content-type:text/html; Charset=utf-8");
$dm_conf = array(    
    'host'=> '127.0.0.1:5236',  //连接地址及端口    
    'db'=> 'DBNAME',  //数据库名    
    'db_user' => 'SYSDBA', //用户名    
    'db_pwd'=> '123456789', //密码);
    $pdo = new PDO("dm:host=".$dm_conf['host'].";
    dbname=".$dm_conf['db']."",$dm_conf['db_user'],$dm_conf['db_pwd']
   );

输入的中文数据是乱码,则在这里C:\windows\System32\dm_svc.conf 打开加一行

CHAR_CODE=(PG_UTF8)

图片.png

5,thinkphp框架改造

    1,增加DM数据库驱动类,让tp支持达梦数据库,

    在目录下\ThinkPHP\Library\Think\Db\Driver增加Dm.class.php文件

复制以下内容并保存

<?php

namespace Think\Db\Driver;
use Think\Db;
defined('THINK_PATH') or exit();
/**
 * DM数据库驱动类
 */
class Dm extends Db{

    /**
     * 架构函数 读取数据库配置信息
     * @access public
     * @param array $config 数据库配置数组
     */
    public function __construct($config=''){
        if ( !extension_loaded('dm') ) {
            E(L('_NOT_SUPPERT_').':dm');
        }
        if(!empty($config)) {
            $this->config   =   $config;
            if(empty($this->config['params'])) {
                $this->config['params'] =   '';
            }
        }
    }

    /**
     * 连接数据库方法
     * @access public
     * @throws ThinkExecption
     */
    public function connect($config='',$linkNum=0) {
        if ( !isset($this->linkID[$linkNum]) ) {
            
            // $link = dm_connect("localhost", "SYSDBA", "lisonglin1221");
            // if(!$link){  echo dm_error().':'.dm_errormsg();exit(); }
            // dm_setoption($link,1,12345,1);  //设置 dm 连接和语句的相关属性,设置UTF8
    
    
    
            if(empty($config))  $config = $this->config;
            
            $pconnect   = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect;
            // $conn = $pconnect ? 'oci_pconnect':'oci_new_connect';
            // $this->linkID[$linkNum] = $conn($config['username'], $config['password'],$config['database']);//modify by wyfeng at 2008.12.19

            $this->linkID[$linkNum] = dm_connect($config['hostname'],$config['username'], $config['password']);
            
            if (!$this->linkID[$linkNum]){
                $this->error(false);
            }else{
                dm_setoption($this->linkID[$linkNum],1,12345,1);
            }
                
            // 标记连接成功
            $this->connected = true;
            //注销数据库安全信息
            if(1 != C('DB_DEPLOY_TYPE')) unset($this->config);
            
        }
        return $this->linkID[$linkNum];
    }

    /**
     * 释放查询结果
     * @access public
     */
    public function free() {
        // mysql_free_result($this->queryID);
        dm_free_result($this->queryID);
        $this->queryID = null;
    }

    /**
     * 执行查询 返回数据集
     * @access public
     * @param string $str  sql指令
     * @return mixed
     */
    public function query($str) {
        if(0===stripos($str, 'call')){ // 存储过程查询支持
            $this->close();
            $this->connected    =   false;
        }
        $this->initConnect(false);
        if ( !$this->_linkID ) return false;
        $this->queryStr = $str;
        //释放前次的查询结果
        if ( $this->queryID ) {    $this->free();    }
        N('db_query',1);
        // 记录开始执行时间
        G('queryStartTime');
        $this->queryID = dm_exec($this->_linkID,$str);    //dm_exec($link,$sql);
        $this->debug();
        if ( false === $this->queryID ) {
            $this->error();
            return false;
        } else {
            $this->numRows = dm_num_rows($this->queryID);
            return $this->getAll();
        }
    }

    /**
     * 执行语句
     * @access public
     * @param string $str  sql指令
     * @return integer|false
     */
    public function execute($str) {
        $this->initConnect(true);
        if ( !$this->_linkID ) return false;
        $this->queryStr = $str;
        //释放前次的查询结果
        if ( $this->queryID ) {    $this->free();    }
        N('db_write',1);
        // 记录开始执行时间
        G('queryStartTime');
        $result = dm_exec($this->_linkID,$str) ;
        $this->debug();
        if ( false === $result) {
            $this->error();
            return false;
        } else {
            // $this->numRows = mysql_affected_rows($this->_linkID);
            // $this->lastInsID = mysql_insert_id($this->_linkID);
            // return $this->numRows;
        }
    }

    /**
     * 启动事务
     * @access public
     * @return void
     */
    public function startTrans() {
        $this->initConnect(true);
        if ( !$this->_linkID ) return false;
        //数据rollback 支持
        if ($this->transTimes == 0) {
            mysql_query('START TRANSACTION', $this->_linkID);
        }
        $this->transTimes++;
        return ;
    }

    /**
     * 用于非自动提交状态下面的查询提交
     * @access public
     * @return boolen
     */
    public function commit() {
        if ($this->transTimes > 0) {
            $result = mysql_query('COMMIT', $this->_linkID);
            $this->transTimes = 0;
            if(!$result){
                $this->error();
                return false;
            }
        }
        return true;
    }

    /**
     * 事务回滚
     * @access public
     * @return boolen
     */
    public function rollback() {
        if ($this->transTimes > 0) {
            $result = mysql_query('ROLLBACK', $this->_linkID);
            $this->transTimes = 0;
            if(!$result){
                $this->error();
                return false;
            }
        }
        return true;
    }

    /**
     * 获得所有的查询数据
     * @access private
     * @return array
     */
    private function getAll() {
        //返回数据集
        $result = array();
        if($this->numRows >0) {
            // while($row = mysql_fetch_assoc($this->queryID)){
            while($row = dm_fetch_array($this->queryID)){
                $result[]   =   $row;
            }
            // mysql_data_seek($this->queryID,0);
            // dm_data_seek($this->queryID,0);
        }
        return $result;
    }

    /**
     * 取得数据表的字段信息
     * @access public
     * @return array
     */
    public function getFields($tableName) {
        $result =   $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName));
        $info   =   array();
        if($result) {
            foreach ($result as $key => $val) {
                $info[$val['Field']] = array(
                    'name'    => $val['Field'],
                    'type'    => $val['Type'],
                    'notnull' => (bool) (strtoupper($val['Null']) === 'NO'), // not null is empty, null is yes
                    'default' => $val['Default'],
                    'primary' => (strtolower($val['Key']) == 'pri'),
                    'autoinc' => (strtolower($val['Extra']) == 'auto_increment'),
                );
            }
        }
        return $info;
    }

    /**
     * 取得数据库的表信息
     * @access public
     * @return array
     */
    public function getTables($dbName='') {
        if(!empty($dbName)) {
           $sql    = 'SHOW TABLES FROM '.$dbName;
        }else{
           $sql    = 'SHOW TABLES ';
        }
        $result =   $this->query($sql);
        $info   =   array();
        foreach ($result as $key => $val) {
            $info[$key] = current($val);
        }
        return $info;
    }

    /**
     * 替换记录
     * @access public
     * @param mixed $data 数据
     * @param array $options 参数表达式
     * @return false | integer
     */
    public function replace($data,$options=array()) {
        foreach ($data as $key=>$val){
            $value   =  $this->parseValue($val);
            if(is_scalar($value)) { // 过滤非标量数据
                $values[]   =  $value;
                $fields[]     =  $this->parseKey($key);
            }
        }
        $sql   =  'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')';
        return $this->execute($sql);
    }

    /**
     * 插入记录
     * @access public
     * @param mixed $datas 数据
     * @param array $options 参数表达式
     * @param boolean $replace 是否replace
     * @return false | integer
     */
    public function insertAll($datas,$options=array(),$replace=false) {
        if(!is_array($datas[0])) return false;
        $fields = array_keys($datas[0]);
        array_walk($fields, array($this, 'parseKey'));
        $values  =  array();
        foreach ($datas as $data){
            $value   =  array();
            foreach ($data as $key=>$val){
                $val   =  $this->parseValue($val);
                if(is_scalar($val)) { // 过滤非标量数据
                    $value[]   =  $val;
                }
            }
            $values[]    = '('.implode(',', $value).')';
        }
        $sql   =  ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values);
        return $this->execute($sql);
    }

    /**
     * 关闭数据库
     * @access public
     * @return void
     */
    public function close() {
        if ($this->_linkID){
            dm_close($this->_linkID);
        }
        $this->_linkID = null;
    }

    /**
     * 数据库错误信息
     * 并显示当前的SQL语句
     * @access public
     * @return string
     */
    public function error() {
        
        $this->error = dm_error().':'.dm_errormsg();;
        if('' != $this->queryStr){
            $this->error .= "\n [ SQL语句 ] : ".$this->queryStr;
        }
        trace($this->error,'','ERR');
        return $this->error;
    }

    /**
     * SQL指令安全过滤
     * @access public
     * @param string $str  SQL字符串
     * @return string
     */
    public function escapeString($str) {
        if($this->_linkID) {
            return mysql_real_escape_string($str,$this->_linkID);
        }else{
            return mysql_escape_string($str);
        }
    }

    /**
     * 字段和表名处理添加`
     * @access protected
     * @param string $key
     * @return string
     */
    protected function parseKey(&$key) {
        $key   =  trim($key);
        if(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
           $key = '`'.$key.'`';
        }
        return $key;
    }
}


以上驱动文件是拿mysql的驱动文件来改造的。因时间紧没有全部测试,不一定全对。大家使用时可留意一下。

2,修改数据库连接配置文件为达梦数据库

<?php
return array(
        'DB_TYPE' => 'Dm',    
        'DB_HOST' => 'localhost',    // 服务器地址
        'DB_USER' => 'SYSDBA',        // 用户名
        'DB_PWD' => '******',        // 密码

        'DB_PORT' => '5236',            // 端口
        'DB_NAME' => 'OA',         // 数据库名
        'DB_PREFIX' => '',        // 数据库表前缀    
);


然后测试一下,数据查询功能,成功

    public function test(){
        $m=M('test');
        $data=$m->field('ID,NAME')->limit(10,3)->select();
        dump($data);
        echo $m->getLastSql();
    }

完善支持THINKPHP3.2的原开发程序。项目不用大改,不过只是测试了查询功能,其它 增、删、改 没空测试,大家自己测试。应该也差不多了

  • 评论列表:
  •  访客
     发布于 2023-07-25 09:47:30  回复
  • 使用这个驱动类怎么查不出数据,求指教

添加回复:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。