PDO连金仓数据库,我把踩过的坑整理了一下(上篇)
PDO连金仓数据库我把踩过的坑整理了一下上篇先说说为什么写这篇去年做一个内部管理系统后端用PHP数据库要换成金仓。我当时心想PHP用PDO连数据库不是很标准的事吗换驱动就行了呗。结果一搞发现事情没那么简单。金仓的PDO驱动需要自己编译还要配置php.ini跟MySQL那种装个扩展就完事的体验完全不一样。折腾了两天才跑通。今天把过程记下来希望能帮到后面的人。一、关于PDO和金仓驱动1.1 PDO是什么PDOPHP Data Objects是PHP官方提供的数据库抽象层。它定义了一套统一的接口不管你连MySQL还是Oracle还是别的数据库代码写法是一样的。// 连MySQL$pdonewPDO(mysql:hostlocalhost;dbnametest,$user,$pass);// 连金仓写法几乎一样$pdonewPDO(kdb:hostlocalhost;dbnametest;port54321,$user,$pass);这就是PDO的好处换数据库大部分代码不用改。1.2 金仓的PDO驱动PDO本身只是个接口具体干活要靠数据库驱动。金仓的驱动叫pdo_kdbLinux下是pdo_kdb.so文件Windows下是php_pdo_kdb.dll。这个驱动不是PHP自带的需要单独下载安装。金仓官网提供了各个PHP版本的驱动包得选对版本。二、安装配置2.1 查看PHP版本拿到驱动包之前先搞清楚自己的PHP版本。php-v# 输出类似PHP 7.4.33 (cli)再看是线程安全还是非线程安全NTSphp-i|grepThread Safety# 或者php-m驱动包默认提供的是NTS版本的。如果是TS版本需要找客服要。2.2 下载对应驱动金仓官网提供这些PHP版本的驱动PHP 5.6PHP 7.0 到 7.4PHP 8.0 到 8.4下载的时候一定要对上号。我用的是PHP 7.4就下了7.4的驱动包。2.3 放置驱动文件下载解压后会得到一个pdo_kdb.so文件Windows下是php_pdo_kdb.dll。把它放到PHP扩展目录下。扩展目录在哪php-i|grepextension_dir我机器上输出的是/usr/lib/php/extensions/no-debug-non-zts-20190902。把文件放进去就行。2.4 配置php.ini找到php.ini文件的位置php-i|grepLoaded Configuration File打开php.ini找到extension_dir这一行确认指向的是扩展目录。然后添加一行extensionpdo_kdb.so如果之前有其他PDO驱动比如pdo_mysql保留也没关系可以共存。2.5 验证是否加载成功php-m|greppdo_kdb看到pdo_kdb说明加载成功了。如果看不到检查驱动文件在不在扩展目录里php.ini里有没有写对有没有重启PHP-FPMsystemctl restart php-fpm三、连接数据库3.1 DSN格式PDO连金仓的DSN数据源名称格式是$dsnkdb:hostlocalhost;dbnameTEST;port54321;参数说明参数说明默认值host数据库IPlocalhostport端口54321dbname数据库名无user用户名无password密码无注意前面的kdb:不是pgsql:也不是mysql:。3.2 完整连接代码?php$dsnkdb:host127.0.0.1;dbnameTEST;port54321;$userSYSTEM;$password123456;try{$pdonewPDO($dsn,$user,$password,[PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODEPDO::FETCH_ASSOC]);echo连接成功\n;}catch(PDOException$e){echo连接失败: .$e-getMessage().\n;}?ERRMODE_EXCEPTION这个模式推荐打开。默认PDO出错只是返回false很难排查问题。开了异常模式后哪行代码出问题一目了然。3.3 连接不上怎么办如果连不上按顺序检查ping一下数据库IP看网络通不通用ksql命令行连一下看账号密码对不对确认端口是不是54321金仓默认端口不是5432检查数据库名大小写我遇到最多的就是端口写错习惯了MySQL的3306写成5432了。四、基本操作4.1 查询数据$stmt$pdo-query(SELECT id, name, age FROM users WHERE age 18);while($row$stmt-fetch()){echo姓名: .$row[name]., 年龄: .$row[age].\n;}fetch()一次拿一行适合结果集大的时候。数据量小的话也可以用fetchAll()一次性全拿。$rows$stmt-fetchAll();foreach($rowsas$row){echo$row[name].\n;}4.2 带参数查询永远不要直接拼接SQL。下面这种写法是绝对禁止的// 千万别这么写$name$_GET[name];$pdo-query(SELECT * FROM users WHERE name $name);正确的做法是用预处理语句$stmt$pdo-prepare(SELECT * FROM users WHERE name ?);$stmt-execute([$_GET[name]]);$user$stmt-fetch();或者用命名占位符$stmt$pdo-prepare(SELECT * FROM users WHERE name :name AND age :age);$stmt-execute([:name张三,:age18]);$users$stmt-fetchAll();预处理语句不光能防SQL注入重复执行的时候性能也好。4.3 插入数据$stmt$pdo-prepare(INSERT INTO users (name, email) VALUES (?, ?));$stmt-execute([李四,lisitest.com]);// 获取刚插入的ID如果表有自增列$id$pdo-lastInsertId();4.4 更新和删除// 更新$stmt$pdo-prepare(UPDATE users SET email ? WHERE id ?);$stmt-execute([newemailtest.com,1]);// 删除$stmt$pdo-prepare(DELETE FROM users WHERE id ?);$stmt-execute([1]);// 影响行数echo$stmt-rowCount();五、事务处理事务可以保证一组操作要么全部成功要么全部失败。比如转账扣A账户和加B账户必须同时成功或同时失败。try{$pdo-beginTransaction();// 从A账户扣100$stmt$pdo-prepare(UPDATE accounts SET balance balance - 100 WHERE id ?);$stmt-execute([1]);// 往B账户加100$stmt$pdo-prepare(UPDATE accounts SET balance balance 100 WHERE id ?);$stmt-execute([2]);$pdo-commit();echo转账成功\n;}catch(Exception$e){$pdo-rollBack();echo转账失败: .$e-getMessage().\n;}事务有几个要注意的地方表必须是InnoDB类型金仓默认支持事务事务里不要做耗时操作否则会长时间锁表事务里不要混合MyISAM表不支持事务六、一个完整示例?php$dsnkdb:host127.0.0.1;dbnameTEST;port54321;$userSYSTEM;$password123456;try{$pdonewPDO($dsn,$user,$password,[PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION]);// 建表$pdo-exec(CREATE TABLE IF NOT EXISTS php_test ( id SERIAL PRIMARY KEY, name VARCHAR(100), email VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ));// 插入$stmt$pdo-prepare(INSERT INTO php_test (name, email) VALUES (?, ?));$stmt-execute([张三,zhangsantest.com]);echo插入成功ID: .$pdo-lastInsertId().\n;// 查询$stmt$pdo-query(SELECT * FROM php_test);while($row$stmt-fetch()){echoID:{$row[id]}, 姓名:{$row[name]}, 邮箱:{$row[email]}\n;}// 更新$stmt$pdo-prepare(UPDATE php_test SET email ? WHERE name ?);$stmt-execute([newemailtest.com,张三]);echo更新了 .$stmt-rowCount(). 行\n;// 删除$stmt$pdo-prepare(DELETE FROM php_test WHERE name ?);$stmt-execute([张三]);echo删除了 .$stmt-rowCount(). 行\n;}catch(PDOException$e){echo错误: .$e-getMessage().\n;}?七、小结上篇主要讲了PDO是什么金仓的PDO驱动叫pdo_kdb怎么装驱动、配php.ini、验证是否成功怎么连接数据库、写查询、插入、更新、删除事务怎么用下篇会讲一些生产环境更需要的东西预处理语句详解、大对象操作、COPY命令批量导入导出数据。欢迎继续看。