PHPackages                             hughcube/laravel-ots - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. hughcube/laravel-ots

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

hughcube/laravel-ots
====================

v1.3.0(2mo ago)06.3k↑295.8%1MITPHPPHP &gt;=7.1CI failing

Since Jun 9Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/hughcube/laravel-ots)[ Packagist](https://packagist.org/packages/hughcube/laravel-ots)[ RSS](/packages/hughcube-laravel-ots/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependencies (14)Versions (30)Used By (1)

 Laravel OTS
=============

[](#-laravel-ots-)

 [ ![Test Actions status](https://github.com/hughcube-php/laravel-ots/workflows/Test/badge.svg) ](https://github.com/hughcube-php/laravel-ots/actions?query=workflow%3ATest) [ ![StyleCI](https://camo.githubusercontent.com/287f1f9b5541a4dad09c9663da2c0a800c361cf81dcf9ae69e6b1c6a15af8683/68747470733a2f2f6769746875622e7374796c6563692e696f2f7265706f732f3337343934383035392f736869656c643f6272616e63683d6d6173746572) ](https://styleci.io/repos/374948059) [ ![Code Coverage](https://camo.githubusercontent.com/5954c5a7d3fab54188c16ff196d8c07741b0e53d696c999583bd49119fb347ea/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f68756768637562652d7068702f6c61726176656c2d6f74732f6261646765732f636f7665726167652e706e673f623d6d6173746572) ](https://scrutinizer-ci.com/g/hughcube-php/laravel-ots/?branch=master) [ ![Scrutinizer Code Quality](https://camo.githubusercontent.com/3714a3513b97bb5f3e910c684a5abad51bc9cd89b2736d503892ba7b68d27022/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f68756768637562652d7068702f6c61726176656c2d6f74732f6261646765732f7175616c6974792d73636f72652e706e673f623d6d6173746572) ](https://scrutinizer-ci.com/g/hughcube-php/laravel-ots/?branch=master) [ ![Code Intelligence Status](https://camo.githubusercontent.com/6448f3e3fe289c3f1a41afb2f1ff9a78abbf4831c977b0567e23a5bef1784de9/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f68756768637562652d7068702f6c61726176656c2d6f74732f6261646765732f636f64652d696e74656c6c6967656e63652e7376673f623d6d6173746572) ](https://scrutinizer-ci.com/g/hughcube-php/laravel-ots/?branch=master) [ ![PHP Versions Supported](https://camo.githubusercontent.com/5c3072425e67297c8ef63d17acd2c86a0d2ef324f19249f2280bd7de902f63a2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344253230372e302d3838393242462e737667) ](https://github.com/hughcube-php/laravel-ots) [ ![Latest Stable Version](https://camo.githubusercontent.com/8176599ef54beff0d3a1b32102bb8f7f0c02fa9d781e3c3359da9eeb53588af9/68747470733a2f2f706f7365722e707567782e6f72672f68756768637562652d7068702f6c61726176656c2d6f74732f76657273696f6e) ](https://packagist.org/packages/hughcube/laravel-ots) [ ![Total Downloads](https://camo.githubusercontent.com/f2e5f8a36a3de4d0de8adb8d12e64fd1d1d1d582495727a2fd3965a1039279d4/68747470733a2f2f706f7365722e707567782e6f72672f68756768637562652d7068702f6c61726176656c2d6f74732f646f776e6c6f616473) ](https://packagist.org/packages/hughcube/laravel-ots) [ ![License](https://camo.githubusercontent.com/cfb52dd4e8786e9468baa9a501c090c53367f978b1f8f2d48f3af252386cb874/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d3432386637652e737667) ](https://github.com/hughcube-php/laravel-ots/blob/master/LICENSE) [ ![Latest Unstable Version](https://camo.githubusercontent.com/656ab12153f0033d49133d4170f3ccb6242db59820f0c1a3a5db5bc46a24bfb2/68747470733a2f2f706f7365722e707567782e6f72672f68756768637562652d7068702f6c61726176656c2d6f74732f762f756e737461626c65) ](https://packagist.org/packages/hughcube/laravel-ots) [ ![composer.lock available](https://camo.githubusercontent.com/9a603d420465cb60b1fb89c6cef692e77e17077214d81edf5562c371239235bf/68747470733a2f2f706f7365722e707567782e6f72672f68756768637562652d7068702f6c61726176656c2d6f74732f636f6d706f7365726c6f636b) ](https://packagist.org/packages/hughcube/laravel-ots)

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

[](#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)

[](#精确查询-term)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchTerm('status', 'active')
    ->searchQuery();
```

### IN 查询 (Terms)

[](#in-查询-terms)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchTerms('category', ['electronics', 'books', 'clothing'])
    ->searchQuery();
```

### 模糊匹配查询 (Match)

[](#模糊匹配查询-match)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchMatch('description', '手机')
    ->searchQuery();
```

### 短语查询 (MatchPhrase)

[](#短语查询-matchphrase)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchMatchPhrase('title', 'iPhone 15')
    ->searchQuery();
```

### 前缀查询 (Prefix)

[](#前缀查询-prefix)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchPrefix('name', 'App')
    ->searchQuery();
```

### 通配符查询 (Wildcard)

[](#通配符查询-wildcard)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchWildcard('name', '*phone*')
    ->searchQuery();
```

### 范围查询 (Range)

[](#范围查询-range)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchRange('price', 100, 500)  // 100 table('products')
    ->useSearchIndex('products_index')
    ->searchRange('price', 100, 500, false, false)  // 100 < price < 500
    ->searchQuery();
```

### 匹配所有 (MatchAll)

[](#匹配所有-matchall)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchMatchAll()
    ->searchQuery();
```

### 存在性查询 (Exists)

[](#存在性查询-exists)

检查字段是否存在值。

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchExists('description')  // 只返回有 description 字段的记录
    ->searchQuery();
```

### 嵌套查询 (Nested)

[](#嵌套查询-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)

[](#地理距离查询-geodistance)

查找指定圆形范围内的地理位置。

```
$rows = Ots::connection()->table('stores')
    ->useSearchIndex('stores_index')
    ->searchGeoDistance('location', 31.2304, 121.4737, 5000)  // 上海市中心 5000 米范围内
    ->searchQuery();
```

### 地理边界框查询 (GeoBoundingBox)

[](#地理边界框查询-geoboundingbox)

查找矩形范围内的地理位置。

```
$rows = Ots::connection()->table('stores')
    ->useSearchIndex('stores_index')
    ->searchGeoBoundingBox(
        'location',
        31.3, 121.3,   // 左上角 (纬度, 经度)
        31.1, 121.6    // 右下角 (纬度, 经度)
    )
    ->searchQuery();
```

### 地理多边形查询 (GeoPolygon)

[](#地理多边形查询-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)

多个条件默认使用 AND 逻辑组合。

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchTerm('status', 'active')
    ->searchRange('price', 100, 500)
    ->searchMatch('description', '手机')
    ->limit(20)
    ->searchQuery();
```

### 布尔查询 (BoolQuery)

[](#布尔查询-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)

[](#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)

[](#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)

[](#must_not-条件-not)

```
$rows = Ots::connection()->table('products')
    ->useSearchIndex('products_index')
    ->searchTerm('status', 'active')
    ->searchMustNot(function ($query) {
        $query->searchTerm('is_deleted', true);
    })
    ->searchQuery();
```

#### filter 条件 (无评分过滤)

[](#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 查询

[](#同步-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 查询

[](#异步-sql-查询)

```
$context = Ots::connection()->asyncSql("SELECT * FROM users WHERE id = 1");

// 稍后获取结果
$rows = $context->HWait();
```

### 构建 SQL 字符串

[](#构建-sql-字符串)

```
$sql = Ots::connection()->table('users')
    ->where('status', 'active')
    ->toSql();
// 输出: SELECT * FROM users WHERE status = 'active'
```

---

Schema 操作
---------

[](#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
------------

[](#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 集成
------------------

[](#laravel-sanctum-集成)

支持将 Sanctum 的 Personal Access Token 存储在 OTS 中，提供两种实现方式。

### 方式1：纯 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 方式

[](#方式2eloquent-model-方式)

继承自 Laravel Sanctum 的 Model，兼容 Sanctum 的所有特性。

```
use HughCube\Laravel\OTS\Sanctum\EloquentPersonalAccessToken;

// 查找 Token
$token = EloquentPersonalAccessToken::findToken($plainTextToken);

// 其他操作与标准 Sanctum Model 相同
```

### Sanctum 配置

[](#sanctum-配置)

在 `AppServiceProvider` 中注册：

```
use Laravel\Sanctum\Sanctum;
use HughCube\Laravel\OTS\Sanctum\PersonalAccessToken;

public function boot()
{
    Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}
```

### 创建 Token 表

[](#创建-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
------------

[](#直接访问-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
------------

[](#contributing)

You can contribute in one of three ways:

1. File bug reports using the [issue tracker](https://github.com/hughcube-php/laravel-ots/issues).
2. Answer questions or fix bugs on the [issue tracker](https://github.com/hughcube-php/laravel-ots/issues).
3. 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
-------

[](#license)

MIT

###  Health Score

47

—

FairBetter than 93% of packages

Maintenance86

Actively maintained with recent releases

Popularity23

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 91.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~63 days

Recently: every ~17 days

Total

29

Last Release

71d ago

Major Versions

v0.0.2 → v1.0.02022-01-06

PHP version history (5 changes)v0.0.1PHP 7.\*|8.\*

v0.0.2PHP &gt;=7.1|8.\*

v1.0.4PHP &gt;=7.2

v1.2.0PHP &gt;=7.4

v1.2.3PHP &gt;=7.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5361789?v=4)[hugh.li](/maintainers/hughcube)[@hughcube](https://github.com/hughcube)

---

Top Contributors

[![hughcube](https://avatars.githubusercontent.com/u/5361789?v=4)](https://github.com/hughcube "hughcube (56 commits)")[![StyleCIBot](https://avatars.githubusercontent.com/u/11048387?v=4)](https://github.com/StyleCIBot "StyleCIBot (5 commits)")

###  Code Quality

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/hughcube-laravel-ots/health.svg)

```
[![Health](https://phpackages.com/badges/hughcube-laravel-ots/health.svg)](https://phpackages.com/packages/hughcube-laravel-ots)
```

###  Alternatives

[philippemarcmeyer/fieldslinker

Designed for matching files headers to database fields during the process importing. Allows drawing links between elements of 2 lists.

2385.6k](/packages/philippemarcmeyer-fieldslinker)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
