pinga / db

以驱动无关的方式提供安全便捷的 SQL 数据库访问

v0.1.3 2023-02-03 09:59 UTC

This package is auto-updated.

Last update: 2024-09-13 12:30:06 UTC


README

以驱动无关的方式提供安全便捷的 SQL 数据库访问。

功能

  • 便捷的接口
  • 执行相同任务时,编写更少的代码
  • 通过使用预处理语句,防止 SQL 注入
  • 服务器返回的数据具有正确的本地类型(即没有字符串化字段)
  • 对多个数据库系统的驱动无关支持

要求

  • PHP 8.1.0+
  • PDO 扩展

安装

  1. 通过 Composer 包含库

    $ composer require pinga/db
    
  2. 包含 Composer 自动加载器

    require __DIR__ . '/vendor/autoload.php';

使用

连接到数据库

  • 从动态数据库配置

    $dataSource = new \Pinga\Db\PdoDataSource('mysql'); // see "Available drivers for database systems" below
    $dataSource->setHostname('localhost');
    $dataSource->setPort(3306);
    $dataSource->setDatabaseName('mydatabase');
    $dataSource->setCharset('utf8mb4');
    $dataSource->setUsername('myusername');
    $dataSource->setPassword('mypassword');
    
    $db = \Pinga\Db\PdoDatabase::fromDataSource($dataSource);

    这是建立数据库连接最方便的方式,因为正确的 DSN 将会自动为你创建。你可以使用流畅的接口中的各种设置器来设置你的配置。

    你可以省略任何不需要的选项,并检查 PdoDataSource 类中的其他可用设置器。

    连接将按需创建,即它们在真正使用之前不会消耗任何资源。所有这些都是自动发生的。

  • 从 DSN(数据源名称)

    $db = \Pinga\Db\PdoDatabase::fromDsn(
        new \Pinga\Db\PdoDsn(
            'mysql:dbname=my-database;host=localhost',
            'my-username',
            'my-password'
        )
    );

    PdoDsn 构造函数的参数与 PDO 构造函数的参数完全相同。但如果你不需要另一个 PDO 实例,不使用 PDO 直接从 DSN 创建此库的实例会更高效。

    连接将按需创建,即它们在真正使用之前不会消耗任何资源。

  • 使用现有的 PDO 实例

    // $pdo = new PDO('mysql:dbname=my-database;host=localhost;charset=utf8mb4', 'my-username', 'my-password');
    
    $db = \Pinga\Db\PdoDatabase::fromPdo($pdo);

    这不会创建另一个数据库连接,而是会重用你提供的 PDO 实例中现有的连接。

    此外,你可以从对库行为的强烈保证和便利性中受益,同时仍然能够使用现有的 PDO 实例而不产生任何副作用。

    只需将 true 作为 fromPdo 方法的第二个参数传递,即可完全保留你的 PDO 实例的原始状态。

    $db = \Pinga\Db\PdoDatabase::fromPdo($pdo, true);

数据库系统可用的驱动程序

\Pinga\Db\PdoDataSource::DRIVER_NAME_MYSQL;
\Pinga\Db\PdoDataSource::DRIVER_NAME_POSTGRESQL;
\Pinga\Db\PdoDataSource::DRIVER_NAME_SQLITE;

选择数据

在选择数据时,你只需一个方法调用就能得到所需的结果。当然,你可以轻松选择你想要得到多行、单行、单个值或所有行的单个列。

$rows = $db->select('SELECT id, name FROM books');

// or

$rows = $db->select(
    'SELECT name, year FROM books WHERE author = ? ORDER BY copies DESC LIMIT 0, 10',
    [ 'Charles Dickens' ]
);

// or

$row = $db->selectRow(
    'SELECT author, year FROM books WHERE author <> ? ORDER BY year ASC LIMIT 0, 1',
    [ 'Miguel de Cervantes' ]
);

// or

$value = $db->selectValue(
    'SELECT year FROM books WHERE name <> ? AND name <> ? ORDER BY year DESC LIMIT 0, 1',
    [
        'Tale of Two Cities',
        'Alice in Wonderland'
    ]
);

