linio/database

在PDO之上提供简单抽象层的库,提供驱动抽象和连接池等功能

5.1.0 2023-02-27 17:33 UTC

README

Latest Stable Version License Build Status

Linio Database 是 Linio 框架的组件之一。它旨在通过封装 PDO 来抽象数据库访问,并提供辅助方法以加快开发速度。

安装

推荐安装 Linio Database 的方式是通过 composer

$ composer require linio/database

测试

要运行测试套件,您需要通过 composer 安装依赖,然后运行 PHPUnit。

$ composer install
$ vendor/bin/phpunit

使用

<?php

use Linio\Component\Database\DatabaseManager;

$container['db'] = function() {
    $db = new DatabaseManager();
    $driverOptions = [
        'host' => '127.0.0.1',
        'port' => 3306,
        'dbname' => 'test_db',
        'username' => 'root',
        'password' => '',
        'pdo_attributes' => [
            \PDO::ATTR_PERSISTENT => true,
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
        ],
    ];
    $db->addConnection(DatabaseManager::DRIVER_MYSQL, $driverOptions);

    return $db;
};

$rows = $container['db']->fetchAll("SELECT * FROM `table` WHERE `field` = :value", ['value' => 'test']);

角色

出于性能考虑,您可能希望对读查询使用从数据库,而对写查询使用主数据库。在创建连接时,您可以指定连接角色:ROLE_MASTERROLE_SLAVE。只允许一个主连接。

您可以拥有多个从连接。使用 weight 参数来平衡从数据库之间的查询。能够处理更多负载的数据库服务器应具有更高的 weight 参数。

要强制读查询使用主连接,在调用 fetch 方法时使用参数 forceMasterConnection

安全模式

当您使用读副本来提高数据库性能时,在主从设置中,实例之间的复制延迟可能导致在尝试读取您最近修改的数据时出现问题。

安全模式选项确保,一旦您已使用主连接发出查询,从此时起的所有查询都将使用相同的连接进行读取。

为了防止复制延迟问题,此库默认使用安全模式。要覆盖此行为,在实例化 DatabaseManager 对象时将 $safeMode 参数设置为 false。

<?php

use Linio\Component\Database\DatabaseManager;

$db = new DatabaseManager(false);

方法

addConnection

<?php

public function addConnection(string $driver, array $options, string $role = DatabaseManager::ROLE_MASTER, int $weight = 1): bool;

$masterDbOptions = ['host' => '127.0.0.1', 'port' => 3306, 'dbname' => 'master_db', 'username' => 'root','password' => ''];
$db->addConnection(DatabaseManager::DRIVER_MYSQL, $masterDbOptions, DatabaseManager::ROLE_MASTER);

$bigSlaveDbOptions = ['host' => '127.0.0.1', 'port' => 3306, 'dbname' => 'big_slave_db', 'username' => 'root','password' => ''];
$db->addConnection(DatabaseManager::DRIVER_MYSQL, $bigSlaveDbOptions, DatabaseManager::ROLE_SLAVE, 5);

$smallSlaveDbOptions = ['host' => '127.0.0.1', 'port' => 3306, 'dbname' => 'small_slave_db', 'username' => 'root','password' => ''];
$db->addConnection(DatabaseManager::DRIVER_MYSQL, $smallSlaveDbOptions, DatabaseManager::ROLE_SLAVE, 2);

getConnections

<?php

use Linio\Component\Database\Entity\Connection;

/**
 * @return Connection[]
 */
public function getConnections() : array;

$connections = $db->getConnections();

var_dump($connections);

/*
array(2) {
  'master' =>
  class Linio\Component\Database\Entity\Connection
  'slave' =>
  array(2) {
    [0] =>
    class Linio\Component\Database\Entity\Connection
    [1] =>
    class Linio\Component\Database\Entity\Connection
  }
}
*/

fetchAll

<?php

use Linio\Component\Database\Exception\FetchException;
use Linio\Component\Database\Exception\InvalidQueryException;

/**
 * @throws InvalidQueryException
 * @throws FetchException
 */
public function fetchAll(string $query, array $params = [], bool $forceMasterConnection = false): array;

$rows = $db->fetchAll("SELECT `id`,`name` FROM `table` WHERE `id` > ?", [1]);

var_dump($rows);

/*
array(2) {
  [0] =>
  array(2) {
    'id' =>
    string(1) "2"
    'name' =>
    string(6) "name 2"
  }
  [1] =>
  array(2) {
    'id' =>
    string(1) "3"
    'name' =>
    string(6) "name 3"
  }
}
*/

fetchOne

<?php

use Linio\Component\Database\Exception\FetchException;
use Linio\Component\Database\Exception\InvalidQueryException;

/**
 * @throws InvalidQueryException
 * @throws FetchException
 */
public function fetchOne(string $query, array $params = [], bool $forceMasterConnection = false): array;

$row = $db->fetchOne("SELECT `id`,`name` FROM `table` WHERE `id` = :id", ['id' => 1]);

var_dump($row);

/*
array(2) {
    'id' =>
    string(1) "1"
    'name' =>
    string(6) "name 1"
}
*/

