首页 理论 架构 工程 文档 白皮书 著作 研究 案例 下载 博客 关于 开始使用 →

第242章 Repository→MySQL

第242章 Repository→MySQL

242.1 提出背景

第239章建立:

Controller→ServiceController\rightarrow Service

第240章建立:

Service→EngineService\rightarrow Engine

第241章建立:

Engine→DomainObjectEngine\rightarrow DomainObject

经过这三个层次以后,ICAI 系统已经能够接收业务请求、组织业务流程、执行领域计算,并修改 Domain Object。

但是 Domain Object 在内存中的变化不能永久存在。

机器个体需要:

  • 查询已有数据;
  • 保存新对象;
  • 更新已有对象;
  • 删除不再需要的数据。

因此需要建立持久化关系:

Repository→MySQL\boxed{ Repository\rightarrow MySQL }

完整工程链进一步形成:

Controller→Service→Engine→DomainObject→Repository→MySQL\boxed{ Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL }

其中:

Repository=持久化访问层Repository=持久化访问层 MySQL=关系型数据库MySQL=关系型数据库

Repository 不负责领域计算,MySQL 也不负责 ICAI 业务逻辑。

本章重点建立四种基础数据操作:

QueryQuery SaveSave UpdateUpdate DeleteDelete


242.2 Repository→MySQL定义

Repository→MySQL是指 Repository 根据 Domain Object 和业务持久化要求,通过数据库访问机制向 MySQL 执行数据查询、保存、更新和删除等持久化操作,并将数据库记录转换为系统能够使用的数据或 Domain Object。

基本关系:

Repository→MySQL\boxed{ Repository\rightarrow MySQL }

完整过程:

DomainObject→Repository→MySQLDomainObject \rightarrow Repository \rightarrow MySQL

查询时则反向:

MySQL→Repository→DomainObjectMySQL \rightarrow Repository \rightarrow DomainObject

因此 Repository 与 MySQL 之间形成:

Repository↔MySQL\boxed{ Repository \leftrightarrow MySQL }

但这种双向关系并不意味着 Repository 和数据库职责相同。

Repository 负责:

如何按照系统的领域需求访问数据。

MySQL 负责:

如何存储和管理关系型数据。


242.3 Repository

**Repository(仓储)**是 Domain Object 与持久化数据之间的访问抽象。

它的主要职责是:

Repository=Query+Save+Update+DeleteRepository= Query+ Save+ Update+ Delete

例如:

class IndividualRepository
{
    public function find($id)
    {
    }

    public function save($individual)
    {
    }

    public function update($individual)
    {
    }

    public function delete($id)
    {
    }
}

Service 不需要知道具体 SQL:

$individual =
    $repository->find($id);

而不是:

$sql = "SELECT * FROM individuals WHERE id = ?";

因此:

Service→Repository\boxed{ Service\rightarrow Repository }

而:

Repository→MySQL\boxed{ Repository\rightarrow MySQL }


242.4 Repository与MySQL的职责边界

Repository 和 MySQL 必须保持职责分离。

Repository≠MySQLRepository\neq MySQL

Repository 是 PHP 工程对象。

MySQL 是数据库系统。

Repository 负责:

  • 组织查询;
  • 参数绑定;
  • 数据转换;
  • Domain Object 映射;
  • 保存;
  • 更新;
  • 删除;
  • 持久化异常处理。

MySQL 负责:

  • 表;
  • 字段;
  • 索引;
  • 数据存储;
  • SQL执行;
  • 事务;
  • 约束。

因此:

PHP Object→Repository→PDO→MySQLPHP\ Object \rightarrow Repository \rightarrow PDO \rightarrow MySQL


242.5 数据查询

**数据查询(Query)**是从 MySQL 中读取持久化数据并返回系统使用的数据或 Domain Object 的过程。

基本关系:

MySQL→Repository→DomainObject\boxed{ MySQL \rightarrow Repository \rightarrow DomainObject }

例如:

$individual =
    $repository->find(15);

Repository:

public function find($id)
{
    $sql = "
        SELECT
            id,
            name,
            type,
            state
        FROM individuals
        WHERE id = :id
    ";

    $statement =
        $this->pdo->prepare($sql);

    $statement->execute(
        array(':id' => $id)
    );

    $row =
        $statement->fetch(
            PDO::FETCH_ASSOC
        );

    if (!$row) {
        return null;
    }

    return $this->mapToDomain(
        $row
    );
}

数据流:

ID→Repository→SQL→MySQL→Record→DomainObjectID \rightarrow Repository \rightarrow SQL \rightarrow MySQL \rightarrow Record \rightarrow DomainObject


242.6 查询与Domain Object

Repository 查询的最终目标不是简单返回一行数组,而是根据系统设计将数据库记录转换成 Domain Object。

数据库:

id = 15
name = Robot A
type = machine
state = idle

经过:

DatabaseRecord→RepositoryDatabaseRecord \rightarrow Repository

转换为:

$individual

即:

DatabaseRecord→DomainObjectDatabaseRecord \rightarrow DomainObject

例如:

protected function mapToDomain(
    array $row
) {
    $individual =
        new Individual();

    $individual->setId(
        (int)$row['id']
    );

    $individual->setName(
        $row['name']
    );

    $individual->setType(
        $row['type']
    );

    $individual->setState(
        $row['state']
    );

    return $individual;
}

这样:

DomainObject≠DatabaseRecordDomainObject \neq DatabaseRecord

而是:

DatabaseRecord→RepositoryDomainObject\boxed{ DatabaseRecord \xrightarrow{Repository} DomainObject }


242.7 查询条件

Repository 可以提供不同查询方法。

例如:

find($id)

表示按照 ID 查询。

findByType($type)

表示按照类型查询。

findByState($state)

表示按照状态查询。

findAll()

表示查询全部。

因此:

Repository=QueryMethodsRepository= QueryMethods

例如:

public function findByState($state)
{
    $sql = "
        SELECT *
        FROM individuals
        WHERE state = :state
    ";

    $statement =
        $this->pdo->prepare($sql);

    $statement->execute(
        array(':state' => $state)
    );

    return $statement->fetchAll(
        PDO::FETCH_ASSOC
    );
}

242.8 查询安全

Repository 执行 SQL 时必须使用参数绑定。

不推荐:

$sql =
    "SELECT * FROM individuals
     WHERE id = " . $id;

