# DB Cache 理論和理解

{% hint style="danger" %}
**目前的 ProudNet DB 系統只在 Windows 上運行。**

遊戲數據庫的特點是，交易規模較小，但訪問次數較多，且大部分數據都是反覆加載和保存，ProudNet數據庫系統通過cache這一過程，減輕數據庫的負荷。
{% endhint %}

## DB Cache數據的結構

遊戲數據庫中存儲的數據以tree爲單位進行處理，該tree由node組成。

<figure><img src="/files/VMoVwNJprCvdTmWrTJHK" alt=""><figcaption><p>將用戶賬戶信息保存到DB的示例</p></figcaption></figure>

每個node具有父母、子女關係,每個node具有名稱-值對,即<mark style="color:orange;">property field</mark>。

<figure><img src="/files/AsVEyHhTl82gWXXrwzMc" alt=""><figcaption><p>用於將用戶帳戶信息存儲在DB中的表格結構</p></figcaption></figure>

加載的數據樹的最上位node root node 的 table name 和 child node 的 table name 必須不同。

## DB Cache 資料存取類型

DB cache的基本使用方法是獨家加載和處理數據，ProudNet DB系統提供以下類型的訪問。

<table data-full-width="true"><thead><tr><th width="153">訪問類型</th><th>應用示例</th><th width="119">Cache 與否</th><th width="107">即時回調</th><th width="191">是否需要專有加載</th><th>內部處理方式</th></tr></thead><tbody><tr><td>單方面更改數據</td><td>遊戲過程中玩家角色資訊頻繁更改</td><td>YES</td><td>YES</td><td>YES</td><td>先向存儲器緩存，然後向DB緩存write</td></tr><tr><td>更改請求響應數據</td><td>創建一個具有唯一名稱的玩家角色</td><td>NO</td><td>NO</td><td>YES</td><td>寫入DB後如果成功則緩存在記憶體中</td></tr><tr><td>存取非專有數據</td><td>從網頁伺服器購買付費物品</td><td>NO</td><td>NO</td><td>NO</td><td>寫入DB後如果成功則緩存在記憶體中</td></tr></tbody></table>

### - 壟斷加載