fetchValue

<?php

use Linio\Component\Database\Exception\FetchException;
use Linio\Component\Database\Exception\InvalidQueryException;

/**
 * @throws InvalidQueryException
 * @throws FetchException
 */
public function fetchValue(string $query, array $params = [], bool $forceMasterConnection = false)

$name = $db->fetchValue("SELECT `name` FROM `table` WHERE `id` = :id", ['id' => 1]);

var_dump($row);

/*
string(6) "name 1"
*/

fetchKeyPairs

<?php

use Linio\Component\Database\Exception\FetchException;
use Linio\Component\Database\Exception\InvalidQueryException;

/**
 * @throws InvalidQueryException
 * @throws FetchException
 */
public function fetchKeyPairs(string $query, array $params = [], bool $forceMasterConnection = false): array;

$keyPairs = $db->fetchKeyPairs("SELECT `id`,`name` FROM `table` WHERE `id` > :id", ['id' => 1]);

var_dump($keyPairs);

/*
array(2) {
    '2' =>
    string(6) "name 2"
    '3' =>
    string(6) "name 3"
}
*/

fetchColumn

<?php

use Linio\Component\Database\Exception\FetchException;
use Linio\Component\Database\Exception\InvalidQueryException;

/**
 * @throws InvalidQueryException
 * @throws FetchException
 */
public function fetchColumn(string $query, array $params = [], int $columnIndex = 0, bool $forceMasterConnection = false): array;

$names = $db->fetchColumn("SELECT `id`,`name` FROM `table` WHERE `id` > :id", ['id' => 1], 1);

var_dump($names);

/*
array(2) {
    [0] =>
    string(6) "name 2"
    [1] =>
    string(6) "name 3"
}
*/

fetchLazy

<?php

use Linio\Component\Database\Entity\LazyFetch;
use Linio\Component\Database\Exception\InvalidQueryException;

/**
 * @throws InvalidQueryException
 */
public function fetchLazy(string $query, array $params = [], bool $forceMasterConnection = false): LazyFetch;

$lazyFetch = $db->fetchLazy("SELECT `id`,`name` FROM `table` WHERE `id` > ?", [1]);

while ($row = $lazyFetch->fetch()) {
    $name = $row['name'];
}

在此示例中,当此 while 循环到达结果集的末尾时,fetch() 方法将返回一个空数组。

execute

<?php

use Linio\Component\Database\Exception\InvalidQueryException;

/**
 * @throws InvalidQueryException
 */
public function execute(string $query, array $params = []): int;

$affectedRowsInsert = $db->execute("INSERT INTO `table` VALUES(:id, :name)", ['id' => 10, 'name' => 'test_name']);

var_dump($affectedRowsInsert);

/*
int(1)
*/

$affectedRowsUpdate = $db->execute("UPDATE `table` SET `name` = :name", ['name' => 'test_name']);

var_dump($affectedRowsUpdate);

/*
int(3)
*/

escapeValue

<?php

use Linio\Component\Database\Exception\DatabaseException;

/**
 * @throws DatabaseException
 */
public function escapeValue(string $value): string;

$escapedValue = $db->escapeValue('Linio\'s Library');

var_dump($escapedValue);

/*
string(17) "Linio\\'s Library"
*/

escapeValues

<?php

use Linio\Component\Database\Exception\DatabaseException;

/**
 * @throws DatabaseException
 */
public function escapeValues(array $values): array;

$escapedValues = $db->escapeValues(['Linio\'s Library', 'Linio\'s Library']);

var_dump($escapedValues);

/*
 * 
array(2) {                    
  [0]=>                       
  string(17) "Linio\\'s Library"
  [1]=>                       
  string(17) "Linio\\'s Library"
}                             
*/

异常

Linio\Component\Database\Exception\DatabaseConnectionException

原因

  • 无效的驱动程序名称
  • 无效的连接参数
  • 尝试建立数据库连接时出错

Linio\Component\Database\Exception\InvalidQueryException

原因

  • 在创建语句之前丢失数据库连接
  • SQL查询格式错误
  • 错误的表名或字段名

Linio\Component\Database\Exception\FetchException

原因

  • 在创建语句后丢失数据库连接

Linio\Component\Database\Exception\TransactionException

原因

  • 开始、提交或回滚事务失败

Linio\Component\Database\Exception\DatabaseException

原因

  • 所有异常都从这个扩展
  • 非特定错误

驱动程序

DatabaseManager::MYSQL

适配器选项

  • host 字符串
  • port 整数
  • dbname 字符串
  • username 字符串
  • password 字符串
  • pdo_attributes 数组 可选

DatabaseManager::PGSQL

适配器选项

  • host 字符串
  • port 整数
  • dbname 字符串
  • username 字符串
  • password 字符串
  • pdo_attributes 数组 可选

DatabaseManager::SQLITE

适配器选项

  • filepath

DatabaseManager::SQLSRV

适配器选项

  • host 字符串
  • port 整数
  • dbname 字符串
  • username 字符串
  • password 字符串
  • pdo_attributes 数组 可选