Giter Club home page Giter Club logo

mysqli's Introduction

Mysqli

本Mysqli构造器基于 https://github.com/ThingEngineer/PHP-MySQLi-Database-Class 移植实现的协程安全版本。

单元测试

./vendor/bin/co-phpunit tests

安装

composer require easyswoole/mysqli

Client实例

$config = new \EasySwoole\Mysqli\Config([
        'host'          => '',
        'port'          => 3300,
        'user'          => '',
        'password'      => '',
        'database'      => '',
        'timeout'       => 5,
        'charset'       => 'utf8mb4',
]);

$client = new \EasySwoole\Mysqli\Client($config);

go(function ()use($client){
    //构建sql
    $client->queryBuilder()->get('user_list');
    //执行sql
    var_dump($client->execBuilder());
});

查询构造器

QueryBuilder是一个SQL构造器,用来构造prepare sql。例如:

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

//执行条件构造逻辑
$builder->where('col1',2)->get('my_table');

//获取上次条件构造的预处理sql语句
echo $builder->getLastPrepareQuery();
// SELECT  * FROM whereGet WHERE  col1 = ? 

//获取上次条件构造的sql语句
echo $builder->getLastQuery();
//SELECT  * FROM whereGet WHERE  col1 = 2 

//获取上次条件构造的预处理sql语句所以需要的绑定参数
echo $builder->getLastBindParams();
//[2]

GET

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// 获取全表
$builder->get('getTable');

// 表前缀
$builder->setPrefix('easyswoole_')->get('getTable');

// 获取总数。下面两个结果相同
$builder->withTotalCount()->where('col1', 1, '>')->get('getTable');
$builder->setQueryOption('SQL_CALC_FOUND_ROWS')->where('col1', 1, '>')->get('getTable');

// fields。支持一维数组或字符串
$builder->fields('col1, col2')->get('getTable');
$builder->get('getTable', null, ['col1','col2']);

// limit 1。下面两个结果相同
$builder->get('getTable', 1)
$builder->getOne('getTable')

// offset 1, limit 10
$builder->get('getTable',[1, 10])

// 去重查询。
$builder->get('getTable', [2,10], ['distinct col1','col2']);

// where查询
$builder->where('col1', 2)->get('getTable');

// where查询2
$builder->where('col1', 2, '>')->get('getTable');

// 多条件where
$builder->where('col1', 2)->where('col2', 'str')->get('getTable');

// whereIn, whereNotIn, whereLike,修改相应的operator(IN, NOT IN, LIKE)
$builder->where('col3', [1,2,3], 'IN')->get('getTable');

// orWhere
$builder->where('col1', 2)->orWhere('col2', 'str')->get('getTable');

Join

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// join。默认INNER JOIN
$builder->join('table2', 'table2.col1 = getTable.col2')->get('getTable');
$builder->join('table2', 'table2.col1 = getTable.col2', 'LEFT')->get('getTable');

// join Where
$builder->join('table2','table2.col1 = getTable.col2')->where('table2.col1', 2)->get('getTable');

GroupBy Having

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// groupBy. 
$builder->groupBy('col1')->get('getTable');
$builder->where('col1',2)->groupBy('col1')->get('getTable');

// having
$builder->groupBy('col1')->having('col1')->get('getTable');
$builder->groupBy('col1')->having('col1', 1, '>')->get('whereGet');

// and having. having第4个参数默认是 `AND`,默认多having是`且`关系
$builder->groupBy('col1')->having('col1', 1, '>')->having('col2', 1, '>')->get('whereGet');

// or having. 下面两种方法效果相等
$builder->groupBy('col1')->having('col1', 1, '>')->orHaving('col2', 1, '>')->get('whereGet');
$builder->groupBy('col1')->having('col1', 1, '>')->having('col2', 1, '>', 'OR')->get('whereGet');

OrderBy

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// orderBy. 默认DESC
$builder->orderBy('col1', 'ASC')->get('getTable');
$builder->where('col1',2)->orderBy('col1', 'ASC')->get('getTable');

Union

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// union. 相当于 adminTable UNION userTable
$builder->union((new QueryBuilder)->where('userName', 'user')->get('userTable'))
    ->where('adminUserName', 'admin')->get('adminTable');

