数据库

数据库连接池配置方式已经在连接池里讲过,这里就不重复了,直接说使用方法。

连接池配置

  1. <?php
  2. return [
  3. 'db' => [
  4. 'defaultPool' => 'alias1', // 默认连接池
  5. ],
  6. 'pools' => [
  7. // 连接池名称
  8. 'alias1' => [
  9. // 同步池子,task进程使用
  10. 'sync' => [
  11. 'pool' => [
  12. 'class' => \Imi\Db\Pool\SyncDbPool::class,
  13. 'config' => [
  14. // 池子中最多资源数
  15. // 'maxResources' => 10,
  16. // 池子中最少资源数
  17. // 'minResources' => 2,
  18. // 资源回收时间间隔,单位:秒
  19. // 'gcInterval' => 60,
  20. // 获取资源最大存活时间,单位:秒
  21. // 'maxActiveTime' => 3600,
  22. // 等待资源最大超时时间,单位:毫秒
  23. // 'waitTimeout' => 3000,
  24. // 负载均衡-轮流
  25. // 'resourceConfigMode' => ResourceConfigMode::TURN,
  26. // 负载均衡-随机
  27. // 'resourceConfigMode' => ResourceConfigMode::RANDOM,
  28. ],
  29. ],
  30. 'resource' => [
  31. 'host' => '127.0.0.1',
  32. 'username' => 'root',
  33. 'password' => 'root',
  34. 'database' => 'database',
  35. // 'port' => '3306',
  36. // 'timeout' => '建立连接超时时间',
  37. // 'charset' => '',
  38. // 'strict_type' => false, //开启严格模式,返回的字段将自动转为数字类型
  39. ],
  40. ],
  41. // 异步池子,worker进程使用
  42. 'async' => [
  43. 'pool' => [
  44. 'class' => \Imi\Db\Pool\CoroutineDbPool::class,
  45. 'config' => [
  46. // 同上
  47. ],
  48. ],
  49. // resource也可以定义多个连接
  50. 'resource' => [
  51. [
  52. 'host' => '127.0.0.1',
  53. 'username' => 'root',
  54. 'password' => 'root',
  55. 'database' => 'database',
  56. // 'timeout' => '建立连接超时时间',
  57. // 'charset' => '',
  58. // 'options' => [], // PDO连接选项
  59. ],
  60. [
  61. 'host' => '127.0.0.2',
  62. 'username' => 'root',
  63. 'password' => 'root',
  64. 'database' => 'database',
  65. // 'timeout' => '建立连接超时时间',
  66. // 'charset' => '',
  67. // 'options' => [], // PDO连接选项
  68. ]
  69. ],
  70. ],
  71. ],
  72. // 从库配置
  73. // 原连接池名后加.slave即为从库配置,非必设
  74. // 如果配置了,默认查询走从库,增删改走主库
  75. // 如果在事务中,默认都走主库
  76. 'alias1.slave' => [
  77. // 同步池子,task进程使用
  78. 'sync' => [
  79. 'pool' => [
  80. 'class' => \Imi\Db\Pool\SyncDbPool::class,
  81. 'config' => [
  82. // 池子中最多资源数
  83. // 'maxResources' => 10,
  84. // 池子中最少资源数
  85. // 'minResources' => 2,
  86. // 资源回收时间间隔,单位:秒
  87. // 'gcInterval' => 60,
  88. // 获取资源最大存活时间,单位:秒
  89. // 'maxActiveTime' => 3600,
  90. // 等待资源最大超时时间,单位:毫秒
  91. // 'waitTimeout' => 3000,
  92. ],
  93. ],
  94. 'resource' => [
  95. 'host' => '127.0.0.1',
  96. 'username' => 'root',
  97. 'password' => 'root',
  98. 'database' => 'database',
  99. // 'port' => '3306',
  100. // 'timeout' => '建立连接超时时间',
  101. // 'charset' => '',
  102. // 'strict_type' => false, //开启严格模式,返回的字段将自动转为数字类型
  103. ],
  104. ],
  105. // 异步池子,worker进程使用
  106. 'async' => [
  107. 'pool' => [
  108. 'class' => \Imi\Db\Pool\CoroutineDbPool::class,
  109. 'config' => [
  110. // 同上
  111. ],
  112. ],
  113. 'resource' => [
  114. 'host' => '127.0.0.1',
  115. 'username' => 'root',
  116. 'password' => 'root',
  117. 'database' => 'database',
  118. // 'timeout' => '建立连接超时时间',
  119. // 'charset' => '',
  120. // 'options' => [], // PDO连接选项
  121. ],
  122. // uri 写法
  123. // 'resource' => [
  124. // 'tcp://192.168.0.222/?username=root&password=root&database=db_test&timeout=60',
  125. // 'tcp://192.168.0.222/?username=root&password=root&database=db_test&timeout=60',
  126. // ],
  127. // 'resource' => 'tcp://192.168.0.222/?username=root&password=root&database=db_test&timeout=60;tcp://192.168.0.222/?username=root&password=root&database=db_test&timeout=60',
  128. ],
  129. ]
  130. ],
  131. ];

