12 KiB
快速開始
前言
hyperf/database 衍生於 illuminate/database,我們對它進行了一些改造,大部分功能保持了相同。在這裡感謝一下 Laravel 開發組,實現瞭如此強大好用的 ORM 元件。
hyperf/database 元件是基於 illuminate/database 衍生出來的元件,我們對它進行了一些改造,從設計上是允許用於其它 PHP-FPM 框架或基於 Swoole 的框架中的,而在 Hyperf 裡就需要提一下 hyperf/db-connection 元件,它基於 hyperf/pool 實現了資料庫連線池並對模型進行了新的抽象,以它作為橋樑,Hyperf 才能把資料庫元件及事件元件接入進來。
安裝
Hyperf 框架
composer require hyperf/db-connection
其它框架
composer require hyperf/database
配置
預設配置如下,資料庫支援多庫配置,預設為 default
。
配置項 | 型別 | 預設值 | 備註 |
---|---|---|---|
driver | string | 無 | 資料庫引擎 |
host | string | 無 | 資料庫地址 |
database | string | 無 | 資料庫預設 DB |
username | string | 無 | 資料庫使用者名稱 |
password | string | null | 資料庫密碼 |
charset | string | utf8 | 資料庫編碼 |
collation | string | utf8_unicode_ci | 資料庫編碼 |
prefix | string | '' | 資料庫模型字首 |
timezone | string | null | 資料庫時區 |
pool.min_connections | int | 1 | 連線池內最少連線數 |
pool.max_connections | int | 10 | 連線池內最大連線數 |
pool.connect_timeout | float | 10.0 | 連線等待超時時間 |
pool.wait_timeout | float | 3.0 | 超時時間 |
pool.heartbeat | int | -1 | 心跳 |
pool.max_idle_time | float | 60.0 | 最大閒置時間 |
options | array | PDO 配置 |
<?php
return [
'default' => [
'driver' => env('DB_DRIVER', 'mysql'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => (float)env('DB_MAX_IDLE_TIME', 60),
]
],
];
有時候使用者需要修改 PDO 預設配置,比如所有欄位需要返回為 string。這時候就需要修改 PDO 配置項 ATTR_STRINGIFY_FETCHES
為 true。
<?php
return [
'default' => [
'driver' => env('DB_DRIVER', 'mysql'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
],
'options' => [
// 框架預設配置
PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
// 如果使用的為非原生 MySQL 或雲廠商提供的 DB 如從庫/分析型例項等不支援 MySQL prepare 協議的, 將此項設定為 true
PDO::ATTR_EMULATE_PREPARES => false,
],
],
];
讀寫分離
有時候你希望 SELECT
語句使用一個數據庫連線,而 INSERT
,UPDATE
,和 DELETE
語句使用另一個數據庫連線。在 Hyperf
中,無論你是使用原生查詢,查詢構造器,或者是模型,都能輕鬆的實現
為了弄明白讀寫分離是如何配置的,我們先來看個例子:
<?php
return [
'default' => [
'driver' => env('DB_DRIVER', 'mysql'),
'read' => [
'host' => ['192.168.1.1'],
],
'write' => [
'host' => ['196.168.1.2'],
],
'sticky' => true,
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
],
],
];
注意在以上的例子中,配置陣列中增加了三個鍵,分別是 read
, write
和 sticky
。 read
和 write
的鍵都包含一個鍵為 host
的陣列。而 read
和 write
的其他資料庫都在鍵為 mysql 的陣列中。
如果你想重寫主陣列中的配置,只需要修改 read
和 write
陣列即可。所以,這個例子中: 192.168.1.1 將作為 「讀」 連線主機,而 192.168.1.2 將作為 「寫」 連線主機。這兩個連線會共享 mysql 陣列的各項配置,如資料庫的憑據(使用者名稱 / 密碼),字首,字元編碼等。
sticky
是一個 可選值,它可用於立即讀取在當前請求週期內已寫入資料庫的記錄。若 sticky
選項被啟用,並且當前請求週期內執行過 「寫」 操作,那麼任何 「讀」 操作都將使用 「寫」 連線。這樣可確保同一個請求週期內寫入的資料可以被立即讀取到,從而避免主從延遲導致資料不一致的問題。不過是否啟用它,取決於應用程式的需求。
多庫配置
多庫配置如下。
<?php
return [
'default' => [
'driver' => env('DB_DRIVER', 'mysql'),
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
],
],
'test'=>[
'driver' => env('DB_DRIVER', 'mysql'),
'host' => env('DB_HOST2', 'localhost'),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8'),
'collation' => env('DB_COLLATION', 'utf8_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
],
],
];
使用時,只需要規定 connection
為 test
,就可以使用 test
中的配置,如下。
<?php
use Hyperf\DbConnection\Db;
// default
Db::select('SELECT * FROM user;');
Db::connection('default')->select('SELECT * FROM user;');
// test
Db::connection('test')->select('SELECT * FROM user;');
模型中修改 connection
欄位,即可使用對應配置,例如一下 Model
使用 test
配置。
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://doc.hyperf.io
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Model;
/**
* @property int $id
* @property string $mobile
* @property string $realname
*/
class User extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'user';
/**
* The connection name for the model.
*
* @var string
*/
protected $connection = 'test';
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = ['id', 'mobile', 'realname'];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = ['id' => 'integer'];
}
執行原生 SQL 語句
配置好資料庫後,便可以使用 Hyperf\DbConnection\Db
進行查詢。
Query 查詢類
這裡主要包括 Select
、屬性為 READS SQL DATA
的儲存過程、函式等查詢語句。
select
方法將始終返回一個數組,陣列中的每個結果都是一個 StdClass
物件
<?php
use Hyperf\DbConnection\Db;
$users = Db::select('SELECT * FROM `user` WHERE gender = ?',[1]); // 返回array
foreach($users as $user){
echo $user->name;
}
Execute 執行類
這裡主要包括 Insert
、Update
、Delete
,屬性為 MODIFIES SQL DATA
的儲存過程等執行語句。
<?php
use Hyperf\DbConnection\Db;
$inserted = Db::insert('INSERT INTO user (id, name) VALUES (?, ?)', [1, 'Hyperf']); // 返回是否成功 bool
$affected = Db::update('UPDATE user set name = ? WHERE id = ?', ['John', 1]); // 返回受影響的行數 int
$affected = Db::delete('DELETE FROM user WHERE id = ?', [1]); // 返回受影響的行數 int
$result = Db::statement("CALL pro_test(?, '?')", [1, 'your words']); // 返回 bool CALL pro_test(?,?) 為儲存過程,屬性為 MODIFIES SQL DATA
自動管理資料庫事務
你可以使用 Db
的 transaction
方法在資料庫事務中執行一組操作。如果事務的閉包 Closure
中出現一個異常,事務將會回滾。如果事務閉包 Closure
執行成功,事務將自動提交。一旦你使用了 transaction
, 就不再需要擔心手動回滾或提交的問題:
<?php
use Hyperf\DbConnection\Db;
Db::transaction(function () {
Db::table('user')->update(['votes' => 1]);
Db::table('posts')->delete();
});
手動管理資料庫事務
如果你想要手動開始一個事務,並且對回滾和提交能夠完全控制,那麼你可以使用 Db
的 beginTransaction
, commit
, rollBack
:
use Hyperf\DbConnection\Db;
Db::beginTransaction();
try{
// Do something...
Db::commit();
} catch(\Throwable $ex){
Db::rollBack();
}
輸出剛剛執行的 SQL
當前方法僅能用於開發環境,線上部署前一定要去掉,不然會引起嚴重的記憶體洩露和資料混淆。
線上記錄 SQL
,請使用 事件監聽
<?php
use Hyperf\DbConnection\Db;
use Hyperf\Collection\Arr;
use App\Model\Book;
// 啟用 SQL 資料記錄功能
Db::enableQueryLog();
$book = Book::query()->find(1);
// 列印最後一條 SQL 相關資料
var_dump(Arr::last(Db::getQueryLog()));