推荐:

$sql = "
    SELECT *
    FROM individuals
    WHERE id = :id
";

$statement =
    $this->pdo->prepare($sql);

$statement->execute(
    array(':id' => $id)
);

形成:

Parameter→PreparedStatement→MySQLParameter \rightarrow PreparedStatement \rightarrow MySQL

这样可以避免将外部字符串直接拼接进入 SQL。


242.9 数据保存

**数据保存(Save)**是将新的 Domain Object 转换为数据库记录,并写入 MySQL 的过程。

基本关系:

DomainObject→Repository→MySQL\boxed{ DomainObject \rightarrow Repository \rightarrow MySQL }

例如:

$individual =
    new Individual();

$individual->setName(
    'Robot A'
);

$individual->setType(
    'machine'
);

$individual->setState(
    'idle'
);

$repository->save(
    $individual
);

Repository:

public function save(
    Individual $individual
) {
    $sql = "
        INSERT INTO individuals
        (
            name,
            type,
            state
        )
        VALUES
        (
            :name,
            :type,
            :state
        )
    ";

    $statement =
        $this->pdo->prepare($sql);

    $statement->execute(
        array(
            ':name' =>
                $individual->getName(),

            ':type' =>
                $individual->getType(),

            ':state' =>
                $individual->getState()
        )
    );

    $individual->setId(
        $this->pdo->lastInsertId()
    );

    return $individual;
}

242.10 保存与创建

数据保存通常发生在 Domain Object 创建以后。

过程:

Create→Initialize→DomainObject→SaveCreate \rightarrow Initialize \rightarrow DomainObject \rightarrow Save

例如:

创建机器个体
↓
初始化属性
↓
初始化状态
↓
形成Domain Object
↓
Repository
↓
INSERT
↓
MySQL

因此:

DomainObject→Repository→INSERTDomainObject \rightarrow Repository \rightarrow INSERT

最终形成持久化对象。


242.11 保存后的ID

如果数据库使用自增主键,那么新对象保存以后会获得数据库生成的 ID。

例如:

保存前:

id = null

执行:

INSERT

以后:

保存后:

id = 15

因此:

Object.id=∅Object.id=\varnothing

经过:

Repository.save()Repository.save()

变为:

Object.id=15Object.id=15

这是 Domain Object 与数据库生命周期连接的重要过程。


242.12 数据更新

**数据更新(Update)**是将已经存在的 Domain Object 的最新状态同步到 MySQL 的过程。

基本关系:

DomainObjectnew→Repository→UPDATE→MySQL\boxed{ DomainObject_{new} \rightarrow Repository \rightarrow UPDATE \rightarrow MySQL }

例如:

原状态:

id = 15
state = idle

Engine 计算以后:

state = running

然后:

$individual->setState(
    'running'
);

$repository->update(
    $individual
);

数据库:

UPDATE individuals
SET state = :state
WHERE id = :id

形成:

idle→runningidle \rightarrow running

最终数据库同步:

DatabaseStatet→DatabaseStatet+1DatabaseState_t \rightarrow DatabaseState_{t+1}


242.13 Update与Engine状态变化

第241章建立:

Engine→DomainObject→StateUpdateEngine \rightarrow DomainObject \rightarrow StateUpdate

本章继续:

DomainObject→Repository→MySQLDomainObject \rightarrow Repository \rightarrow MySQL

因此两个章节连接为:

Engine→DomainObject→Repository→MySQL\boxed{ Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL }

例如:

数据库:
idle

↓ Repository查询

Domain Object:
idle

↓ Engine计算

Domain Object:
running

↓ Repository更新

数据库:
running

这形成完整的状态持久化链。


242.14 更新方法

Repository 可以定义:

public function update(
    Individual $individual
) {
    $sql = "
        UPDATE individuals
        SET
            name = :name,
            type = :type,
            state = :state
        WHERE id = :id
    ";

    $statement =
        $this->pdo->prepare($sql);

    return $statement->execute(
        array(
            ':id' =>
                $individual->getId(),

            ':name' =>
                $individual->getName(),

            ':type' =>
                $individual->getType(),

            ':state' =>
                $individual->getState()
        )
    );
}

这里:

WHERE id=:idWHERE\ id=:id

决定更新哪一个 Domain Object。

因此:

ObjectID→DatabaseRecordObjectID \rightarrow DatabaseRecord

是更新过程的重要标识。


242.15 数据删除

**数据删除(Delete)**是从持久化存储中删除指定数据记录的过程。

基本关系:

DomainIdentity→Repository→DELETE→MySQL\boxed{ DomainIdentity \rightarrow Repository \rightarrow DELETE \rightarrow MySQL }

例如:

$repository->delete(
    15
);

Repository:

public function delete($id)
{
    $sql = "
        DELETE FROM individuals
        WHERE id = :id
    ";

    $statement =
        $this->pdo->prepare($sql);

    return $statement->execute(
        array(':id' => $id)
    );
}

形成:

ID→DELETE→RecordRemovedID \rightarrow DELETE \rightarrow RecordRemoved


242.16 删除与Domain Object

删除数据库记录不一定等于销毁 Domain Object。

必须区分:

DatabaseDeleteDatabaseDelete

与:

ObjectDestroyObjectDestroy

例如:

Domain Object
↓
Repository.delete()
↓
MySQL记录删除

此时数据库记录不存在了,但当前 PHP 请求中的 Domain Object 变量可能仍然存在。

因此:

DatabaseRecord=∅DatabaseRecord=\varnothing

不代表:

DomainObject=∅DomainObject=\varnothing

两者属于不同生命周期。


242.17 删除与ICAI对象生命周期

第159章建立了:

Create→Initialize→Load→Run→Modify→Save→Update→DestroyCreate \rightarrow Initialize \rightarrow Load \rightarrow Run \rightarrow Modify \rightarrow Save \rightarrow Update \rightarrow Destroy

数据库删除主要对应持久化层的:

DeleteDelete

而 Domain Object 销毁属于:

DestroyDestroy

因此:

Delete≠DestroyDelete\neq Destroy

例如 ICAI 机器个体被停用以后,可以选择:

active
↓
inactive

而不是直接:

DELETE

因此数据库删除必须根据具体领域规则决定。


242.18 软删除

对于某些 ICAI 对象,不适合直接删除数据库记录,可以采用状态标记。