直接操作 Db 对象

  1. // 获取新的数据库连接实例
  2. $db = Db::getNewInstance();
  3. // 读库
  4. $db = Db::getNewInstance($poolName, QueryType::READ);
  5. // 写库
  6. $db = Db::getNewInstance($poolName, QueryType::WRITE);
  7. // 获取数据库连接实例,每个RequestContext中共用一个
  8. $db = Db::getInstance();
  9. // 读库
  10. $db = Db::getInstance($poolName, QueryType::READ);
  11. // 写库
  12. $db = Db::getInstance($poolName, QueryType::WRITE);
  13. // 释放连接,回归连接池
  14. Db::release($db);
  15. $returnValue = Db::use(function(IDb $db){
  16. // 操作 $db
  17. return 'imi';
  18. }); // imi

连贯操作

IMI 中数据库查询连贯操作都来自于查询器,查询器的创建方式:

  1. use Imi\Db\Db;
  2. $query = Db::query();

事务

手动控制事务:

  1. // 开启事务
  2. Db::getInstance()->beginTransaction();
  3. // 提交事务
  4. Db::getInstance()->commit();
  5. // 回滚事务
  6. Db::getInstance()->rollBack();

获取连接顺带自动开启/提交/回滚事务:

  1. Db::transUse(function(IDb $db){
  2. });
  3. Db::transUse(function(IDb $db){
  4. }, $poolName, QueryType::WRITE);

获取连接后,想要使用某个连接,执行事务操作,自动开启/提交/回滚事务:

  1. $db = Db::getInstance();
  2. Db::trans($db, function(IDb $db){
  3. });

自动事务处理

@Transaction 注解,类:Imi\Db\Annotation\Transaction

这个注解可以加在任意方法上,在方法调用前开启事务,在方法中抛出异常时回滚事务,方法成功返回时提交事务。

@Transaction

@Transaction(autoCommit="自动提交事务true/false,默认为true")

事务类型:

事务嵌套(默认)

@Transaction(type=TransactionType::NESTING)

该方法必须在事务中被调用

@Transaction(type=TransactionType::REQUIREMENT)

如果当前不在事务中则开启事务

@Transaction(type=TransactionType::AUTO)

部分回滚:

@Transaction(rollbackType=RollbackType::PART, rollbackLevels="回滚层数,默认为1")

指定表 (table/from)

  1. // 指定表名
  2. Db::query()->table('tb_test');
  3. // 指定表名并且设置别名
  4. Db::query()->table('tb_test', 'test');
  5. // 指定表名和数据库名
  6. Db::query()->table('tb_test', null, 'db1');
  7. // 传入参数原样代入到SQL中
  8. Db::query()->tableRaw('tb_test');

table()tableRaw() 也可以使用 from()fromRaw() 代替。

distinct

  1. // 结果唯一
  2. Db::query()->distinct();
  3. // 结果不唯一
  4. Db::query()->distinct(false);

