范神经 发表于 2024-8-2 03:05:49

ThinkPHP6支持金仓数据库(Kingbase)解决无法使用模型查询问题

参考了很多前人的文章,最后只支持Db::query原生查询,不支持thinkphp数据模型方法,这在实际项目中是很难接受的,特分享出解决方案。
先按照流程配置如下:
1.准备工作
首先确认PHP支持金仓数据库的扩展,可以去金仓官网下载,安装配置(详细配置略过……)。
使用 php -m 命令检查,显示有 pdo_kdb即可。 这里注意一下libpq.dll的版本要>=10,否则会报错误。


2,新增金仓数据库的connenter类
进到ThinkPHP项目目录下的vendor\topthink\think-orm\src\db\connector\下,复制Pgsql.php为Kingbase.php(基于pgsql修改),修改文件中的类名为Kingbase。
/**
* Kingbase数据库驱动
*/
class Kingbase extends PDOConnection找到 protected function parseDsn(array $config): string 方法,修改该方法下代码:
$dsn = 'pgsql:dbname=' . $config['database'] . ';host=' . $config['hostname'];
//修改为:
$dsn = 'kdb:host=' . $config['hostname'] . ';dbname=' . $config['database'];3.新增金仓数据库的builder类
进到ThinkPHP项目目录下的vendor\topthink\think-orm\src\db\builder\下,复制Pgsql.php为Kingbase.php,同样修改文件中的类名为Kingbase。
/**
* Kingbase数据库驱动
*/
class Kingbase extends Builder其他代码不需要修改。
 
4.ThinkPHP配置文件
三处mysql都修改为kingbase:
return [
    // 默认使用的数据库连接配置
    'default'         => env('database.driver', 'kingbase'),

……

// 数据库连接配置信息
    'connections'   => [
      'kingbase' => [
            // 数据库类型
            'type'            => env('database.type', 'kingbase'),
            // 服务器地址
            'hostname'      => env('database.hostname', 'localhost'),
            // 数据库名
            'database'      => env('database.database', 'TEST'),
            // 用户名
            'username'      => env('database.username', 'SYSTEM'),
            // 密码
            'password'      => env('database.password', '123456'),
            // 端口
            'hostport'      => env('database.hostport', '54321'),
            // 数据库连接参数
            'params'          => [],
            // 数据库编码默认采用utf8
            'charset'         => env('database.charset', 'utf8'),
            // 数据库表前缀
            'prefix'          => env('database.prefix', ''),

……

      // 更多的数据库配置信息
    ],
];到此处,和其他文章介绍的方案都一样,现在介绍重点,重点就在这个执行的sql语句上,这个语句执行了很多次都不成功,不是提示table_msg函数不存在,就是其他的一些错误,后来在KStudio中单独创建各个函数,依次排除问题解决。
现在分享3个函数的创建语句,需要到对应的模式下,新建查询进行导入:
CREATE OR REPLACE FUNCTION public .pgsql_type(a_type varchar ) RETURNS varchar AS
DECLARE
v_type varchar ;
BEGIN
   IF a_type='int8' THEN
          v_type:='bigint' ;
   ELSIF a_type='int4' THEN
          v_type:='integer' ;
   ELSIF a_type='int2' THEN
          v_type:='smallint' ;
   ELSIF a_type='bpchar' THEN
          v_type:='char' ;
ELSE
          v_type:=a_type;
END IF;
RETURN v_type;
END 
CREATE OR REPLACE FUNCTION public .table_msg(a_schema_name varchar , a_table_name varchar ) RETURNS SETOF tablestruct AS
DECLARE
v_ret public .tablestruct;

v_oid oid;

v_sql text;

v_rec RECORD;

v_key varchar ;

BEGIN
    SELECT
    pg_class.oid INTO v_oid
    FROM
    pg_class
INNER JOIN pg_namespace ON
    (
      pg_class.relnamespace = pg_namespace.oid
            AND lower (pg_namespace.nspname) = a_schema_name
    )
    WHERE
    pg_class.relname = a_table_name;

IF NOT FOUND THEN
         RETURN ;
END IF;

v_sql = '
   SELECT
         sys_attribute.attname AS fields_name,
         sys_attribute.attnum AS fields_index,
         pgsql_type(sys_type.typname::varchar) AS fields_type,
         sys_attribute.atttypmod-4 as fields_length,
         CASE WHEN sys_attribute.attnotnull THEN ' 'not null' '
         ELSE ' '' '
         END AS fields_not_null,
         sys_attrdef.adbin AS fields_default,
         sys_description.description AS fields_comment
   FROM
         sys_attribute
         INNER JOIN sys_class ON sys_attribute.attrelid = sys_class.oid
         INNER JOIN sys_type ON sys_attribute.atttypid = sys_type.oid
         LEFT OUTER JOIN sys_attrdef ON sys_attrdef.adrelid = sys_class.oid AND sys_attrdef.adnum = sys_attribute.attnum
         LEFT OUTER JOIN sys_description ON sys_description.objoid = sys_class.oid AND sys_description.objsubid = sys_attribute.attnum
   WHERE
         sys_attribute.attnum > 0
         AND attisdropped <> ATTISLOCAL
ORDER BY sys_attribute.attnum' ;

FOR v_rec IN EXECUTE v_sql LOOP
         v_ret.fields_name = v_rec.fields_name;

v_ret.fields_type = v_rec.fields_type;

IF v_rec.fields_length > 0 THEN
            v_ret.fields_length := v_rec.fields_length;
ELSE
            v_ret.fields_length := NULL ;
END IF;

v_ret.fields_not_null = v_rec.fields_not_null;

v_ret.fields_default = v_rec.fields_default;

v_ret.fields_comment = v_rec.fields_comment;

SELECT
    constraint_name INTO v_key
FROM
    information_schema.key_column_usage
WHERE
    table_schema = a_schema_name
    AND table_name = a_table_name
    AND column_name = v_rec.fields_name;

IF FOUND THEN
            v_ret.fields_key_name = v_key;
ELSE
            v_ret.fields_key_name = '' ;
END IF;

RETURN NEXT v_ret;
END LOOP;

RETURN ;
END  
CREATE OR REPLACE FUNCTION public .table_msg(a_table_name varchar ) RETURNS SETOF tablestruct AS
DECLARE
v_ret tablestruct;
BEGIN
FOR v_ret IN SELECT * FROM table_msg('public' ,a_table_name) LOOP
    RETURN NEXT v_ret;
END LOOP;
    RETURN ;
END 
成功导入3个函数后,在函数项下会出现3个函数,如图:

 
在数据类型功能下,增加一个数据类型,数据类型配置如下:


 
 
完成此步骤后:可以在Controller控制器中执行如下代码测试:
 
try {
            $data =\app\home\model\User::select();
            dump($data );
      }catch (\Exception $e ) {
            dump($e ->getMessage());
      }


      \app\home\model\User::create(["user_name" =>"123456" ,
            "user_pwd" =>"123456" ,
            "mobile" =>"abc" ,
            "full_name" =>"abc" ,
      ]);  

 
来源:https://www.cnblogs.com/lanfengye/p/18337128
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: ThinkPHP6支持金仓数据库(Kingbase)解决无法使用模型查询问题