colopl / laravel-spanner
Google Cloud Spanner 的 Laravel 数据库驱动程序
Requires
- php: ^8.2
- ext-grpc: *
- ext-json: *
- google/cloud-spanner: ^1.58.4
- grpc/grpc: ^1.42
- laravel/framework: ^11.15.0
- symfony/cache: ~7
- symfony/deprecation-contracts: ~2
- symfony/lock: ~7
Requires (Dev)
- orchestra/testbench: ~9
- phpstan/phpstan: ^1
- phpunit/phpunit: ~11.0
Suggests
- ext-protobuf: Native support for protobuf is available. Will use pure PHP implementation if not present.
- ext-sysvmsg: Can use SemaphoreLock for session handling. Will use FileLock if not present.
- ext-sysvsem: Can use SemaphoreLock for session handling. Will use FileLock if not present.
- ext-sysvshm: Can use SemaphoreLock for session handling. Will use FileLock if not present.
- dev-master
- v8.2.0
- v8.1.2
- v8.1.1
- v8.1.0
- v8.0.0
- 7.x-dev
- v7.4.2
- v7.4.1
- v7.4.0
- v7.3.0
- v7.2.0
- v7.1.0
- v7.0.0
- 6.x-dev
- v6.1.2
- v6.1.1
- v6.1.0
- v6.0.0
- 5.x-dev
- v5.3.0
- v5.2.2
- v5.2.1
- v5.2.0
- v5.1.1
- v5.1.0
- v5.0.0
- 4.x-dev
- v4.7.1
- v4.7.0
- v4.6.0
- v4.5.0
- v4.4.0
- v4.3.0
- v4.2.0
- v4.1.1
- v4.1.0
- v4.0.0
- v3.x-dev
- v3.10.2
- v3.10.1
- v3.10.0
- v3.9.3
- v3.9.2
- v3.9.1
- v3.9.0
- v3.8.0
- v3.7.6
- v3.7.5
- v3.7.4
- v3.7.3
- v3.7.2
- v3.7.1
- v3.7.0
- v3.6.0
- v3.5.2
- v3.5.1
- v3.5.0
- v3.4.3
- v3.4.2
- v3.4.1
- v3.4.0
- v3.3.1
- v3.3.0
- v3.2.0
- dev-feature/change-stream
- dev-feature/where-in-embedded
- dev-feature/snapshot
- dev-fix/datetime-format-bug
This package is auto-updated.
Last update: 2024-09-24 07:52:40 UTC
README
Google Cloud Spanner 的 Laravel 数据库驱动程序
要求
- PHP >= 8.2
- Laravel >= 11
- gRPC 扩展
- protobuf 扩展(建议以提高性能)
sysvmsg
,sysvsem
,sysvshm
扩展(建议以提高性能)
安装
将 JSON 凭据文件路径放入环境变量:GOOGLE_APPLICATION_CREDENTIALS
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json
通过 composer 安装
composer require colopl/laravel-spanner
将连接配置添加到 config/database.php
[ 'connections' => [ 'spanner' => [ 'driver' => 'spanner', 'instance' => '<Cloud Spanner instanceId here>', 'database' => '<Cloud Spanner database name here>', ] ] ];
就这么多。您可以使用数据库连接像平常一样。
$conn = DB::connection('spanner'); $conn->...
其他配置
您可以将 SpannerClient
配置和 CacheSessionPool
选项传递如下。有关更多信息,请参阅Google 客户端库文档
[ 'connections' => [ 'spanner' => [ 'driver' => 'spanner', 'instance' => '<Cloud Spanner instanceId here>', 'database' => '<Cloud Spanner database name here>', // Spanner Client configurations 'client' => [ 'projectId' => 'xxx', ... ], // CacheSessionPool options 'session_pool' => [ 'minSessions' => 10, 'maxSessions' => 500, ], ] ] ];
推荐设置
请注意,以下内容不是必需的,但强烈建议以提高性能。
- 安装
protobuf
pecl 扩展以加快网络通信。 - 安装
sysvmsg
,sysvsem
,sysvshm
扩展以加快会话管理。 - 将缓存目录(默认为
./storage/framework/spanner
)挂载到 tmpfs 以提高会话 IO 性能。可以通过在config/database.php
文件中设置connections.{name}.cache_path
来更改缓存路径。
不支持的功能
- STRUCT 数据类型
- 插入/更新 JSON 数据类型
- 显式只读事务(快照)
限制
SQL 模式
当前仅支持在 GoogleSQL 上运行的 Spanner(不支持 PostgreSQL 模式)。
查询
- 在一个查询中绑定超过 950 个参数会导致服务器错误。为了绕过此限制,当传递的参数超过由
parameter_unnest_threshold
配置(默认为900
)设置的限制时,此驱动程序将尝试在内部切换到使用Query.Builder::whereInUnnest(...)
。您可以通过将其值设置为false
来关闭此功能。
Eloquent
如果您使用交错键,您必须在其 interleaveKeys
属性中定义它们,否则您将无法保存。有关更详细的说明,请参阅 Colopl\Spanner\Tests\Eloquent\ModelTest
。
更多信息
迁移
由于 Cloud Spanner 不支持 AUTO_INCREMENT 属性,Blueprint::increments
(及其所有变体)将创建一个类型为 STRING(36) DEFAULT (GENERATE_UUID())
的列以生成和填充列,并将其标记为主键。
事务
Google Cloud Spanner 有时请求事务重试(例如 UNAVAILABLE
和 ABORTED
),即使逻辑是正确的。因此,请勿手动管理事务。
您应该始终使用 transaction
方法,该方法内部处理重试请求。
// BAD: Do not use transactions manually!! try { DB::beginTransaction(); ... DB::commit(); } catch (\Throwable $ex) { DB::rollBack(); } // GOOD: You should always use transaction method DB::transaction(function() { ... });
Google Cloud Spanner 为所有数据操作创建事务,即使您没有显式创建事务。
特别是,在 SELECT 语句中,事务类型根据它是显式还是隐式而有所不同。
// implicit transaction (Read-only transaction) $conn->select('SELECT ...'); // explicit transaction (Read-write transaction) $conn->transaction(function() { $conn->select('SELECT ...'); }); // implicit transaction (Read-write transaction) $conn->insert('INSERT ...'); // explicit transaction (Read-write transaction) $conn->transaction(function() { $conn->insert('INSERT ...'); });
有关更多信息,请参阅Cloud Spanner关于事务的文档
陈旧读取
您可以使用以下陈旧读取(时间戳边界)。
// There are four types of timestamp bounds: ExactStaleness, MaxStaleness, MinReadTimestamp and ReadTimestamp. $timestampBound = new ExactStaleness(10); // by Connection $connection->selectWithTimestampBound('SELECT ...', $bindings, $timestampBound); // by Query Builder $queryBuilder ->withStaleness($timestampBound) ->get();
陈旧读取始终以singleUse
选项作为只读事务运行。因此,您不能将其作为读写事务运行。
数据提升
数据提升创建快照并在不影响现有工作负载的情况下并行运行查询。
您可以在此处了解更多关于它的信息。
以下是如何使用它的示例。
// Using Connection $connection->selectWithOptions('SELECT ...', $bindings, ['dataBoostEnabled' => true]); // Using Query Builder $queryBuilder ->useDataBoost() ->setRequestTimeoutSeconds(60) ->get();
注意
这将在后台创建一个新会话,该会话不会与当前会话池共享。这意味着,使用数据提升运行的查询将不会与可能正在进行的任何事务关联。
请求标签和事务标签
Spanner允许您为您的查询和事务附加标签,这些标签可以用于故障排除。
您可以根据以下方式设置请求标签和事务标签。
$requestPath = request()->path(); $tag = 'url=' . $requestPath; $connection->setRequestTag($tag); $connection->setTransactionTag($tag);
数据类型
Google Cloud Spanner的一些数据类型在PHP中没有相应的内置类型。您可以使用以下类,通过Google Cloud PHP客户端
- BYTES:
Google\Cloud\Spanner\Bytes
- DATE:
Google\Cloud\Spanner\Date
- NUMERIC:
Google\Cloud\Spanner\Numeric
- TIMESTAMP:
Google\Cloud\Spanner\Timestamp
在获取行时,库将以下列类型转换为以下类型
Timestamp
-> 带默认时区的CarbonNumeric
->string
请注意,如果您在没有QueryBuilder的情况下执行查询,则不会进行这些转换。
分区DML
您可以按以下方式运行分区DML。
// by Connection $connection->runPartitionedDml('UPDATE ...'); // by Query Builder $queryBuilder->partitionedUpdate($values); $queryBuilder->partitionedDelete();
但是,分区DML有一些限制。有关更多信息,请参阅Cloud Spanner关于分区DML的文档。
交错
您可以按以下方式定义交错表。
$schemaBuilder->create('user_items', function (Blueprint $table) { $table->uuid('user_id'); $table->uuid('id'); $table->uuid('item_id'); $table->integer('count'); $table->timestamps(); $table->primary(['user_id', 'id']); // interleaved table $table->interleaveInParent('users')->cascadeOnDelete(); // interleaved index $table->index(['userId', 'created_at'])->interleaveIn('users'); });
行删除策略
您可以按以下方式定义行删除策略。
$schemaBuilder->create('user', function (Blueprint $table) { $table->uuid('user_id'); $table->timestamps(); // create a policy $table->deleteRowsOlderThan(['updated_at'], 365); }); $schemaBuilder->table('user', function (Blueprint $table) { // add policy $table->addRowDeletionPolicy('udpated_at', 100); // replace policy $table->replaceRowDeletionPolicy('udpated_at', 100); // drop policy $table->dropRowDeletionPolicy(); });
序列
如果您想将简单的序列用作主键,可以使用useSequence()
方法。如果未提供$name
,则调用useSequence()
将创建一个名为user_id_sequence
的序列,其start_with_counter
设置为1和1,000,000之间的随机值。
$schemaBuilder->create('user', function (Blueprint $table) { $table->integer('id')->useSequence(); });
如果您想获得更多灵活性,也可以直接创建、修改和删除序列,如下所示。
$schemaBuilder->create('user_items', function (Blueprint $table) { $table->createSequence('sequence_name'); $table->integer('id')->useSequence('sequence_name'); $table->alterSequence('sequence_name') ->startWithCounter(100) ->skipRangeMin(1) ->skipRangeMax(10); $table->dropSequence('sequence_name'); });
辅助索引选项
您可以按以下方式定义Spanner特定的索引选项,如null过滤和存储。
$schemaBuilder->table('user_items', function (Blueprint $table) { $table->index('userId') // Interleave in parent table ->interleaveIn('user') // Add null filtering ->nullFiltered() // Add storing ->storing(['itemId', 'count']); });
突变
您可以使用突变插入、更新和删除数据以修改数据,而不是使用DML来提高性能。
$queryBuilder->insertUsingMutation($values);
$queryBuilder->updateUsingMutation($values);
$queryBuilder->insertOrUpdateUsingMutation($values);
$queryBuilder->deleteUsingMutation($values);
请注意,mutation API 的操作方式与 DML 不同。在一个事务中的所有 mutations 调用都会排队,并在你提交时批量发送。这意味着,如果你通过上述函数进行了任何修改,然后在提交之前尝试 SELECT 相同的记录,返回的结果将不会包括你在事务中进行的任何修改。
SessionPool 和 AuthCache
为了提高每个请求的第一个连接的性能,我们使用了 AuthCache 和 CacheSessionPool。
默认情况下,这个库使用 Filesystem Cache Adapter 作为缓存池。如果你想使用自己的缓存池,你可以扩展 ServiceProvider 并将其注入到 Colopl\Spanner\Connection
构造函数中。
每个会话的初始化大约需要一秒钟,因此建议在服务器的启动阶段预热会话。这可以通过运行 php artisan spanner:warmup
命令实现。你可以通过设置 config/database.php
中的 connections.{name}.session_pool.maxSessions
选项来设置要预热的会话数量。
同样,会话在使用后保持活跃 60 分钟,因此建议在服务器的关闭阶段删除会话。这可以通过运行 php artisan spanner:cooldown
命令实现。
队列工作员
每个作业处理完成后,连接将断开,这样会话就可以释放到会话池中。这允许会话通过 maintainSessionPool()
进行更新或过期。
Laravel Tinker
你可以使用 Laravel Tinker,例如使用 php artisan tinker
命令。但是,当你访问 Cloud Spanner 时,你的会话可能会挂起。这是已知的问题,当 PHP 分叉进程时发生 gRPC 问题。解决方案是在 php.ini
中添加以下行。
grpc.enable_fork_support=1
开发
测试
你可以通过以下命令在 docker 上运行测试。请注意,必须设置一些环境变量。为了设置变量,将 .env.sample 重命名为 .env
并编辑定义的变量的值。
make test
许可
Apache 2.0 - 更多信息请参阅 LICENSE。