指定字段 (field)

  1. // 指定一个字段
  2. Db::query()->field('id');
  3. // 指定多个字段,也支持设置别名。空格和as都支持
  4. Db::query()->field('id', 'name1 name', 'age1 as age');
  5. // 和上面的用法等同
  6. Db::query()->field(['id', 'name1 name', 'age1 as age']);
  7. // 传入参数原样代入到SQL中
  8. Db::query()->fieldRaw('id, name1 name, age1 as age');

条件 where

where

  1. // id = 1
  2. Db::query()->where('id', '=', 1);
  3. // id > 1
  4. Db::query()->where('id', '>', 1);
  5. // title like '%test%'
  6. Db::query()->where('title', 'like', '%test%');
  7. // id between 1 and 10
  8. Db::query()->where('id', 'between', [1, 10]);
  9. // id not between 1 and 10
  10. Db::query()->where('id', 'not between', [1, 10]);
  11. // or id = 1
  12. Db::query()->where('id', '=', 1, 'or');
  13. Db::query()->orWhere('id', '=', 1);

TP 风格 where

  1. // select * from `tb_test` where (`id` = 1 or (`id` = 2 ) and `title` like '%test%' and `age` > 18 and (`id` = 2 or (`id` = 3 ) ) )
  2. Db::query()->from('tb_test')->whereEx([
  3. 'id' => 1,
  4. 'or' => [
  5. 'id' => 2,
  6. ],
  7. 'title' => ['like', '%test%'],
  8. 'age' => ['>', 18],
  9. 'and' => [
  10. 'id' => 2,
  11. 'or' => [
  12. 'id' => 3,
  13. ]
  14. ]
  15. ]);

whereRaw

  1. // 传入参数原样代入到SQL中
  2. Db::query()->whereRaw('id >= 1');
  3. // 传入参数原样代入到SQL中,并且为or条件
  4. Db::query()->whereRaw('id >= 1', 'or');
  5. Db::query()->orWhereRaw('id >= 1');

whereBrackets

  1. // where id = 1 or (age < 14)
  2. Db::query()->where('id', '=', 1)->whereBrackets(function(){
  3. // 直接返回字符串
  4. return 'age < 14';
  5. }, 'or');
  6. // where id = 1 or (age < 14)
  7. Db::query()->where('id', '=', 1)->whereBrackets(function(){
  8. // 直接返回字符串
  9. return new \Imi\Db\Query\Where\Where('age', '<', 14);
  10. }, 'or');
  11. Db::query()->where('id', '=', 1)->orWhereBrackets(function(){
  12. // 直接返回字符串
  13. return new \Imi\Db\Query\Where\Where('age', '<', 14);
  14. });

whereStruct

  1. // or age < 14
  2. Db::query()->whereStruct(new \Imi\Db\Query\Where\Where('age', '<', 14), 'or');
  3. Db::query()->orWhereStruct(new \Imi\Db\Query\Where\Where('age', '<', 14));

其它

  1. // or age between 1 and 14
  2. Db::query()->whereBetween('age', 1, 14, 'or');
  3. Db::query()->orWhereBetween('age', 1, 14);
  4. // or age not between 1 and 14
  5. Db::query()->whereNotBetween('age', 1, 14, 'or');
  6. Db::query()->orWhereNotBetween('age', 1, 14);
  7. // or age in (1,2,3)
  8. Db::query()->whereIn('age', [1, 2, 3], 'or');
  9. Db::query()->orWhereIn('age', [1, 2, 3]);
  10. // or age not in (1,2,3)
  11. Db::query()->whereNotIn('age', [1, 2, 3], 'or');
  12. Db::query()->orWhereNotIn('age', [1, 2, 3]);
  13. // or age is null
  14. Db::query()->whereIsNull('age', 'or');
  15. Db::query()->orWhereIsNull('age');
  16. // or age is not null
  17. Db::query()->whereIsNotNull('age', 'or');
  18. Db::query()->orWhereIsNotNull('age');