// or

$column = $db->selectColumn(
    'SELECT author FROM books ORDER BY copies DESC LIMIT ?, ?',
    [
        0,
        3
    ]
);

插入数据

对于简单的插入,你可以使用便捷的简写

$db->insert(
    'books',
    [
        // set
        'name' => 'Don Quixote',
        'author' => 'Miguel de Cervantes',
        'year' => 1612
    ]
);

你的表是否有自动生成的主键 ID?通过另一个简短的方法调用即可访问这些插入的 ID。序列名称仅适用于 一些 数据库驱动程序,例如 PostgreSQL。

$newId = $db->getLastInsertId();
// or
$newId = $db->getLastInsertId('my-sequence-name');

如果你需要执行更复杂的语句,请参阅下面的 "执行语句" 部分。

更新数据

对于简单的更新,你还可以使用便捷的简写

$db->update(
    'books',
    [
        // set
        'author' => 'J. K. Rowling',
        'copies' => 2
    ],
    [
        // where
        'name' => "Harry Potter and the Philosopher's Stone"
    ]
);

你想要知道这次操作更新了多少行吗?只需从 update 方法调用中获取返回值。

如果你需要执行更复杂的语句,请参阅下面的 "执行语句" 部分。

删除数据

同样,对于简单的删除,你也可以使用便捷的简写

$db->delete(
    'books',
    [
        // where
        'author' => 'C. S. Lewis',
        'year' => 1949
    ]
);

delete 方法调用的返回值将告诉你这次操作删除了多少行。

如果你需要执行更复杂的语句,请参阅下面的 "执行语句" 部分。

执行语句

你可以像以下示例那样执行任何任意的 SQL 语句

$db->exec(
    'INSERT INTO books (name, author, year) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE copies = copies + 1',
    [
        "Harry Potter and the Philosopher's Stone",
        'J. K. Rowling',
        1997
    ]
);

// or

$db->exec(
    "UPDATE books SET name = CONCAT(LEFT(name, 5), ' in ', RIGHT(name, 10)) WHERE year >= ? AND year < ?",
    [
        1860,
        1890
    ]
);

对于你执行的每个语句,返回值将是受影响的行数。

如果您正在执行的是一个 INSERT 语句,您可以通过 getLastInsertId 方法再次获取插入的 ID。

事务

事务控制就像它应该的那样简单

$db->beginTransaction();

// and later

$db->commit();
// or
$db->rollBack();

// and optionally
$active = $db->isTransactionActive();

错误处理

此库中的方法不返回任何错误代码。您将通过异常了解任何问题。

输入转义

您不需要手动转义任何输入。只需像上面那样使用占位符并单独传递数据即可。所有输入都将自动为您转义。

性能分析

为了在开发过程中监控查询性能,您可以启用性能分析

$db->setProfiler(new \Pinga\Db\SimpleProfiler());

无论何时您想查看分析过的查询或将它们存储在日志文件中,您都可以获取分析器记录的所有测量值作为数组

$db->getProfiler()->getMeasurements();

通常,您在检索之前会想要对这些测量值进行排序,以便将运行时间最长的查询列在首位

$db->getProfiler()->sort();

服务器和客户端信息

为了检索有关您连接到的数据库服务器或 PHP 使用的数据库客户端的信息,您可以使用以下方法之一

$db->getDriverName();
// e.g. 'MySQL'

$db->getServerInfo();
// e.g. 'Uptime: 82196  Threads: 1  Questions: 2840  Slow queries: 0  Opens: 23  Flush tables: 1  Open tables: 33  Queries per second avg: 0.736'

$db->getServerVersion();
// e.g. '5.5.5-10.1.13-MariaDB'

$db->getClientVersion();
// e.g. 'mysqlnd 5.0.1-dev'

监听器

连接建立

$db->addOnConnectListener(function (\Delight\Db\PdoDatabase $db) {
	// do something
});

贡献

所有贡献都受欢迎!如果您想贡献,请首先创建一个问题,以便讨论您的功能、问题或问题。

许可协议

此项目根据 MIT 许可协议 许可。