例如:

deleted = 1

或者:

status = deleted

此时:

LogicalDeleteLogicalDelete

代替:

PhysicalDeletePhysicalDelete

例如:

UPDATE individuals
SET deleted = 1
WHERE id = :id

这样历史数据仍然保留。

因此:

DeleteDelete

可以进一步分为:

Delete=LogicalDelete+PhysicalDeleteDelete= LogicalDelete+ PhysicalDelete

具体方式取决于 Domain Object 的生命周期和历史保存要求。


242.19 Repository四种基本操作

Repository 最基本的数据操作可以统一为:

CRUD\boxed{ CRUD }

其中:

C=CreateC=Create R=ReadR=Read U=UpdateU=Update D=DeleteD=Delete

对应:

操作 Repository MySQL
创建 save INSERT
查询 find/query SELECT
更新 update UPDATE
删除 delete DELETE

因此:

Repository→CRUD→MySQLRepository \rightarrow CRUD \rightarrow MySQL


242.20 Repository与Service

Service 不应该直接操作 MySQL。

错误:

Service
↓
SQL
↓
MySQL

推荐:

Service
↓
Repository
↓
MySQL

例如:

class IndividualService
{
    protected $repository;

    public function __construct(
        IndividualRepository $repository
    ) {
        $this->repository =
            $repository;
    }

    public function find($id)
    {
        return $this->repository
            ->find($id);
    }
}

因此:

Service→RepositoryService \rightarrow Repository

而:

Repository→MySQLRepository \rightarrow MySQL


242.21 Repository与Engine

Engine 通常也不应该直接操作 MySQL。

错误:

Engine
↓
SQL
↓
MySQL

推荐:

Service
↓
Repository
↓
Domain Object
↓
Engine
↓
Domain Object
↓
Repository
↓
MySQL

即:

Engine≠Repository\boxed{ Engine \neq Repository }

Engine 负责:

CalculationCalculation

Repository 负责:

PersistencePersistence


242.22 Repository与Domain Object双向转换

Repository 的重要职责之一是完成:

Record↔DomainObjectRecord\leftrightarrow DomainObject

查询:

MySQLRecord→Repository→DomainObjectMySQLRecord \rightarrow Repository \rightarrow DomainObject

保存:

DomainObject→Repository→MySQLRecordDomainObject \rightarrow Repository \rightarrow MySQLRecord

因此:

Repository=Mapping+Persistence\boxed{ Repository= Mapping+ Persistence }

例如:

MySQL:
id,name,type,state

↓ map

Domain Object:
Individual

反方向:

Domain Object:
Individual

↓ map

MySQL:
id,name,type,state

242.23 Repository查询完整流程

查询流程:

Request
↓
Controller
↓
Service
↓
Repository
↓
PDO
↓
MySQL
↓
Record
↓
Repository
↓
Domain Object
↓
Service
↓
Controller

数学形式:

ID→Repository→MySQL→Record→DomainObject\boxed{ ID \rightarrow Repository \rightarrow MySQL \rightarrow Record \rightarrow DomainObject }

这是数据库数据进入 ICAI 运行环境的基本入口。


242.24 Repository保存完整流程

保存流程:

Domain Object
↓
Service
↓
Repository
↓
PDO
↓
INSERT
↓
MySQL
↓
Insert ID
↓
Repository
↓
Domain Object

数学形式:

DomainObject→Repository→INSERT→MySQL\boxed{ DomainObject \rightarrow Repository \rightarrow INSERT \rightarrow MySQL }

如果产生新的 ID:

MySQL→Repository→DomainObject.idMySQL \rightarrow Repository \rightarrow DomainObject.id


242.25 Repository更新完整流程

更新流程:

Domain Object
↓
Engine计算
↓
状态修改
↓
Service
↓
Repository
↓
UPDATE
↓
MySQL

数学模型:

Objectt→Engine→Objectt+1→Repository→Databaset+1\boxed{ Object_t \rightarrow Engine \rightarrow Object_{t+1} \rightarrow Repository \rightarrow Database_{t+1} }

因此:

Objectt+1≈Databaset+1Object_{t+1} \approx Database_{t+1}

这里的“≈”表示领域对象状态与持久化状态完成同步,而不是两个对象在技术上完全相同。


242.26 Repository删除完整流程

删除流程:

Business Request
↓
Controller
↓
Service
↓
Repository
↓
DELETE
↓
MySQL

如果采用软删除:

Service
↓
Repository
↓
UPDATE deleted=1
↓
MySQL

因此删除的具体实现应该由业务规则决定,而不是简单地认为:

Delete=SQL DELETEDelete=SQL\ DELETE


242.27 MySQL表与Domain Object

例如机器个体 Domain Object:

class Individual
{
    protected $id;
    protected $name;
    protected $type;
    protected $state;
}

对应数据库:

CREATE TABLE individuals (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    type VARCHAR(100) NOT NULL,
    state VARCHAR(100) NOT NULL,
    created_at DATETIME NOT NULL,
    updated_at DATETIME NOT NULL
);

形成:

Individual↔individualsIndividual \leftrightarrow individuals

但不能简单认为:

Individual=individualsIndividual=individuals

因为:

Individual=DomainObjectIndividual=DomainObject

而:

individuals=DatabaseTableindividuals=DatabaseTable

两者属于不同层次。


242.28 Repository接口

可以定义:

interface IndividualRepositoryInterface
{
    public function find($id);

    public function save(
        Individual $individual
    );

    public function update(
        Individual $individual
    );

    public function delete($id);
}

具体实现:

class MySQLIndividualRepository
    implements IndividualRepositoryInterface
{
    protected $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function find($id)
    {
        // SELECT
    }

    public function save(
        Individual $individual
    ) {
        // INSERT
    }

    public function update(
        Individual $individual
    ) {
        // UPDATE
    }

    public function delete($id)
    {
        // DELETE
    }
}

因此:

Service→RepositoryInterfaceService \rightarrow RepositoryInterface

而:

MySQLRepository→MySQLMySQLRepository \rightarrow MySQL

可以降低业务层与具体数据库访问实现之间的耦合。


242.29 PDO与MySQL

在 PHP 工程中,可以通过 PDO 访问 MySQL:

PHP→PDO→MySQLPHP \rightarrow PDO \rightarrow MySQL