JSON 字段支持

看如下代码,datajson类型字段,查询json对象中的member.age11的记录

  1. Db::query()->where('data->member.age', '=', 11)->select();

join

  1. // select * from tb_test1 left join tb_test2 on tb_test1.aid = tb_test2.bid
  2. Db::query()->table('tb_test1')->join('tb_test2', 'tb_test1.aid', '=', 'tb_test2.bid');
  3. // select * from tb_test1 left join tb_test2 as test2 on tb_test1.aid = test2.bid
  4. Db::query()->table('tb_test1')->join('tb_test2', 'tb_test1.aid', '=', 'test2.bid', 'test');
  5. // select * from tb_test1 right join tb_test2 on tb_test1.aid = tb_test2.bid and tb_test1.age > 14
  6. Db::query()->table('tb_test1')->join('tb_test2', 'tb_test1.aid', '=', 'tb_test2.bid', null, new \Imi\Db\Query\Where\Where('tb_test1.age', '>', '14'), 'right');
  7. // select * from tb_test1 left join tb_test2 on tb_test1.aid = tb_test2.bid
  8. Db::query()->table('tb_test1')->joinRaw('left join tb_test2 on tb_test1.aid = tb_test2.bid');
  9. // 下面三种用法,第5个参数都支持传Where
  10. // left join
  11. Db::query()->table('tb_test1')->leftJoin('tb_test2', 'tb_test1.aid', '=', 'tb_test2.bid');
  12. // right join
  13. Db::query()->table('tb_test1')->rightJoin('tb_test2', 'tb_test1.aid', '=', 'tb_test2.bid');
  14. // cross join
  15. Db::query()->table('tb_test1')->crossJoin('tb_test2', 'tb_test1.aid', '=', 'tb_test2.bid');

order

  1. // order by id asc, age desc
  2. Db::query()->order('id')->order('age', 'desc');
  3. // order by id desc
  4. Db::query()->orderRaw('id desc');

group by

  1. // group by id, name
  2. Db::query()->group('id', 'name');
  3. // group by sum(id)
  4. Db::query()->groupRaw('sum(id)');

having

having()用法同where()

havingRaw()用法同whereRaw()

havingBrackets()用法同whereBrackets()

havingStruct()用法同whereStruct()

分页查询

  1. // limit 900, 100
  2. Db::query()->page(10, 100);
  3. // limit 10, 1
  4. Db::query()->offset(10)->limit(1);
  5. // limit 1
  6. Db::query()->limit(1);

查询执行

查询记录

查询单行

  1. $result = Db::query()->table('tb_test')->select();
  2. $result->get(); // 数组
  3. $result->get($className); // $className对应的类对象

查询多行

  1. $result = Db::query()->table('tb_test')->select();
  2. $result->getArray(); // 数组内嵌套数组
  3. $result->getArray($className); // 数组内嵌套$className对应的类对象
  4. $result->getRowCount(); // 获取查询出的记录行数

聚合函数

  1. // count(*)
  2. Db::query()->table('tb_test')->count();
  3. // count(id)
  4. Db::query()->table('tb_test')->count('id');
  5. // sum(id)
  6. Db::query()->table('tb_test')->sum('id');
  7. // avg(id)
  8. Db::query()->table('tb_test')->avg('id');
  9. // max(id)
  10. Db::query()->table('tb_test')->max('id');
  11. // min(id)
  12. Db::query()->table('tb_test')->min('id');
  13. // 其它自定义:test(id)
  14. Db::query()->table('tb_test')->aggregate('test', 'id');

插入记录

  1. // insert into tb_test(name, age) values('yurun', 666)
  2. $result = Db::query()->table('tb_test')->insert([
  3. 'name' => 'yurun',
  4. 'age' => 666,
  5. ]);
  6. // insert into tb_test values('yurun', 666)
  7. $result = Db::query()->table('tb_test')->insert([
  8. 'yurun',666,
  9. ]);
  10. $result->isSuccess(); // SQL是否执行成功
  11. $result->getLastInsertId(); // 获取最后插入的ID
  12. $result->getAffectedRows(); // 获取影响行数