爲了避免[**競爭狀態**](/proudnet.cn/proudnet-note/dictionary.md#race-condition),DB cache系統只允許將相同的數據加載到1個DB cache client上,這被稱爲<mark style="color:orange;">壟斷加載(exclusive load)</mark>。<br>

DB Cache System在已經有一個DB Cache Client獨佔時，如果新的DB Cache Client提出獨佔請求，以前的DB Cache Client就會收到轉讓獨佔權的請求，並且可以接受或拒絕。 此時,如果以前的DB Cache Client將數據Unload,新的DB Cache Client將獲得壟斷權。

<figure><img src="/files/IVqwvUs5b8iF22cbjnRh" alt=""><figcaption><p>Server 1 擁有的 Gamer X 是由 Server 2 壟斷裝入的狀態</p></figcaption></figure>

#### (1) 單方面更改數據

<figure><img src="/files/GIESTa6O2rVcyeBFKIlp" alt=""><figcaption></figcaption></figure>

進行<mark style="color:orange;">單方面數據更改</mark>時，數據會立即反映到DB緩存的內存中，這種更改過一段時間後，在數據庫中進行實際記錄，即數據緩存。 由於<mark style="color:orange;">單方面數據更改</mark>處理會立即返回，因此在更改數據的例程中不會出現等待時間。 因此，無需在數據變更後等待結果完成的過程。<br>

不需要像下面的例程那樣<mark style="color:orange;">unlock then lock</mark>過程。

```cpp
UpdateSomeData()
{
    lock(X);
    ...
    unlock(X);
    UnilateralUpdateSomeData(X);
    lock(X);
    ...
    unlock(X);
}
```

{% hint style="info" %} <mark style="color:orange;">單方面數據更改</mark>無條件地應用於DB cache的內存，但更改可能無法反映在數據庫中設置<mark style="color:orange;">DB Constraints</mark>的記錄中。

因此，即使未設置或設置了 <mark style="color:orange;">DB Constraints</mark>，也建議在確定的情況下使用它。 在通常的網絡遊戲中,關於玩家和世界地區客體的數據庫客體可以安全地使用<mark style="color:orange;">單方面數據更改</mark>。
{% endhint %}

#### (2) 更改請求響應數據

<mark style="color:orange;">請求響應型數據變更</mark>是請求響應型,與<mark style="color:orange;">單方面數據更改</mark>相反。 DB cache client向DB cache server要求<mark style="color:orange;">請求響應型數據變更</mark>，並將其實際記錄在數據庫中，通過DB cache client確認記錄成功與否。

<figure><img src="/files/DHlVAqdg2Zmbx7qhPnQZ" alt=""><figcaption></figcaption></figure>

<mark style="color:orange;">請求響應型數據變更</mark>並不是真正的cache，但更改不會反映在 DB cache 中，直到實際記錄成功，從而減少由於 [**DB Constraints**](/proudnet.cn/proudnet-note/dictionary.md#db-constraints) 導致記錄失敗的機率。 當<mark style="color:orange;">請求響應型數據變更</mark>通常用於在網路遊戲中建立玩家角色時，這會禁止重名。

#### (3) 存取非專有數據

<mark style="color:orange;">單方面數據更改</mark>和<mark style="color:orange;">請求響應型數據變更</mark>僅限於獨家加載的數據。

但是，有時您想要讀取或寫入已經在其他 DB 緩存中獨家加載的數據。 在網絡服務器上閱覽播放器角色的信息,或者在付費道具結算服務器上向播放器角色的包中添加或變更道具時,也有需要閱覽或變更正在運營工具上登錄的播放器的角色信息的情況。

<mark style="color:orange;">存取非專有數據</mark>是用於此的功能。

所有<mark style="color:orange;">存取非專有數據</mark>都對DBConstraints具有抗性，儘管它們不是立即響應的，因爲它們以<mark style="color:orange;">請求響應型數據變更</mark>的方式運行。 另外，如果非壟斷性地更改數據，則進行壟斷加載的DB cache client會收到數據被其他地方更改的通知。

<figure><img src="/files/kijaEkGsEgYnaRlHFNss" alt=""><figcaption></figcaption></figure>

## DB直接存取DB cache處理的數據

由DB快取載入和處理的資料樹的資料狀態保持比DB中的資料狀態更新的狀態。\
這是因為資料先記錄在DB快取中，然後再記錄在DB中。

因此，如果使用者將資料與資料庫快取處理的資料樹分開直接記錄在資料庫中，則可能會出現不必要的錯誤，因為資料庫中的資料暫時過時。

這和<mark style="color:orange;">data race condition</mark>是類似的問題。

<figure><img src="/files/fpUs3D8Cwo1zLD74knCN" alt=""><figcaption><p>Data race condition by DB cache vs. DB access</p></figcaption></figure>

ProudNet在DB中想要直接操作DB cache處理的data tree時,爲了避免<mark style="color:orange;">data race condition</mark>,提供<mark style="color:orange;">數據隔離功能(data isolation)</mark>,即使直接訪問DB,也不會發生<mark style="color:orange;">data race condition</mark>,完全解除用戶想要的data tree的使用權。

<figure><img src="/files/kN27QJjHv6o7LNiZH2EM" alt=""><figcaption><p>Data isolation</p></figcaption></figure>

使用方法如下。

> * 對於DB中需要直接訪問的data tree,通過<mark style="color:orange;">Proud.CDbCacheClient2.RequestIsolateData(X)</mark>呼叫,X將被隔離處理,如果X已經加載,則可以卸載。
> * <mark style="color:orange;">Proud.IDbCacheClientDelegate2.OnDeisolateDataSuccess(X)</mark>回電後，可以安全地訪問DB中的X。
> * 如果 X 是隔離的， DB 緩存不能加載 X 。
> * 完成對 X 的數據庫訪問後， 調用 <mark style="color:orange;">Proud.CDbCacheClient2.RequestDeisolateData()</mark> 方法解除隔離 。

<figure><img src="/files/QoML4ZlJWdQYF2CKwG6J" alt=""><figcaption><p>Data Isolation Usage</p></figcaption></figure>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.proudnet.com/proudnet.cn/proudnet/db_system/db_cache_ver2/theory.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