例如:

$pdo = new PDO(
    'mysql:host=localhost;dbname=icai;charset=utf8mb4',
    'root',
    'password'
);

然后:

$statement =
    $pdo->prepare($sql);

执行:

$statement->execute(
    $params
);

Repository 使用 PDO,而不是把 PDO 连接代码散布到 Service 和 Engine 中。

因此:

PDO连接属于Repository基础设施边界\boxed{ PDO连接属于Repository基础设施边界 }


242.30 数据查询异常

查询可能发生异常:

数据库连接失败
SQL执行失败
表不存在
字段不存在
参数错误
权限不足

因此:

Repository→PersistenceExceptionRepository \rightarrow PersistenceException

Repository 不应该静默返回错误数据。

错误:

try {
    // query
} catch (Exception $e) {
    return array();
}

这种处理会把:

DatabaseErrorDatabaseError

错误转换成:

EmptyDataEmptyData

Service 就无法区分:

NoDataNoData

和:

QueryFailedQueryFailed

正确做法是保持异常语义:

Repository→Exception→ServiceRepository \rightarrow Exception \rightarrow Service


242.31 查询为空与查询失败

必须严格区分:

NotFoundNotFound

和:

QueryFailedQueryFailed

例如:

数据库正常:

SELECT
↓
0 records

这是:

NotFoundNotFound

数据库异常:

SELECT
↓
Connection Error

这是:

PersistenceExceptionPersistenceException

因此:

NotFound≠QueryFailed\boxed{ NotFound\neq QueryFailed }

这是 Repository 工程的重要边界。


242.32 保存、更新与事务

如果一个业务过程涉及多个数据库操作,就可能需要事务。

例如:

保存Individual
↓
保存Capability
↓
保存Goal
↓
保存Memory

如果中间失败:

保存Individual ✓
保存Capability ✓
保存Goal ✗

则系统可能处于不完整状态。

因此:

Transaction=Begin→Operations→Commit/RollbackTransaction= Begin \rightarrow Operations \rightarrow Commit/Rollback

例如:

$pdo->beginTransaction();

try {

    // INSERT
    // INSERT
    // UPDATE

    $pdo->commit();

} catch (Exception $e) {

    $pdo->rollBack();

    throw $e;
}

事务属于持久化一致性机制。


242.33 Repository与状态一致性

Engine 修改 Domain Object 后:

StateObjectState_{Object}

发生变化。

如果没有保存:

StateDatabaseState_{Database}

仍然可能保持旧状态。

例如:

Domain Object:
running

MySQL:
idle

此时:

StateObject≠StateDatabaseState_{Object}\neq State_{Database}

因此:

ObjectChange→Persistence→Synchronization\boxed{ ObjectChange \rightarrow Persistence \rightarrow Synchronization }

Repository 的重要作用就是完成这种状态持久化。


242.34 Repository与ICAI记忆

ICAI 的记忆结构也需要持久化。

例如:

individual_memory

可以保存:

id
individual_id
memory_type
content
state
source
created_at

形成:

MemoryObject→MemoryRepository→MySQLMemoryObject \rightarrow MemoryRepository \rightarrow MySQL

同样:

Experience→ExperienceRepository→MySQLExperience \rightarrow ExperienceRepository \rightarrow MySQL Knowledge→KnowledgeRepository→MySQLKnowledge \rightarrow KnowledgeRepository \rightarrow MySQL

因此 Repository 不只是保存普通 CRUD 数据,也是 ICAI 长期运行的重要持久化基础。


242.35 Repository与机器个体生命周期

机器个体运行过程中会不断经历:

Load→Run→Modify→Save→UpdateLoad \rightarrow Run \rightarrow Modify \rightarrow Save \rightarrow Update

例如:

MySQL
↓
Repository.find()
↓
Domain Object
↓
Engine
↓
状态变化
↓
Repository.update()
↓
MySQL

最终:

Databaset→Objectt→Engine→Objectt+1→Databaset+1Database_t \rightarrow Object_t \rightarrow Engine \rightarrow Object_{t+1} \rightarrow Database_{t+1}

这形成机器个体的一次完整持久化运行周期。


242.36 Repository→MySQL完整工程模型

综合本章:

                    ┌──────────────┐
                    │    MySQL     │
                    └──────┬───────┘
                           ↑↓
                    ┌──────┴───────┐
                    │  Repository  │
                    └──────┬───────┘
                           ↑↓
                    ┌──────┴───────┐
                    │ DomainObject │
                    └──────┬───────┘
                           ↑↓
                       Engine
                           ↑↓
                       Service
                           ↑↓
                      Controller

核心数据库操作:

Query+Save+Update+Delete\boxed{ Query+Save+Update+Delete }

对应:

SELECT+INSERT+UPDATE+DELETE\boxed{ SELECT+INSERT+UPDATE+DELETE }


242.37 四种操作统一模型

可以将四种基本操作统一为:

查询

MySQL→Repository→DomainObjectMySQL \rightarrow Repository \rightarrow DomainObject

保存

DomainObject→Repository→MySQLDomainObject \rightarrow Repository \rightarrow MySQL

更新

DomainObjectnew→Repository→MySQLDomainObject_{new} \rightarrow Repository \rightarrow MySQL

删除

Identity→Repository→MySQLIdentity \rightarrow Repository \rightarrow MySQL

因此:

Repository=Read+Create+Update+Delete\boxed{ Repository= Read+ Create+ Update+ Delete }


242.38 本章核心边界

本章必须保持以下边界:

Repository≠MySQL\boxed{ Repository\neq MySQL } DomainObject≠DatabaseRecord\boxed{ DomainObject\neq DatabaseRecord } Service≠Repository\boxed{ Service\neq Repository } Engine≠Repository\boxed{ Engine\neq Repository } Delete≠Destroy\boxed{ Delete\neq Destroy } NotFound≠QueryFailed\boxed{ NotFound\neq QueryFailed } ObjectUpdate≠DatabaseUpdate\boxed{ ObjectUpdate\neq DatabaseUpdate }

对象首先发生领域变化:

DomainObjectt→DomainObjectt+1DomainObject_t \rightarrow DomainObject_{t+1}

然后才进行持久化:

DomainObjectt+1→Repository→MySQLDomainObject_{t+1} \rightarrow Repository \rightarrow MySQL