批量插入

  1. $result = Db::query()->from('test')->batchInsert([
  2. ['name'=>'a'],
  3. ['name'=>'b'],
  4. ['name'=>'c'],
  5. ]);
  6. $result->isSuccess(); // SQL是否执行成功
  7. $result->getAffectedRows(); // 获取影响行数

更新记录

  1. // update tb_test set name = 'yurun', age = 666 where id = 1
  2. $result = Db::query()->table('tb_test')->where('id', '=', 1)->update([
  3. 'name' => 'yurun',
  4. 'age' => 666,
  5. ]);
  6. // $result使用方法同上

替换数据

  1. // replace into tb_test set id = 1, name = 'yurun', age = 666
  2. $result = Db::query()->table('tb_test')->replace([
  3. 'id' => 1,
  4. 'name' => 'yurun',
  5. 'age' => 666,
  6. ]);

递增/递减

  1. // score 递增 1
  2. $result = Db::query()->table('tb_test')
  3. ->where('id', '=', 1)
  4. ->setFieldInc('score')
  5. ->update();
  6. // score 递增 10
  7. $result = Db::query()->table('tb_test')
  8. ->where('id', '=', 1)
  9. ->setFieldInc('score', 10)
  10. ->update();
  11. // score 递减 1
  12. $result = Db::query()->table('tb_test')
  13. ->where('id', '=', 1)
  14. ->setFieldDec('score')
  15. ->update();
  16. // score 递减 10
  17. $result = Db::query()->table('tb_test')
  18. ->where('id', '=', 1)
  19. ->setFieldDec('score', 10)
  20. ->update();

update/insert/replace时使用表达式

  1. // update tb_test set score = score + 1 where id = 1
  2. $result = Db::query()->table('tb_test')
  3. ->where('id', '=', 1)
  4. ->setFieldExp('score', 'score + 1')
  5. ->update();

删除记录

  1. // delete from tb_test where id = 1
  2. $result = Db::query()->table('tb_test')->where('id', '=', 1)->delete();
  3. // $result使用方法同上

直接执行SQL

  1. $result = Db::query()->execute('select * from tb_test'));
  2. // $result使用方法同上

参数绑定

复杂的查询时,难免需要拼接 SQL,这时候就需要参数绑定来防止注入了!

  1. // where id = 123
  2. $result = Db::query()->whereRaw('id = ?')->bindValue(1, 123);
  3. $result = Db::query()->whereRaw('id = :val')->bindValue(':val', 123);
  4. // 批量绑定
  5. $result = Db::query()->bindValues([
  6. ':name' => 'yurun',
  7. ':age' => 666,
  8. ])->execute('select * from tb_test where name = :name and age = :age');

Result 用法

  1. $result = Db::query()->table('tb_test')->select();

是否执行成功

  1. $success = $result->isSuccess(); // true/false

获取最后插入的ID

用于获取新增记录的自增字段值

  1. $lastInsertId = $result->getLastInsertId(); // int

获取影响行数

  1. $rows = $result->getAffectedRows();

update 时,如果没有值被改变,可能会返回0

返回一行数据

返回数组

  1. $dataArray = $result->get();

返回对象

实例化这个类时,把数组传入构造方法

  1. $dataArray = $result->get(XXXModel::class);

返回数组列表

成员为数组

  1. $list = $result->getArray();

成员为对象

  1. $list = $result->getArray(XXXModel::class);

获取一列

  1. $ids = Db::query()->field('id')->select()->getColumn();
  2. // 结果格式:[1, 2, 3]

获取标量结果

  1. $name = Db::query()->field('name')->where('id', '=', 1)->select()->getScalar();

获取记录行数

得到取回多少条记录

  1. $rowCount = $result->getRowCount();

获取执行的SQL

  1. $sql = $result->getSql();

获取结果集

  1. $statement = $result->getStatement(); // \Imi\Db\Interfaces\IStatement