UPDATE

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// update 
$builder->update('updateTable', ['a' => 1]);

// limit update
$builder->update('updateTable', ['a' => 1], 5);

// where update
$builder->where('whereUpdate', 'whereValue')->update('updateTable', ['a' => 1]);

DELETE

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// delete all
$builder->delete('deleteTable');

// limit delete
$builder->delete('deleteTable', 1);

// where delete
$builder->where('whereDelete', 'whereValue')->delete('deleteTable');

INSERT

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// insert into
$builder->insert('insertTable', ['a' => 1, 'b' => "b"]);

// replace into
$builder->replace('replaceTable', ['a' => 1]);

SUBQUERY

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// 单一where条件子查询
// 等同于 SELECT * FROM users WHERE id in ((SELECT userId FROM products WHERE  qty > 2))
$sub = $this->builder::subQuery();
$sub->where("qty", 2, ">");
$sub->get("products", null, "userId");
$builder->where("id", $sub, 'in')->get('users');

// 多where条件子查询
// 等同于 SELECT * FROM users WHERE col2 = 1 AND id in ((SELECT userId FROM products WHERE  qty > 2))
$sub = $this->builder::subQuery();
$sub->where ("qty", 2, ">");
$sub->get ("products", null, "userId");
$this->builder->where('col2',1)->where ("id", $sub, 'in')->get('users');

// INSERT 包含子结果集
// 等同于 INSERT INTO products (`productName`, `userId`, `lastUpdated`) VALUES ('test product', (SELECT name FROM users WHERE  id = 6  LIMIT 1), NOW())
$userIdQ = $this->builder::subQuery();
$userIdQ->where ("id", 6);
$userIdQ->getOne ("users", "name");
$data = Array (
    "productName" => "test product",
    "userId" => $userIdQ,
    "lastUpdated" => $this->builder->now()
);
$this->builder->insert ("products", $data);

LOCK

use EasySwoole\Mysqli\QueryBuilder;

$builder = new QueryBuilder();

// FOR UPDATE 排它锁。下面两个方法效果相同
$builder->setQueryOption("FOR UPDATE")->get('getTable');
$builder->selectForUpdate(true)->get('getTable');

// FOR UPDATE NOWAIT
$builder->selectForUpdate(true, 'NOWAIT')->get('getTable');
// FOR UPDATE WAIT Second
$builder->selectForUpdate(true, 'WAIT 5')->get('getTable');
// FOR UPDATE SKIP LOCKED
$builder->selectForUpdate(true, 'SKIP LOCKED')->get('getTable');

//  LOCK IN SHARE MODE。共享锁
$builder->lockInShareMode()->get('getTable');
$builder->setQueryOption(['LOCK IN SHARE MODE'])->get('getTable');

// LOCK TABLES 获取表锁
$builder->lockTable('table');

// UNLOCK TABLES 释放表锁
$builder->unlockTable('table');

mysqli's People

Contributors

chenjing0521 avatar edenleung avatar evalor avatar hanwenbo avatar kiss291323003 avatar kyour-cn avatar player626 avatar tioncico avatar xuanyanwow avatar xuesilf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

mysqli's Issues

where null查询会查不到数据

  1. where('time', null) // time = null ×
  2. where('time', null, '=') // time = null ×
  3. where(['time' => null]) // time = null ×
  4. where('time', null, 'is') // time is null √
  5. where('time is null') // time is null √

以上1-3常用的方式会被解析成错误的where条件, 导致查询null值失败

auto add back quote

image
在数据库字段为关键词时,直接使用field方法声明字段会报错,如下:
image
需要手动在字段上增加“``”反引号才不会报错,querybuilder这里是不是应该给字段自动增加一下反引号

不支持where括号嵌套语句,只能手写,但是特殊情况相当麻烦,比如in多值条件特别麻烦

贡上一个简单的函数,功能非常羞涩