242.39 ICAI完整数据运行链

第239章到第242章可以形成完整工程链:

Controller→Service→Engine→DomainObject→Repository→MySQL\boxed{ Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL }

具体过程:

HTTP Request
↓
Controller
↓
Service
↓
Repository 查询
↓
Domain Object
↓
Engine 计算
↓
Domain Object 修改
↓
State Update
↓
Repository 更新
↓
MySQL
↓
Business Result
↓
Controller
↓
Response

这已经构成一个完整的 ICAI 单次业务运行过程。


242.40 本章总结

Repository→MySQL 是 ICAI 工程体系中实现数据持久化的核心关系。

Repository 负责将 Domain Object 与数据库记录连接起来:

DomainObject↔Repository↔MySQL\boxed{ DomainObject \leftrightarrow Repository \leftrightarrow MySQL }

查询:

MySQL→Repository→DomainObject\boxed{ MySQL \rightarrow Repository \rightarrow DomainObject }

保存:

DomainObject→Repository→INSERT→MySQL\boxed{ DomainObject \rightarrow Repository \rightarrow INSERT \rightarrow MySQL }

更新:

DomainObjectnew→Repository→UPDATE→MySQL\boxed{ DomainObject_{new} \rightarrow Repository \rightarrow UPDATE \rightarrow MySQL }

删除:

Identity→Repository→DELETE→MySQL\boxed{ Identity \rightarrow Repository \rightarrow DELETE \rightarrow MySQL }

因此四种基本数据操作可以统一为:

Query+Save+Update+Delete\boxed{ Query+ Save+ Update+ Delete }

而 ICAI 完整运行链进一步形成:

Controller→Service→Engine→DomainObject→Repository→MySQL\boxed{ Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL }

数据查询方向:

MySQL→Repository→DomainObject\boxed{ MySQL \rightarrow Repository \rightarrow DomainObject }

数据修改方向:

DomainObject→Repository→MySQL\boxed{ DomainObject \rightarrow Repository \rightarrow MySQL }

由此,前面三个工程关系:

Controller→ServiceController\rightarrow Service Service→EngineService\rightarrow Engine Engine→DomainObjectEngine\rightarrow DomainObject

与本章:

Repository→MySQLRepository\rightarrow MySQL

共同形成 ICAI MVC 工程中的完整数据与计算路径:

Request→Controller→Service→Engine→DomainObject→Repository→MySQL\boxed{ Request \rightarrow Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL }

而从数据库重新进入机器个体运行环境,则形成反向数据加载:

MySQL→Repository→DomainObject→Engine→State\boxed{ MySQL \rightarrow Repository \rightarrow DomainObject \rightarrow Engine \rightarrow State }

至此,ICAI 已经形成从请求、业务、计算、对象、持久化数据重新加载的基本闭环,为后续数据库关系、事务、数据一致性以及 ICAI Runtime 的持续运行奠定工程基础。

第242B章 统一持久化层接口语义

242B.1 提出背景

第242章已经建立:

Repository→MySQLRepository\rightarrow MySQL

并确定 Repository 负责数据查询、保存、更新和删除,将 Domain Object 与 MySQL 数据连接起来。

但是,当 ICAI 系统中的 Domain Object 不断增加以后,仅仅拥有 Repository 还存在一个新的问题。

例如:

IndividualRepository
GoalRepository
CapabilityRepository
MemoryRepository
BehaviorRepository
RiskRepository

如果每一个 Repository 都自行定义方法:

get()
load()
read()
find()
insert()
save()
store()
modify()
update()
remove()
delete()

虽然这些 Repository 都能够访问数据库,但是整个 ICAI 系统的持久化接口会逐渐失去统一性。

因此,在:

Repository→MySQLRepository\rightarrow MySQL

的基础上,还必须建立:

统一持久化层接口语义\boxed{ 统一持久化层接口语义 }

其核心不是规定所有 Repository 必须使用完全相同的数据库表结构,而是规定:

相同的持久化行为必须具有一致的接口名称、输入语义、输出语义、状态语义和异常语义。

因此形成:

DomainObject→RepositoryInterface→Repository→MySQLDomainObject \rightarrow RepositoryInterface \rightarrow Repository \rightarrow MySQL


242B.2 统一持久化层接口定义

统一持久化层接口(Unified Persistence Interface),是指 ICAI 对不同 Domain Object 的持久化操作建立统一的程序接口规范,使不同 Repository 对外表现出一致的基本操作语义。

可以定义:

PersistenceInterface={Create,Find,Save,Update,Delete}PersistenceInterface= \{ Create, Find, Save, Update, Delete \}

其中:

  • Create:建立新的持久化对象;
  • Find:根据身份或条件获取对象;
  • Save:保存对象当前状态;
  • Update:更新已经存在的对象;
  • Delete:删除持久化对象。

这里必须明确:

Interface≠ImplementationInterface\neq Implementation

接口规定:

应该提供什么持久化能力。

实现规定:

具体如何完成持久化。


242B.3 为什么需要统一接口

如果没有统一接口,不同 Repository 很容易出现:

IndividualRepository::find()

GoalRepository::get()

MemoryRepository::load()

BehaviorRepository::read()

这些方法虽然可能都表示“查询”,但是调用者必须记住每一个 Repository 的不同名称。

统一以后:

IndividualRepository::find()

GoalRepository::find()

MemoryRepository::find()

BehaviorRepository::find()

于是:

QuerySemantic=FindQuerySemantic=Find

调用者只需要理解一种基本查询语义。

因此:

统一接口→降低系统认知复杂度\boxed{ 统一接口\rightarrow降低系统认知复杂度 }

统一接口并不是为了减少代码,而是为了减少不同模块之间的语义差异。


242B.4 Repository接口的核心原则

统一持久化接口必须遵循三个基本原则。

第一:

接口统一接口统一

第二:

语义统一语义统一

第三:

实现可以不同实现可以不同

因此:

RepositoryInterface
        ↓
 ┌──────┼────────┐
 ↓      ↓        ↓
Individual Goal  Memory
Repository Repository Repository
        ↓
      MySQL

不同 Repository 可以拥有不同的领域对象、不同的表结构和不同的数据映射方式,但对外提供的基本持久化语义应该保持一致。


242B.5 Create语义

Create 表示:

建立一个新的持久化对象。

形式:

Create(O)→PersistentObjectCreate(O) \rightarrow PersistentObject

其中 OO 表示 Domain Object。

例如:

$repository->create($individual);

其基本过程为:

Domain Object
↓
身份检查
↓
数据映射
↓
INSERT
↓
获得持久化身份
↓
持久化完成

因此:

Create=NewObject+PersistenceCreate= NewObject+ Persistence

Create 的重点是:

对象此前不存在于当前持久化集合中。


242B.6 Find语义

Find 表示:

根据对象身份寻找已经存在的持久化对象。

例如:

$individual =
    $repository->find($id);

其过程:

Identity→Repository→MySQL→Record→DomainObjectIdentity \rightarrow Repository \rightarrow MySQL \rightarrow Record \rightarrow DomainObject

如果找到:

Find(id)=DomainObjectFind(id)=DomainObject

如果没有找到:

Find(id)=nullFind(id)=null

因此:

NotFound\neqException\boxed{ NotFound\neqException }

正常查询没有找到对象,不一定是系统错误。


242B.7 Save语义

Save 表示:

将 Domain Object 当前状态保存到持久化层。

形式:

Save(O)→Persist(O)Save(O) \rightarrow Persist(O)

它关注的是:

CurrentDomainStateCurrentDomainState

而不是单纯的 SQL INSERT

因此:

Save≠INSERTSave\neq INSERT

也不能简单定义:

Save=UPDATESave=UPDATE

具体采用 INSERT 还是 UPDATE,应由 Repository 的持久化状态规则决定。

因此 Save 是一种较高层的持久化语义,而不是某一条固定 SQL 语句的别名。


242B.8 Update语义

Update 表示:

将已经存在的持久化对象更新为当前 Domain Object 的状态。

形式:

Ot→Update→Ot+1O_t \rightarrow Update \rightarrow O_{t+1}

例如:

$individual->setState('running');

$repository->update(
    $individual
);

其本质是:

DomainStatenew→PersistentStatenewDomainState_{new} \rightarrow PersistentState_{new}

因此:

Update⇒ExistingObjectUpdate\Rightarrow ExistingObject

如果对象根本不存在,则不能无条件把 update() 转换为 create()

否则就会造成接口语义混乱。


242B.9 Delete语义

Delete 表示:

移除对象对应的持久化记录。

形式:

Identity→Delete→NotPersistedIdentity \rightarrow Delete \rightarrow NotPersisted

例如:

$repository->delete($id);

但是必须保持:

Delete≠Destroy\boxed{ Delete\neq Destroy }

Delete 属于持久化层。

Destroy 属于对象生命周期。

因此:

Repository::delete()

不能直接解释为:

DomainObject::destroy()

242B.10 五种接口的统一模型

统一接口可以表示为:

PersistenceInterface={Create,Find,Save,Update,Delete}\boxed{ PersistenceInterface= \{ Create, Find, Save, Update, Delete \} }

对应:

接口 语义 输入 结果
create() 建立持久化对象 Domain Object 持久化结果
find() 查找对象 Identity Domain Object / null
save() 保存当前状态 Domain Object 持久化结果
update() 更新已有对象 Domain Object 持久化结果
delete() 删除持久化记录 Identity 持久化结果

这五种操作构成统一持久化层的基础语义。


242B.11 RepositoryInterface

PHP 中可以建立统一接口:

interface RepositoryInterface
{
    public function create($object);

    public function find($id);

    public function save($object);

    public function update($object);

    public function delete($id);
}

这里的接口不负责:

SQL
PDO
MySQL

它只负责定义:

ContractContract

即:

Repository 必须向上层提供什么能力。


242B.12 Domain Object作为接口输入

统一持久化接口应尽量以 Domain Object 作为主要输入。

例如:

$repository->save(
    $individual
);

而不是:

$repository->save(
    array(
        'name' => 'Robot A',
        'state' => 'running'
    )
);

因为数组只表示数据:

Array=DataArray=Data

而 Domain Object 表示领域对象:

DomainObject=Identity+State+Behavior+RuleDomainObject=Identity+State+Behavior+Rule

因此:

RepositoryInput=DomainObject\boxed{ RepositoryInput=DomainObject }

能够保持持久化层与领域层之间的正确关系。


242B.13 Identity作为查询输入

查询对象时通常不需要整个 Domain Object。

例如:

$repository->find(1001);

其中:

1001=Identity1001=Identity

所以:

FindInput=IdentityFindInput=Identity

而:

SaveInput=DomainObjectSaveInput=DomainObject

这两个接口的输入语义不同。

因此不能为了形式统一而强行要求所有 Repository 方法都接受相同参数类型。

真正需要统一的是:

SemanticContractSemanticContract

而不是机械地统一所有参数。


242B.14 查询结果语义

find() 必须明确规定结果。

定义:

