hughcube / laravel-ots
Installs: 5 472
Dependents: 1
Suggesters: 0
Security: 0
Stars: 0
Watchers: 1
Forks: 0
Open Issues: 0
pkg:composer/hughcube/laravel-ots
Requires
- php: >=7.4
- ext-json: *
- aliyun/aliyun-tablestore-sdk-php: *
Requires (Dev)
README
Laravel OTS 是一个功能完整的阿里云表格存储 (Tablestore/OTS) Laravel 适配器,提供了优雅的 API 来操作 OTS 服务。
功能特性
- 完整的数据 CRUD 操作(单行、批量、范围查询)
- 搜索索引支持(10+ 种查询类型)
- Schema 管理(表、二级索引、搜索索引)
- 本地事务支持
- 并行扫描 (ParallelScan)
- 数据流 (Stream) 处理
- Laravel 缓存驱动 + 分布式锁
- SQL 查询支持(同步/异步)
- Eloquent ORM 模型支持
- Laravel Sanctum 集成
安装
composer require hughcube/laravel-ots -vvv
配置
在 config/database.php 的 connections 数组中添加 OTS 连接配置:
'ots' => [ 'driver' => 'ots', 'endpoint' => env('OTS_ENDPOINT'), 'instance' => env('OTS_INSTANCE'), 'access_key_id' => env('OTS_ACCESS_KEY_ID'), 'access_key_secret' => env('OTS_ACCESS_KEY_SECRET'), ],
在 .env 文件中配置:
OTS_ENDPOINT=https://instance.cn-hangzhou.ots.aliyuncs.com OTS_INSTANCE=instance OTS_ACCESS_KEY_ID=your_access_key_id OTS_ACCESS_KEY_SECRET=your_access_key_secret
使用指南
获取连接
use HughCube\Laravel\OTS\Ots; // 获取默认连接 $connection = Ots::connection(); // 获取指定连接 $connection = Ots::connection('ots'); // 直接获取 OTSClient 实例 $otsClient = $connection->getOts();
数据操作
Query Builder
按主键查询单行
use HughCube\Laravel\OTS\Ots; $row = Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->findByPrimaryKey();
按主键查询多行
$rows = Ots::connection()->table('users') ->findMany([ ['id' => 1], ['id' => 2], ['id' => 3], ]);
插入数据
// 方式1:通过 primaryKeyColumns 定义主键结构 Ots::connection()->table('users') ->primaryKeyColumns([ 'id' => PrimaryKeyTypeConst::CONST_INTEGER, ]) ->insert([ 'id' => 1, 'name' => 'John', 'email' => 'john@example.com', ]); // 方式2:通过 primaryKey 指定主键值(其余字段自动作为属性列) Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->insert([ 'name' => 'John', 'email' => 'john@example.com', ]); // 多主键表插入 Ots::connection()->table('orders') ->primaryKeyColumns([ 'user_id' => PrimaryKeyTypeConst::CONST_INTEGER, 'order_id' => PrimaryKeyTypeConst::CONST_INTEGER, ]) ->insert([ 'user_id' => 100, 'order_id' => 1, 'amount' => 99.99, 'status' => 'pending', ]); // 插入并返回自增ID $id = Ots::connection()->table('users') ->primaryKeyColumns([ 'partition' => PrimaryKeyTypeConst::CONST_STRING, 'id' => PrimaryKeyTypeConst::CONST_PK_AUTO_INCR, // 自增主键 ]) ->insertGetId([ 'partition' => 'user', 'name' => 'John', 'email' => 'john@example.com', ]);
更新数据
Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->update([ 'name' => 'John Doe', 'updated_at' => time(), ]);
删除数据
Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->delete();
条件写入(乐观并发控制)
// 期望行存在才更新 Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->expectExist() ->update(['name' => 'New Name']); // 期望行不存在才插入 Ots::connection()->table('users') ->expectNotExist() ->insert(['id' => 1, 'name' => 'John']); // 忽略行存在性检查 Ots::connection()->table('users') ->rowExistence(RowExistenceExpectationConst::CONST_IGNORE) ->insert(['id' => 1, 'name' => 'John']);
指定返回的列
$row = Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->attributeColumns(['name', 'email']) ->findByPrimaryKey();
范围查询
基础范围查询
$rows = Ots::connection()->table('logs') ->startKey(['user_id' => 1, 'timestamp' => 0]) ->endKey(['user_id' => 1, 'timestamp' => INF_MAX]) ->limit(100) ->getRange();
正向/反向查询
// 正向查询(从小到大) $rows = Ots::connection()->table('logs') ->forward() ->startKey(['id' => 1]) ->endKey(['id' => 100]) ->getRange(); // 反向查询(从大到小) $rows = Ots::connection()->table('logs') ->backward() ->startKey(['id' => 100]) ->endKey(['id' => 1]) ->getRange();
搜索索引查询
使用搜索索引
$query = Ots::connection()->table('products') ->useSearchIndex('products_index');
精确查询 (Term)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchTerm('status', 'active') ->searchQuery();
IN 查询 (Terms)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchTerms('category', ['electronics', 'books', 'clothing']) ->searchQuery();
模糊匹配查询 (Match)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchMatch('description', '手机') ->searchQuery();
短语查询 (MatchPhrase)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchMatchPhrase('title', 'iPhone 15') ->searchQuery();
前缀查询 (Prefix)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchPrefix('name', 'App') ->searchQuery();
通配符查询 (Wildcard)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchWildcard('name', '*phone*') ->searchQuery();
范围查询 (Range)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchRange('price', 100, 500) // 100 <= price <= 500 ->searchQuery(); // 开区间 $rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchRange('price', 100, 500, false, false) // 100 < price < 500 ->searchQuery();
匹配所有 (MatchAll)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchMatchAll() ->searchQuery();
存在性查询 (Exists)
检查字段是否存在值。
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchExists('description') // 只返回有 description 字段的记录 ->searchQuery();
嵌套查询 (Nested)
用于查询嵌套类型的字段。
// 使用回调构建嵌套查询 $rows = Ots::connection()->table('orders') ->useSearchIndex('orders_index') ->searchNested('items', function ($query) { $query->searchTerm('items.product_id', 'P001') ->searchRange('items.quantity', 1, 10); }) ->searchQuery(); // 使用原生查询数组 $rows = Ots::connection()->table('orders') ->useSearchIndex('orders_index') ->searchNested('items', [ 'query_type' => QueryTypeConst::TERM_QUERY, 'query' => [ 'field_name' => 'items.name', 'term' => 'iPhone', ], ]) ->searchQuery();
地理距离查询 (GeoDistance)
查找指定圆形范围内的地理位置。
$rows = Ots::connection()->table('stores') ->useSearchIndex('stores_index') ->searchGeoDistance('location', 31.2304, 121.4737, 5000) // 上海市中心 5000 米范围内 ->searchQuery();
地理边界框查询 (GeoBoundingBox)
查找矩形范围内的地理位置。
$rows = Ots::connection()->table('stores') ->useSearchIndex('stores_index') ->searchGeoBoundingBox( 'location', 31.3, 121.3, // 左上角 (纬度, 经度) 31.1, 121.6 // 右下角 (纬度, 经度) ) ->searchQuery();
地理多边形查询 (GeoPolygon)
查找多边形范围内的地理位置。
$rows = Ots::connection()->table('stores') ->useSearchIndex('stores_index') ->searchGeoPolygon('location', [ [31.2, 121.4], // 点1 (纬度, 经度) [31.3, 121.5], // 点2 [31.2, 121.6], // 点3 [31.1, 121.5], // 点4 ]) ->searchQuery();
组合查询 (简单 AND)
多个条件默认使用 AND 逻辑组合。
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchTerm('status', 'active') ->searchRange('price', 100, 500) ->searchMatch('description', '手机') ->limit(20) ->searchQuery();
布尔查询 (BoolQuery)
支持完整的布尔逻辑:must (AND)、should (OR)、must_not (NOT)、filter (过滤)。
// 复杂布尔查询示例: // (status = 'active' OR status = 'pending') AND price > 100 AND NOT (category = 'test') $rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchShould(function ($query) { $query->searchTerm('status', 'active'); }) ->searchShould(function ($query) { $query->searchTerm('status', 'pending'); }) ->minimumShouldMatch(1) // 至少匹配一个 should 条件 ->searchMust(function ($query) { $query->searchRange('price', 100, null); }) ->searchMustNot(function ($query) { $query->searchTerm('category', 'test'); }) ->searchQuery();
must 条件 (AND)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchMust(function ($query) { $query->searchTerm('status', 'active'); }) ->searchMust(function ($query) { $query->searchRange('price', 100, 500); }) ->searchQuery();
should 条件 (OR)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchShould(function ($query) { $query->searchTerm('category', 'electronics'); }) ->searchShould(function ($query) { $query->searchTerm('category', 'computers'); }) ->minimumShouldMatch(1) // 至少匹配一个 ->searchQuery();
must_not 条件 (NOT)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchTerm('status', 'active') ->searchMustNot(function ($query) { $query->searchTerm('is_deleted', true); }) ->searchQuery();
filter 条件 (无评分过滤)
$rows = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchMatch('description', '手机') // 参与评分 ->searchFilter(function ($query) { $query->searchTerm('status', 'active'); // 不参与评分,仅过滤 }) ->searchQuery();
异步搜索查询
$context = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchTerm('status', 'active') ->asyncSearchQuery(); // 稍后获取结果 $rows = $context->HWait();
SQL 查询
同步 SQL 查询
// 直接执行 SQL $rows = Ots::connection()->sql("SELECT * FROM users WHERE id = 1"); // 使用 Query Builder 构建 SQL $rows = Ots::connection()->table('users') ->where('status', 'active') ->where('age', '>', 18) ->sqlGet();
异步 SQL 查询
$context = Ots::connection()->asyncSql("SELECT * FROM users WHERE id = 1"); // 稍后获取结果 $rows = $context->HWait();
构建 SQL 字符串
$sql = Ots::connection()->table('users') ->where('status', 'active') ->toSql(); // 输出: SELECT * FROM users WHERE status = 'active'
Schema 操作
表操作
创建表
use HughCube\Laravel\OTS\Ots; use HughCube\Laravel\OTS\Schema\Blueprint; Ots::connection()->getSchemaBuilder()->create('users', function (Blueprint $table) { // 定义主键 $table->integer('id')->primaryKey()->autoIncrement(); $table->string('partition_key')->primaryKey(); });
创建表(带预定义属性列)
预定义属性列用于创建二级索引,必须在创建表时定义。
Ots::connection()->getSchemaBuilder()->create('orders', function (Blueprint $table) { // 定义主键 $table->string('user_id')->primaryKey(); $table->integer('order_id')->primaryKey()->autoIncrement(); // 预定义属性列(用于二级索引) $table->definedString('status'); // 字符串类型 $table->definedInteger('amount'); // 整数类型 $table->definedDouble('price'); // 浮点数类型 $table->definedBoolean('is_paid'); // 布尔类型 $table->definedBlob('data'); // 二进制类型 // 或者使用通用方法指定类型 $table->definedColumn('category', DefinedColumnTypeConst::DCT_STRING); });
删除表
Ots::connection()->getSchemaBuilder()->drop('users');
检查表是否存在
if (Ots::connection()->getSchemaBuilder()->hasTable('users')) { // 表存在 }
获取所有表
$tables = Ots::connection()->getSchemaBuilder()->getAllTables();
二级索引
创建全局二级索引
Ots::connection()->getSchemaBuilder()->createGlobalIndex( 'users', // 表名 'users_email_idx', // 索引名 function (Blueprint $table) { $table->string('email')->primaryKey(); $table->integer('id')->primaryKey(); // 定义索引包含的属性列 $table->definedColumn('name'); $table->definedColumn('created_at'); } );
创建本地二级索引
Ots::connection()->getSchemaBuilder()->createLocalIndex( 'users', 'users_status_idx', function (Blueprint $table) { $table->integer('id')->primaryKey(); $table->string('status')->primaryKey(); } );
删除二级索引
Ots::connection()->getSchemaBuilder()->dropSecondaryIndex('users', 'users_email_idx');
搜索索引
创建搜索索引
use Aliyun\OTS\ProtoBuffer\Protocol\FieldType; Ots::connection()->getSchemaBuilder()->createSearchIndex( 'products', // 表名 'products_index', // 索引名 [ 'field_schemas' => [ ['field_name' => 'name', 'field_type' => FieldType::TEXT, 'analyzer' => 'single_word'], ['field_name' => 'description', 'field_type' => FieldType::TEXT, 'analyzer' => 'max_word'], ['field_name' => 'price', 'field_type' => FieldType::DOUBLE], ['field_name' => 'status', 'field_type' => FieldType::KEYWORD], ['field_name' => 'created_at', 'field_type' => FieldType::LONG], ], ] );
列出搜索索引
$indexes = Ots::connection()->getSchemaBuilder()->listSearchIndexes('products');
检查是否有搜索索引
// 检查表是否有任何搜索索引 if (Ots::connection()->getSchemaBuilder()->hasSearchIndex('products')) { // 有搜索索引 } // 检查是否有特定名称的搜索索引 if (Ots::connection()->getSchemaBuilder()->hasSearchIndex('products', 'products_index')) { // 指定的搜索索引存在 }
检查是否有二级索引
// 检查表是否有任何二级索引 if (Ots::connection()->getSchemaBuilder()->hasSecondaryIndex('users')) { // 有二级索引 } // 检查是否有特定名称的二级索引 if (Ots::connection()->getSchemaBuilder()->hasSecondaryIndex('users', 'users_email_idx')) { // 指定的二级索引存在 }
查看搜索索引详情
$info = Ots::connection()->getSchemaBuilder()->describeSearchIndex('products', 'products_index');
删除搜索索引
Ots::connection()->getSchemaBuilder()->dropSearchIndex('products', 'products_index');
事务支持
OTS 支持本地事务,用于同一分区键下的多行原子操作。
基础事务用法
use HughCube\Laravel\OTS\Ots; $connection = Ots::connection(); // 开始事务(需要指定分区键) $transaction = $connection->beginLocalTransaction('users', ['partition_key' => 'pk_value']); try { // 事务内操作 $transaction->putRow([ 'table_name' => 'users', 'primary_key' => [['id', 1], ['partition_key', 'pk_value']], 'attribute_columns' => [['name', 'John']], ]); $transaction->updateRow([ 'table_name' => 'users', 'primary_key' => [['id', 2], ['partition_key', 'pk_value']], 'update_of_attribute_columns' => [ 'PUT' => [['balance', 100]], ], ]); // 提交事务 $transaction->commit(); } catch (\Exception $e) { // 回滚事务 $transaction->rollback(); throw $e; }
使用回调方式
$connection->localTransaction('users', ['partition_key' => 'pk_value'], function ($transaction) { $transaction->putRow([...]); $transaction->updateRow([...]); // 回调结束自动提交,异常自动回滚 });
并行扫描
用于大数据量的高效扫描,支持多线程并行处理。
基础用法
use HughCube\Laravel\OTS\ParallelScanner; $scanner = new ParallelScanner(Ots::connection(), 'products', 'products_index'); // 设置查询条件 $scanner->matchAll(); // 获取所有结果 $rows = $scanner->get(); // 获取计数 $count = $scanner->count();
高级配置
$scanner = new ParallelScanner(Ots::connection(), 'products', 'products_index'); // 设置扫描参数 $scanner->limit(1000) // 每次扫描的行数 ->aliveTime(60) // 会话存活时间(秒) ->columns(['id', 'name']) // 指定返回的列 ->query($customQuery); // 自定义查询条件 // 计算分片 $scanner->computeSplits(); // 获取分片扫描器 $partitionScanners = $scanner->getPartitionScanners(); // 扫描特定分片 $rows = $scanner->getPartition(0);
数据流处理
用于监听表数据变更,实现实时数据同步。
启用数据流
Ots::connection()->getSchemaBuilder()->enableStream('users', 24); // 24小时过期
读取数据流
use HughCube\Laravel\OTS\Stream\StreamReader; $reader = new StreamReader(Ots::connection(), 'users'); // 获取所有分片的记录 $records = $reader->readAll(); // 收集所有记录 $allRecords = $reader->collect();
监听数据变更
$reader = new StreamReader(Ots::connection(), 'users'); // 长轮询监听(阻塞式) $reader->watch(function ($records) { foreach ($records as $record) { // 处理变更记录 $actionType = $record['action_type']; // PUT_ROW, UPDATE_ROW, DELETE_ROW $primaryKey = $record['primary_key']; $columns = $record['columns'] ?? []; } });
禁用数据流
Ots::connection()->getSchemaBuilder()->disableStream('users');
缓存驱动
Laravel OTS 提供了完整的缓存驱动实现。
配置缓存
在 config/cache.php 中添加:
'stores' => [ 'ots' => [ 'driver' => 'ots', 'connection' => 'ots', 'table' => 'cache', ], ],
基础缓存操作
use Illuminate\Support\Facades\Cache; // 设置缓存 Cache::store('ots')->put('key', 'value', 3600); // 获取缓存 $value = Cache::store('ots')->get('key'); // 永久缓存 Cache::store('ots')->forever('key', 'value'); // 删除缓存 Cache::store('ots')->forget('key'); // 批量操作 Cache::store('ots')->putMany(['key1' => 'value1', 'key2' => 'value2'], 3600); $values = Cache::store('ots')->many(['key1', 'key2']);
原子操作
// 自增/自减 Cache::store('ots')->increment('counter', 1); Cache::store('ots')->decrement('counter', 1); // 条件设置(不存在才设置) Cache::store('ots')->add('key', 'value', 3600);
分布式锁
$lock = Cache::store('ots')->lock('processing', 10); // 10秒超时 if ($lock->get()) { try { // 执行需要锁保护的操作 } finally { $lock->release(); } } // 阻塞式获取锁 $lock->block(5, function () { // 获取到锁后执行 });
清理过期缓存
// 手动清理过期行 Cache::store('ots')->flushExpiredRows();
Eloquent ORM
定义模型
use HughCube\Laravel\OTS\Eloquent\Model; class User extends Model { protected $connection = 'ots'; protected $table = 'users'; // 定义主键列 protected function getPrimaryKeyColumns(): array { return [ ['id', PrimaryKeyTypeConst::CONST_INTEGER], ]; } // 定义搜索索引(可选) protected $searchIndex = 'users_index'; }
使用模型
// 按主键查询 $user = User::find(['id' => 1]); // 创建 $user = new User(); $user->id = 1; $user->name = 'John'; $user->save(); // 更新 $user->name = 'John Doe'; $user->save(); // 删除 $user->delete();
Laravel Sanctum 集成
支持将 Sanctum 的 Personal Access Token 存储在 OTS 中,提供两种实现方式。
方式1:纯 OTS 表查询(推荐)
不依赖 Eloquent Model,直接操作 OTS 表。
use HughCube\Laravel\OTS\Sanctum\PersonalAccessToken; // 配置(可选) PersonalAccessToken::setConnectionName('ots'); // 设置 OTS 连接 PersonalAccessToken::setTableName('my_tokens'); // 设置表名 // 创建 Token $token = PersonalAccessToken::createToken($user, 'api-token', ['read', 'write']); echo $token->plainTextToken; // 返回明文 token // 查找 Token $token = PersonalAccessToken::findToken($plainTextToken); if ($token && $token->isValidAccessToken()) { $user = $token->tokenable(); // 获取关联用户 } // 检查权限 if ($token->can('write')) { // 有写入权限 } // 更新 Token $token->last_used_at = now(); $token->save(); // 删除 Token $token->delete();
方式2:Eloquent Model 方式
继承自 Laravel Sanctum 的 Model,兼容 Sanctum 的所有特性。
use HughCube\Laravel\OTS\Sanctum\EloquentPersonalAccessToken; // 查找 Token $token = EloquentPersonalAccessToken::findToken($plainTextToken); // 其他操作与标准 Sanctum Model 相同
Sanctum 配置
在 AppServiceProvider 中注册:
use Laravel\Sanctum\Sanctum; use HughCube\Laravel\OTS\Sanctum\PersonalAccessToken; public function boot() { Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class); }
创建 Token 表
Ots::connection()->getSchemaBuilder()->create('personal_access_tokens', function (Blueprint $table) { $table->string('token')->primaryKey(); // token hash $table->string('app')->primaryKey(); // 应用名(分区键) });
异步操作
大多数操作都支持异步模式,返回 RequestContext 对象,可以通过 HWait() 方法等待结果。
异步查询
// 异步单行查询 $context = Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->async() ->findByPrimaryKey(['id' => 1]); // 异步搜索 $context = Ots::connection()->table('products') ->useSearchIndex('products_index') ->searchTerm('status', 'active') ->asyncSearchQuery(); // 异步 SQL $context = Ots::connection()->asyncSql("SELECT * FROM users"); // 等待结果 $result = $context->HWait();
异步写入操作
// 异步插入 $context = Ots::connection()->table('users') ->primaryKeyColumns(['id' => PrimaryKeyTypeConst::CONST_INTEGER]) ->asyncInsert(['id' => 1, 'name' => 'John']); // 或者使用 async() 链式调用 $context = Ots::connection()->table('users') ->async() ->insert(['id' => 1, 'name' => 'John']); // 异步插入并获取自增 ID $context = Ots::connection()->table('users') ->primaryKeyColumns([ 'partition' => PrimaryKeyTypeConst::CONST_STRING, 'id' => PrimaryKeyTypeConst::CONST_PK_AUTO_INCR, ]) ->asyncInsertGetId(['partition' => 'user', 'name' => 'John']); // 获取结果后解析自增 ID $response = $context->HWait(); $id = $response['primary_key'][1][1] ?? null; // 异步更新 $context = Ots::connection()->table('users') ->primaryKey(['id' => 1]) ->asyncUpdate(['name' => 'John Doe']); // 异步删除 $context = Ots::connection()->table('users') ->asyncDelete(['id' => 1]);
并行执行多个异步操作
// 同时发起多个异步请求 $contexts = []; $contexts[] = Ots::connection()->table('users')->async()->findByPrimaryKey(['id' => 1]); $contexts[] = Ots::connection()->table('users')->async()->findByPrimaryKey(['id' => 2]); $contexts[] = Ots::connection()->table('users')->async()->findByPrimaryKey(['id' => 3]); // 等待所有结果 $results = []; foreach ($contexts as $context) { $results[] = $context->HWait(); }
通用异步处理
use HughCube\Laravel\OTS\OTS\Handlers\OTSHandlers; $context = OTSHandlers::asyncDoHandle( Ots::connection()->getOts(), 'getRow', $request ); $response = $context->HWait();
直接访问 OTS SDK
对于未封装的高级功能,可以直接访问底层 OTSClient:
$otsClient = Ots::connection()->getOts(); // 调用任意 SDK 方法 $response = $otsClient->describeTable(['table_name' => 'users']); // 或者通过 Connection 的魔术方法 $response = Ots::connection()->describeTable(['table_name' => 'users']);
工具方法
解析行数据
use HughCube\Laravel\OTS\Ots; // 解析单行 $row = Ots::parseRow($response['row']); // 解析自增 ID $id = Ots::parseRowAutoId($response);
检查批量写入结果
if (!Ots::isBatchWriteSuccess($response)) { Ots::throwBatchWriteException($response); }
Contributing
You can contribute in one of three ways:
- File bug reports using the issue tracker.
- Answer questions or fix bugs on the issue tracker.
- Contribute new features or update the wiki.
The code contribution process is not very formal. You just need to make sure that you follow the PSR-0, PSR-1, and PSR-2 coding guidelines. Any new code contributions must be accompanied by unit tests where applicable.
License
MIT