public function buildWhere($fields)
{
if (count($fields) > 1 && isset($fields[0]) && is_string($fields[0])) {
$tmpFill = [null, null, '='];
list($field, $params, $operator) = $fields + $tmpFill;
switch (strtolower($operator)) {
case 'not in':
case 'in':
$inSql = '';
foreach ($params as $param) {
if (is_string($param)) {
$inSql .= ", '{$param}' ";
} else {
$inSql .= ", {$param} ";
}
}
$newSql = " " . $field . " " . strtoupper($operator) . "(" . ltrim($inSql, ',') . ") ";
break;
case 'not between':
case 'between':
$beginStr = is_string($params[0]) ? "'{$params[0]}'" : $params[0];
$endStr = is_string($params[1]) ? "'{$params[1]}'" : $params[1];
$newSql = " {$field} " . strtoupper($operator) . " {$beginStr} AND {$endStr} ";
break;
default:
if (is_string($params)) {
$newSql = " " . $field . " " . strtoupper($operator) . " '" . $params . "' ";
} elseif ($params === null) {
$newSql = " " . $field . " " . strtoupper($operator) . " NULL";
} else {
$newSql = " " . $field . " " . strtoupper($operator) . " " . $params . " ";
}
}
return $newSql;
} else {
$whereArray = [];
$cond = $fields[count($fields) - 1];
if (is_string($cond) && in_array(strtoupper($cond), ['OR', 'AND'])) {
$cond = strtoupper($cond);
unset($fields[count($fields) - 1]);
} else {
$cond = ' AND ';
}
foreach ($fields as $value) {
$whereArray[] = $this->buildWhere($value);
}
return " ( " . implode($cond, $whereArray) . " ) ";
}

}

使用方法:

$db = Mysql::defer('mysql');
$where = $db->buildWhere([
["ip", "%127.0.0.1%", 'like'],
[
['id', '1', '>'],
[
['id', ['5', 10], 'not in'],
['id', '1'],
'or'
],
["username", "abc"],
'or'
],
'and'
]);
$db->where($where)->get('user');
// "SELECT * FROM user WHERE (
// ip LIKE '%127.0.0.1%' AND (
// id > '1' OR (
// id NOT IN( '5' , 10 ) OR
// id = '1' )
// OR username = 'abc'
// )
// ) "

model 创建链接池使用的引用变量 自己测试没问题 想听一下权威的建议

public function __construct(&$transmit, $params)
{
$this->transmit = &$transmit;
$this->params = $params;
if (isset($this->transmit['dbs'][$this->database])
&& $this->transmit['dbs'][$this->database] instanceof MysqlObject) {
$this->db = $this->transmit['dbs'][$this->database];
} else {
$db = PoolManager::getInstance()->getPool($this->getMysqlPool())->getObj(Config::getInstance()->getConf('mysql.' . $this->database . '.POOL_TIME_OUT'));
$this->db = $this->transmit['dbs'][$this->database] = $db;
}
if (!($this->db instanceof MysqlObject)) {
throw new \Exception($this->database . 'mysql pool is empty');
}
}

这种方式调用的mysql池 自己测试没有问题

是在controller 和 model 中使用getModel调用 model

/**

  • @var $serviceModel ServiceModel
    */
    $serviceModel = $this->getModel(ServiceModel::class);
    protected function getModel($model)
    {
    if (!class_exists($model)) {
    $this->error('model 类 ' . $model . ' 不存在!');
    }
    $obj = new $model($this->transmit, $this->params);
    return $obj;
    }
    释放连接池也是在 如 controller gc()中完成
    但是之前有人在群里说这种方式 怎么死的也不会知道 就是心理有点怪怪的
    不知道这种方式会不会真有问题

只是想用这种方式实现 没有mysql代理情况下的分库 和 跨model的事务嵌套

使用计数器开启嵌套事务出现问题在初始化的时候没有 导致回滚出错+计数器

改造后:

public function startTransactionWithCount($resetLevel = false)
{
// 强制结束上次事务并重开
if ($resetLevel) {
$this->transactionLevel = 0;
$this->rollback();
$this->commit();
}
++$this->transactionLevel;
if ($this->transactionLevel == 1) {
$this->startTransaction();
}
}

public function commitWithCount()
{
if ($this->transactionLevel == 1) {
$this->commit();
}
$this->transactionLevel--;
}

public function rollbackWithCount($commit = true)
{
if ($this->transactionLevel == 1) {
$this->transactionLevel = 0;
$this->rollback($commit);
} else {
$this->transactionLevel--;
}
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.