Find(id)={DomainObjectObjectExistsnullObjectNotFoundExceptionPersistenceFailureFind(id)= \begin{cases} DomainObject & ObjectExists\\ null & ObjectNotFound\\ Exception & PersistenceFailure \end{cases}

因此有三个状态:

找到
↓
DomainObject

没有找到
↓
null

持久化失败
↓
PersistenceException

这三种状态不能混在一起。


242B.15 NotFound语义

没有找到对象是一种正常的数据状态。

例如:

$object =
    $repository->find(99999);

如果数据库中不存在:

id = 99999

则:

null

可以表示:

ObjectNotFoundObjectNotFound

而不是:

throw new Exception();

这样 Service 才能够根据实际业务决定:

对象不存在
↓
创建
↓
返回业务提示
↓
或者结束当前业务

242B.16 PersistenceException语义

如果数据库发生异常:

连接失败
SQL执行失败
权限错误
事务提交失败
数据库不可用

则属于:

PersistenceExceptionPersistenceException

例如:

class PersistenceException
    extends Exception
{
}

这样可以形成:

NotFoundNotFound

与:

PersistenceFailurePersistenceFailure

的明确区别。


242B.17 BusinessException与PersistenceException

ICAI 系统需要区分:

BusinessExceptionBusinessException

和:

PersistenceExceptionPersistenceException

例如:

个体不存在

可能属于业务状态。

而:

MySQL连接失败

属于持久化系统异常。

因此:

BusinessException≠PersistenceException\boxed{ BusinessException\neq PersistenceException }

业务层不应该把数据库故障误认为业务条件不满足。


242B.18 PersistenceResult

对于 create()save()update()delete() 等写操作,可以建立统一的结果对象。

例如:

class PersistenceResult
{
    protected $success;
    protected $affectedRows;
    protected $id;
    protected $message;

    public function __construct(
        $success,
        $affectedRows = 0,
        $id = null,
        $message = ''
    ) {
        $this->success =
            $success;

        $this->affectedRows =
            $affectedRows;

        $this->id = $id;

        $this->message =
            $message;
    }

    public function isSuccess()
    {
        return $this->success;
    }

    public function getAffectedRows()
    {
        return $this->affectedRows;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getMessage()
    {
        return $this->message;
    }
}

于是:

WriteOperation→PersistenceResultWriteOperation \rightarrow PersistenceResult

不同 Repository 可以共享这种结果语义。


242B.19 Create与Save的语义边界

CreateSave 不能简单视为同一个方法。

Create 强调:

New→PersistentNew \rightarrow Persistent

Save 强调:

CurrentState→PersistentStateCurrentState \rightarrow PersistentState

因此:

Create

重点是:

建立一个新持久化对象。

而:

Save

重点是:

保存对象当前状态。

如果一个系统只需要简单 CRUD,可以选择只保留 save();如果需要严格区分对象生命周期,则可以明确提供 create()save()

因此:

InterfaceSemanticInterfaceSemantic

必须根据 ICAI 的对象生命周期模型确定,而不能机械复制数据库 CRUD。


242B.20 Save与Update的语义边界

同样:

Save≠UpdateSave\neq Update

Update 明确表示:

ExistingObject→NewStateExistingObject \rightarrow NewState

Save 可以表示:

Object→PersistCurrentStateObject \rightarrow PersistCurrentState

因此:

Save

可以是更高层的持久化动作。

而:

Update

是明确的已有对象更新动作。


242B.21 Repository接口与数据库实现

统一接口:

RepositoryInterface

具体实现:

MySQLRepository

形成:

RepositoryInterface←MySQLRepositoryRepositoryInterface \leftarrow MySQLRepository

例如:

class IndividualRepository
    implements RepositoryInterface
{
    protected $pdo;

    public function __construct(PDO $pdo)
    {
        $this->pdo = $pdo;
    }

    public function create($object)
    {
        // INSERT
    }

    public function find($id)
    {
        // SELECT
    }

    public function save($object)
    {
        // SAVE
    }

    public function update($object)
    {
        // UPDATE
    }

    public function delete($id)
    {
        // DELETE
    }
}

这样:

Interface≠ImplementationInterface \neq Implementation


242B.22 不同Repository统一接口

例如:

IndividualRepository
GoalRepository
CapabilityRepository
MemoryRepository
BehaviorRepository
RiskRepository

都可以遵循统一接口。

形成:

                RepositoryInterface
                       ↓
       ┌───────────────┼───────────────┐
       ↓               ↓               ↓
Individual          Goal            Memory
Repository        Repository       Repository
       ↓               ↓               ↓
       └────────────── MySQL ──────────┘

不同 Repository 的领域对象不同,但基础持久化语义保持一致。


242B.23 Domain Object与Repository边界

必须保持:

DomainObject≠Repository\boxed{ DomainObject\neq Repository }

Domain Object 表示:

领域中的对象。

Repository 表示:

对象如何进入和离开持久化系统。

例如:

Individual

负责表达:

ID
Type
State
Attribute
Relation

而:

IndividualRepository

负责:

Find
Create
Save
Update
Delete

因此:

DomainObject=DomainRepresentationDomainObject=DomainRepresentation Repository=PersistenceAccessRepository=PersistenceAccess


242B.24 Repository与Engine边界

同样:

Engine≠Repository\boxed{ Engine\neq Repository }

Engine 负责:

CalculationCalculation

Repository 负责:

PersistencePersistence

因此:

Engine
↓
计算对象状态
↓
Domain Object
↓
Repository
↓
MySQL

而不是:

Engine
↓
SQL
↓
MySQL

这保证领域计算与数据库实现分离。


242B.25 Repository与Service边界

Service 负责业务流程:

Service=BusinessFlowService=BusinessFlow

Repository 负责持久化:

Repository=PersistenceRepository=Persistence

因此:

Service
↓
Repository Interface
↓
Repository

例如:

public function updateState(
    $id,
    $state
) {
    $individual =
        $this->repository->find($id);

    if ($individual === null) {
        return null;
    }

    $individual->setState($state);

    return $this->repository
        ->update($individual);
}

Service 不需要知道:

SELECT
UPDATE
PDO
MySQL

242B.26 Repository事务接口语义

当一次业务操作需要修改多个对象时,需要事务。

可以定义:

Transaction=Begin+Commit+RollbackTransaction= Begin+Commit+Rollback

例如:

Begin
↓
Repository A
↓
Repository B
↓
Repository C
↓
Commit

发生错误:

Begin
↓
Repository A
↓
Repository B
↓
Error
↓
Rollback

事务的目的不是统一 Repository 方法,而是统一:

PersistenceConsistencyPersistenceConsistency


242B.27 事务与Service边界

一次完整业务可能调用多个 Repository:

Service
↓
Begin
├── IndividualRepository
├── GoalRepository
├── MemoryRepository
└── BehaviorRepository
↓
Commit

因此业务事务通常由 Service 组织。

原因是:

Service=BusinessTransactionService=BusinessTransaction

而:

Repository=PersistenceOperationRepository=PersistenceOperation

Repository 不应该自行决定整个业务流程何时提交或回滚。


242B.28 持久化接口与对象状态

Domain Object 在内存中的状态:

StateObjectState_{Object}

数据库中的状态:

StateDatabaseState_{Database}

对象发生变化后:

StateObject,t→StateObject,t+1State_{Object,t} \rightarrow State_{Object,t+1}

再通过:

RepositoryRepository

完成:

StateDatabase,t→StateDatabase,t+1State_{Database,t} \rightarrow State_{Database,t+1}

因此:

ObjectChange→Persistence→SynchronizationObjectChange \rightarrow Persistence \rightarrow Synchronization


242B.29 ICAI记忆对象的统一持久化

ICAI 的 Memory 同样遵循统一接口。

例如:

$memoryRepository->find($id);

$memoryRepository->save($memory);

$memoryRepository->update($memory);

$memoryRepository->delete($id);

因此:

MemoryObject→MemoryRepository→MySQLMemoryObject \rightarrow MemoryRepository \rightarrow MySQL

知识、经验、行为、目标等对象也可以采用相同持久化语义。

例如:

Knowledge→KnowledgeRepositoryKnowledge \rightarrow KnowledgeRepository Experience→ExperienceRepositoryExperience \rightarrow ExperienceRepository Behavior→BehaviorRepositoryBehavior \rightarrow BehaviorRepository


242B.30 ICAI统一持久化模型

综合前面的定义:

UnifiedPersistence=Interface+DomainObject+Repository+Result+Exception+Transaction\boxed{ UnifiedPersistence= Interface+ DomainObject+ Repository+ Result+ Exception+ Transaction }

其运行结构为:

Domain Object
↓
Repository Interface
↓
Repository Implementation
↓
Persistence
↓
MySQL

查询方向:

MySQL
↓
Repository
↓
Domain Object

写入方向:

Domain Object
↓
Repository
↓
MySQL

242B.31 与第242章的关系

第242章解决的是:

Repository→MySQL\boxed{ Repository\rightarrow MySQL }

重点是:

  • 数据查询;
  • 数据保存;
  • 数据更新;
  • 数据删除;
  • PDO;
  • MySQL;
  • 数据映射;
  • 持久化状态。

本章解决的是:

RepositoryInterface→Repository\boxed{ RepositoryInterface\rightarrow Repository }

重点是:

  • 接口;
  • 方法语义;
  • 输入语义;
  • 输出语义;
  • 空结果;
  • 异常;
  • 持久化结果;
  • 事务语义。

因此两者不是重复关系。

完整关系为:

RepositoryInterface→Repository→MySQLRepositoryInterface \rightarrow Repository \rightarrow MySQL


242B.32 ICAI完整持久化链

经过第242章和第242B章,完整结构成为:

Controller
↓
Service
↓
Engine
↓
Domain Object
↓
Repository Interface
↓
Repository
↓
PDO
↓
MySQL

查询时:

MySQL
↓
PDO
↓
Repository
↓
Domain Object
↓
Engine
↓
Service
↓
Controller

因此:

Request→Controller→Service→Engine→DomainObject→RepositoryInterface→Repository→MySQL\boxed{ Request \rightarrow Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow RepositoryInterface \rightarrow Repository \rightarrow MySQL }


242B.33 统一接口的工程意义

统一持久化接口使 ICAI 获得以下能力。

第一,降低调用复杂度

不同 Repository 使用统一基本语义:

Find/Save/Update/DeleteFind/Save/Update/Delete

第二,隔离数据库实现

Service⊥MySQLService \perp MySQL

第三,统一错误处理

NotFoundNotFound

与:

PersistenceExceptionPersistenceException

明确区分。

第四,统一结果结构

PersistenceResultPersistenceResult

第五,支持 Repository 替换

Interface→ImplementationInterface \rightarrow Implementation

第六,支持 ICAI 大量 Domain Object 的统一持久化

Individual→RepositoryIndividual \rightarrow Repository Memory→RepositoryMemory \rightarrow Repository Goal→RepositoryGoal \rightarrow Repository Behavior→RepositoryBehavior \rightarrow Repository


242B.34 统一持久化层最终模型

最终可以建立:

PersistenceLayer=Interface+Repository+Mapping+Result+Exception+Transaction+Storage\boxed{ PersistenceLayer= Interface+ Repository+ Mapping+ Result+ Exception+ Transaction+ Storage }

完整关系:

DomainObject→RepositoryInterface→Repository→PDO→MySQL\boxed{ DomainObject \rightarrow RepositoryInterface \rightarrow Repository \rightarrow PDO \rightarrow MySQL }

其中:

Create=建立新的持久化对象Create=\text{建立新的持久化对象} Find=查找已有对象Find=\text{查找已有对象} Save=保存对象当前状态Save=\text{保存对象当前状态} Update=更新已有对象Update=\text{更新已有对象} Delete=删除持久化记录Delete=\text{删除持久化记录}

查询结果:

Find→DomainObject/nullFind\rightarrow DomainObject/null

写操作:

Write→PersistenceResultWrite\rightarrow PersistenceResult

异常:

PersistenceFailure→PersistenceExceptionPersistenceFailure\rightarrow PersistenceException

事务:

Begin→Operation→Commit/RollbackBegin\rightarrow Operation\rightarrow Commit/Rollback


242B.35 本章总结

第242章建立了:

Repository→MySQLRepository\rightarrow MySQL

本章进一步建立:

RepositoryInterface→Repository\boxed{ RepositoryInterface\rightarrow Repository }

二者共同形成:

DomainObject→RepositoryInterface→Repository→MySQL\boxed{ DomainObject \rightarrow RepositoryInterface \rightarrow Repository \rightarrow MySQL }

统一持久化层的核心并不是要求所有 Repository 使用完全相同的数据库结构,而是要求相同的持久化行为具有稳定、明确、可预测的接口语义。

因此形成:

Create+Find+Save+Update+Delete\boxed{ Create+ Find+ Save+ Update+ Delete }

同时明确:

Repository≠MySQLRepository\neq MySQL DomainObject≠DatabaseRecordDomainObject\neq DatabaseRecord Engine≠RepositoryEngine\neq Repository Service≠RepositoryService\neq Repository Delete≠DestroyDelete\neq Destroy NotFound≠PersistenceExceptionNotFound\neq PersistenceException

最终,ICAI 的工程链从:

Controller→Service→Engine→DomainObject→Repository→MySQLController \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow Repository \rightarrow MySQL

进一步规范为:

Controller→Service→Engine→DomainObject→RepositoryInterface→Repository→Persistence→MySQL\boxed{ Controller \rightarrow Service \rightarrow Engine \rightarrow DomainObject \rightarrow RepositoryInterface \rightarrow Repository \rightarrow Persistence \rightarrow MySQL }

由此,持久化层不再只是“访问数据库的 PHP 类”,而成为 ICAI 领域对象与长期数据存储之间具有统一接口、统一语义、统一结果和统一异常边界的独立工程层。

这为后续第243章继续建立新的 ICAI 工程关系提供统一的持久化基础。

Leave a Reply

Your email address will not be published. Required fields are marked *