mirror of
https://github.com/zhamao-robot/zhamao-framework.git
synced 2026-07-21 07:35:34 +08:00
change ALL docs from MkDocs to VuePress!!
This commit is contained in:
@@ -16,10 +16,11 @@ $config['init_atomics'] = [
|
||||
|
||||
这时我们就成功初始化两个原子计数器,名字分别为 `foo` 和 `bar`。
|
||||
|
||||
!!! warning "注意"
|
||||
::: warning 注意
|
||||
|
||||
初始化的值必须是不小于 0 的 int32 值!
|
||||
初始化的值必须是不小于 0 的 int32 值!
|
||||
|
||||
:::
|
||||
|
||||
## 使用
|
||||
|
||||
@@ -59,7 +60,8 @@ class Hello {
|
||||
|
||||
设置计数的数字:`ZMAtomic::get("bar")->set(77);`
|
||||
|
||||
!!! note "提示"
|
||||
::: tip 提示
|
||||
|
||||
还有一些不常用的方法,可以看 Swoole 官方的文档,这里就不一一列举了。
|
||||
还有一些不常用的方法,可以看 Swoole 官方的文档,这里就不一一列举了。
|
||||
|
||||
:::
|
||||
|
||||
@@ -101,7 +101,8 @@ $r = file_get_contents(working_dir() . "/composer.json");
|
||||
file_put_contents("/tmp/test.txt", "hello world");
|
||||
```
|
||||
|
||||
!!! warning "注意"
|
||||
::: warning 注意
|
||||
|
||||
在默认的情况里,框架的根目录均为可写可读的,在读写文件时务必要注意目录的位置和权限。使用 `working_dir()` 获取目录后面需要加 `/` 再追加自己的文件名或子目录名。
|
||||
在默认的情况里,框架的根目录均为可写可读的,在读写文件时务必要注意目录的位置和权限。使用 `working_dir()` 获取目录后面需要加 `/` 再追加自己的文件名或子目录名。
|
||||
|
||||
:::
|
||||
|
||||
@@ -81,14 +81,14 @@ public function storeAfterRemove() {
|
||||
}
|
||||
```
|
||||
|
||||
<chat-box>
|
||||
) store
|
||||
( OK!
|
||||
) storeAfterRemove
|
||||
( 内容存在!
|
||||
^ 等待 30 秒
|
||||
( 内容不存在!
|
||||
</chat-box>
|
||||
<chat-box :my-chats="[
|
||||
{type:0,content:'store'},
|
||||
{type:1,content:'OK!'},
|
||||
{type:0,content:'storeAfterRemove'},
|
||||
{type:1,content:'内容存在!'},
|
||||
{type:2,content:'等待 30 秒'},
|
||||
{type:1,content:'内容不存在!'},
|
||||
]"></chat-box>
|
||||
|
||||
### LightCache::update()
|
||||
|
||||
@@ -218,14 +218,14 @@ public function getStore() {
|
||||
}
|
||||
```
|
||||
|
||||
<chat-box>
|
||||
^ 我在 2021-01-05 15:21:00 发送这条消息
|
||||
) getStore
|
||||
( 2021-01-05 15:20:00
|
||||
^ 这时我用 Ctrl+C 停止框架,过一会儿再启动
|
||||
) getStore
|
||||
( 存储时间:2021-01-05 15:20:00
|
||||
</chat-box>
|
||||
<chat-box :my-chats="[
|
||||
{type:2,content:'我在 2021-01-05 15:21:00 发送这条消息'},
|
||||
{type:0,content:'getStore'},
|
||||
{type:1,content:'2021-01-05 15:20:00'},
|
||||
{type:2,content:'这时我用 Ctrl+C 停止框架,过一会儿再启动'},
|
||||
{type:0,content:'getStore'},
|
||||
{type:1,content:'存储时间:2021-01-05 15:20:00'},
|
||||
]"></chat-box>
|
||||
|
||||
### 数据加锁
|
||||
|
||||
@@ -250,10 +250,11 @@ public function test() {
|
||||
|
||||
在运行完测试后,通过 `LightCache::get("web_count")`,获取到的数你会发现不是 200000。怎么回事呢?请自行翻阅多进程开发相关的书籍哦!(或者简单理解为,有一些情况下,进程 1 执行到了 `if-else` 语句,另一个进程也执行到了这里,两次在代码层面加的数是相同的,则虽然请求了两次,但是后执行 set 的那个进程又覆盖了前一个进程执行的值,导致最终结果加了 1 而不是 2)
|
||||
|
||||
!!! note "提示"
|
||||
::: tip 提示
|
||||
|
||||
同样的场景,使用 ZMAtomic 就不需要使用锁了。Atomic 是一句话:`add(1)` 立即加值的。而 LightCache 需要加锁的情况一般都是 `get->改值->set` 这样的代码。
|
||||
同样的场景,使用 ZMAtomic 就不需要使用锁了。Atomic 是一句话:`add(1)` 立即加值的。而 LightCache 需要加锁的情况一般都是 `get->改值->set` 这样的代码。
|
||||
|
||||
:::
|
||||
|
||||
解决这一问题,就需要用到锁。这种情况下,我们首先考虑的是自旋锁,框架也因此内置了一个方便使用的自旋锁组件。详见下一章:自旋锁。
|
||||
|
||||
@@ -271,13 +272,13 @@ public function test() {
|
||||
|
||||
### WorkerCache 跨进程大缓存
|
||||
|
||||
WorkerCache 和 LightCache 几乎完全不同,WorkerCache 存储的方式说白了就是 PHP 的静态变量,不过框架支持使用封装好的进程间通信进行跨进程读取。但由于需要设置一个存储变量的进程,所以配置文件必须先指定要将数据存到哪个 Worker/TaskWorker 进程中。关于框架内多进程的说明,请见 [进阶 - 多进程 Hack](/advanced/multi-process/)。
|
||||
WorkerCache 和 LightCache 几乎完全不同,WorkerCache 存储的方式说白了就是 PHP 的静态变量,不过框架支持使用封装好的进程间通信进行跨进程读取。但由于需要设置一个存储变量的进程,所以配置文件必须先指定要将数据存到哪个 Worker/TaskWorker 进程中。关于框架内多进程的说明,请见 [进阶 - 多进程 Hack](/advanced/multi-process)。
|
||||
|
||||
定义:`ZM\Store\WorkerCache`。
|
||||
|
||||
#### 配置
|
||||
|
||||
见 [基本配置](/guide/basic-config/)。
|
||||
见 [基本配置](/guide/basic-config)。
|
||||
|
||||
#### WorkerCache::get()
|
||||
|
||||
@@ -342,12 +343,11 @@ class Hello {
|
||||
}
|
||||
```
|
||||
|
||||
<chat-box>
|
||||
) set_store hello world
|
||||
( 成功!
|
||||
) get_store hello
|
||||
( world
|
||||
) get_store foo
|
||||
( 内容不存在!
|
||||
</chat-box>
|
||||
|
||||
<chat-box :my-chats="[
|
||||
{type:0,content:'set_store hello world'},
|
||||
{type:1,content:'成功!'},
|
||||
{type:0,content:'get_store hello'},
|
||||
{type:1,content:'world'},
|
||||
{type:0,content:'get_store foo'},
|
||||
{type:1,content:'内容不存在!'},
|
||||
]"></chat-box>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# MySQL 数据库(旧版组件)
|
||||
|
||||
!!! warning "注意"
|
||||
::: warning 注意
|
||||
|
||||
此 MySQL 组件为旧版 MySQL 查询器组件,为了统一和提升对未来独立组件的兼容性,现转变为使用 `doctrine/dbal` 和 `doctrine/orm` 库来实现查询器,请转到 [MySQL 查询器]()。
|
||||
此 MySQL 组件为旧版 MySQL 查询器组件,为了统一和提升对未来独立组件的兼容性,现转变为使用 `doctrine/dbal` 和 `doctrine/orm` 库来实现查询器,请转到 [MySQL 查询器]()。
|
||||
|
||||
:::
|
||||
|
||||
## 配置
|
||||
|
||||
@@ -78,8 +80,6 @@ DB::table("admin")->where("name", "fake_admin")->count();
|
||||
//SELECT count(*) FROM admin WHERE name = 'fake_admin'
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 直接执行 SQL
|
||||
|
||||
> 在查询器外执行的 SQL 语句都不会被缓存,都是一定会请求数据库的。
|
||||
@@ -98,4 +98,4 @@ $r = DB::rawQuery("SELECT * FROM admin WHERE name = ?", ["fake_admin"]);
|
||||
echo $r[0]["password"];
|
||||
```
|
||||
|
||||
> 参数查询已经从根本上杜绝了 SQL 注入的问题。
|
||||
> 参数查询已经从根本上杜绝了 SQL 注入的问题。
|
||||
|
||||
3
docs/component/store/mysql-statement.md
Normal file
3
docs/component/store/mysql-statement.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# MySQLStatement
|
||||
|
||||
你好啊,这里是 Statement。TODO
|
||||
@@ -1,4 +1,27 @@
|
||||
# 执行 SQL 语句
|
||||
# MySQL 数据库
|
||||
|
||||
## 简介
|
||||
|
||||
炸毛框架的数据库组件对接了 MySQL 连接池,在使用过程中无需配置即可实现 MySQL 查询,同时拥有高并发。
|
||||
|
||||
目前 2.5 版本后炸毛框架底层采用了 `doctrine/dbal` 组件,可以方便地构建 SQL 语句。
|
||||
|
||||
本章大体查询内容均以下表 `users` 为基础:
|
||||
|
||||
| id | username | gender | update_time |
|
||||
| -- | -------- | ------ | ----------- |
|
||||
| 1 | jack | man | 2021-10-12 |
|
||||
| 2 | rose | woman | 2021-10-11 |
|
||||
|
||||
## 配置
|
||||
|
||||
炸毛框架的数据库组件支持原生 SQL、查询构造器,去掉了复杂的对象模型关联,同时默认为数据库连接池,使开发变得简单。
|
||||
|
||||
数据库的配置位于 `config/global.php` 文件的 `mysql_config` 段,见 [全局配置](../../../../guide/basic-config#mysql_config)。
|
||||
|
||||
如果 `mysql_config.host` 字段为空,则不创建数据库连接池,填写后将创建,且默认保持长连接。
|
||||
|
||||
## 执行 SQL 语句
|
||||
|
||||
在一开始,无论你做什么数据库操作,均需要获取一个 `\ZM\MySQL\MySQLWrapper` 作为你的操作对象。
|
||||
|
||||
@@ -7,11 +30,13 @@
|
||||
$wrapper = \ZM\MySQL\MySQLManager::getWrapper();
|
||||
```
|
||||
|
||||
!!! tip "提示"
|
||||
::: tip 提示
|
||||
|
||||
这部分内容部分直接取自 [DBAL - Data Retrieval And Manipulation](https://www.doctrine-project.org/projects/doctrine-dbal/en/2.13/reference/data-retrieval-and-manipulation.html) 原文并直接翻译,如有实际不同请提交 Issue 反馈。
|
||||
这部分内容部分直接取自 [DBAL - Data Retrieval And Manipulation](https://www.doctrine-project.org/projects/doctrine-dbal/en/2.13/reference/data-retrieval-and-manipulation.html) 原文并直接翻译,如有实际不同请提交 Issue 反馈。
|
||||
|
||||
## 执行预处理 SQL 语句
|
||||
:::
|
||||
|
||||
### 执行预处理 SQL 语句
|
||||
|
||||
预处理查询很巧妙地解决了 SQL 注入问题,并且可以方便地绑定参数进行查询。
|
||||
|
||||
@@ -27,7 +52,7 @@ $stmt->bindValue(2, "jack");
|
||||
$resultSet = $stmt->executeQuery();
|
||||
```
|
||||
|
||||
其中 `$resultSet` 与 `Statement` 方法相似,此处的对象可能是 [数据库语句对象](../mysql-statement) 或 数据库结果对象(结果对象与语句对象的 `fetchXXX()` 部分一致)。
|
||||
其中 `$resultSet` 与 `Statement` 方法相似,此处的对象可能是 [数据库语句对象](./mysql-statement) 或 数据库结果对象(结果对象与语句对象的 `fetchXXX()` 部分一致)。
|
||||
|
||||
这里也可以使用命名标签,使用标签可以给相同参数处使用同一个标签:
|
||||
|
||||
@@ -38,7 +63,7 @@ $stmt->bindValue("name", "jack");
|
||||
$resultSet = $stmt->executeQuery();
|
||||
```
|
||||
|
||||
## 执行常规语句
|
||||
### 执行常规语句
|
||||
|
||||
执行常规语句为 `statement` 方式执行,此方法执行后只返回影响的行数,而不返回结果,适用于 `UPDATE` 等语句。
|
||||
|
||||
@@ -48,7 +73,7 @@ $count = $wrapper->executeStatement('UPDATE users SET username = ? WHERE id = ?'
|
||||
echo $count; // 1
|
||||
```
|
||||
|
||||
## 执行查询语句
|
||||
### 执行查询语句
|
||||
|
||||
为给定的 SQL 创建一个准备好的语句并将参数传递给 executeQuery 方法,然后返回结果集。此方法为上述的「预处理查询语句」的简化版,可直接在第二个参数使用 array 插入绑定参数执行。
|
||||
|
||||
@@ -68,7 +93,7 @@ array(
|
||||
*/
|
||||
```
|
||||
|
||||
### fetchAllAssociative()
|
||||
#### fetchAllAssociative()
|
||||
|
||||
执行查询并将所有结果返回一个数组中。
|
||||
|
||||
@@ -79,7 +104,7 @@ $resultSet = $wrapper->fetchAllAssociative('SELECT * FROM user WHERE username =
|
||||
// 结果同 executeQuery()->fetchAllAssociative() 中 $user 的值。
|
||||
```
|
||||
|
||||
### fetchAllKeyValue()
|
||||
#### fetchAllKeyValue()
|
||||
|
||||
执行查询并将前两列分别作为键和值提取到关联数组中。
|
||||
|
||||
@@ -93,7 +118,7 @@ array(
|
||||
*/
|
||||
```
|
||||
|
||||
### fetchAllAssociativeIndexed()
|
||||
#### fetchAllAssociativeIndexed()
|
||||
|
||||
执行查询并将数据作为关联数组获取,其中键代表第一列,值是其余列及其值的关联数组。
|
||||
|
||||
@@ -111,7 +136,7 @@ array(
|
||||
*/
|
||||
```
|
||||
|
||||
### fetchNumeric()
|
||||
#### fetchNumeric()
|
||||
|
||||
查询并返回第一行数据,形式以数字索引方式返回每一列。
|
||||
|
||||
@@ -127,7 +152,7 @@ array(
|
||||
*/
|
||||
```
|
||||
|
||||
### fetchOne()
|
||||
#### fetchOne()
|
||||
|
||||
仅返回查询结果的第一行第一列的值。
|
||||
|
||||
@@ -136,7 +161,7 @@ $username = $wrapper->fetchOne('SELECT username FROM users WHERE id = ?', array(
|
||||
echo $username; // jack
|
||||
```
|
||||
|
||||
### fetchAssociative()
|
||||
#### fetchAssociative()
|
||||
|
||||
返回结果内第一行的关联数组形式的数据。
|
||||
|
||||
@@ -153,7 +178,7 @@ array(
|
||||
*/
|
||||
```
|
||||
|
||||
### delete()
|
||||
#### delete()
|
||||
|
||||
删除查询操作,第一个参数为表名,第二个参数为 `['列名' => '列值']`。
|
||||
|
||||
@@ -163,7 +188,7 @@ $wrapper->delete('users', array('username' => 'jack'));
|
||||
// 等同于执行DELETE FROM user WHERE username = ? ,参数列表为('jack')
|
||||
```
|
||||
|
||||
### insert()
|
||||
#### insert()
|
||||
|
||||
插入数据库一行,第一个参数为表名,第二个参数为对应数据。
|
||||
|
||||
@@ -172,7 +197,7 @@ $wrapper->insert('users', array('id' => 0, 'username' => 'jwage', 'gender' => 'w
|
||||
// INSERT INTO user (id, username, gender, update_time) VALUES (?,?,?,?) (0,jwage,woman,2021-10-17)
|
||||
```
|
||||
|
||||
### update()
|
||||
#### update()
|
||||
|
||||
更新数据库,使用给定数据更新匹配键值标识符的所有行。
|
||||
|
||||
@@ -181,4 +206,3 @@ $wrapper->insert('users', array('id' => 0, 'username' => 'jwage', 'gender' => 'w
|
||||
$wrapper->update('user', array('username' => 'jwage'), array('id' => 1));
|
||||
// UPDATE user (username) VALUES (?) WHERE id = ? (jwage, 1)
|
||||
```
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
# 配置
|
||||
|
||||
炸毛框架的数据库组件支持原生 SQL、查询构造器,去掉了复杂的对象模型关联,同时默认为数据库连接池,使开发变得简单。
|
||||
|
||||
数据库的配置位于 `config/global.php` 文件的 `mysql_config` 段,见 [全局配置](../../../../guide/basic-config#mysql_config)。
|
||||
|
||||
如果 `mysql_config.host` 字段为空,则不创建数据库连接池,填写后将创建,且默认保持长连接。
|
||||
@@ -1 +0,0 @@
|
||||
你好啊,这里是 Statement。
|
||||
@@ -1,14 +0,0 @@
|
||||
# MySQL 数据库简介
|
||||
|
||||
炸毛框架的数据库组件对接了 MySQL 连接池,在使用过程中无需配置即可实现 MySQL 查询,同时拥有高并发。
|
||||
|
||||
目前 2.5 版本后炸毛框架底层采用了 `doctrine/dbal` 组件,可以方便地构建 SQL 语句。
|
||||
|
||||
本章大体查询内容均以下表 `users` 为基础:
|
||||
|
||||
| id | username | gender | update_time |
|
||||
| -- | -------- | ------ | ----------- |
|
||||
| 1 | jack | man | 2021-10-12 |
|
||||
| 2 | rose | woman | 2021-10-11 |
|
||||
|
||||
#
|
||||
@@ -59,4 +59,4 @@ ZMRedis::call(function($redis) {
|
||||
|
||||
选一个喜欢的就好。硬要是说区别的话,对象模式是在 PHP 自动回收这个 `ZMRedis` 对象时会归还连接,也可以通过手动 `unset($obj)` 进行回收,否则就会执行到函数结尾自动回收。切记不可将 `$obj` 对象持久化存到静态或全局变量等。
|
||||
|
||||
回调模式看似是回调,但是是同步执行的,不会发生顺序错乱。也就是说到了 `ZMRedis::call()` 方法里面的时候,后面的代码不会提前执行,是顺序执行的。回调的作用仅仅是用作自动回收连接对象。
|
||||
回调模式看似是回调,但是是同步执行的,不会发生顺序错乱。也就是说到了 `ZMRedis::call()` 方法里面的时候,后面的代码不会提前执行,是顺序执行的。回调的作用仅仅是用作自动回收连接对象。
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
|
||||
前面讲到 LightCache 轻量缓存在特定的情况下为了保证数据不被多进程的因素导致丢失或覆盖,在高并发情况下修改数据需要加锁,所以炸毛框架内置了 SpinLock 自旋锁。
|
||||
|
||||
!!! tip "提示"
|
||||
::: tip 提示
|
||||
|
||||
框架单进程运行的模式下不需要任何自旋锁。
|
||||
框架单进程运行的模式下不需要任何自旋锁。
|
||||
|
||||
:::
|
||||
|
||||
## 配置
|
||||
|
||||
@@ -61,9 +63,11 @@ public function test() {
|
||||
|
||||
原理剖析:在 LightCache 获取前,先对此内容上锁,这时如果其他进程有同时也在执行这个代码的时候,就会在 `SpinLock::lock()` 这行代码处原地等待,防止继续执行。等前面的那个进程执行到 `SpinLock::unlock()` 释放锁时,其他进程才可继续执行,从而避免了多个进程并行执行这段代码导致的数据错乱。
|
||||
|
||||
!!! error "警告"
|
||||
::: danger 警告
|
||||
|
||||
使用锁时务必谨慎,如果不按照下面的规则使用自旋锁可能导致 CPU 占用率上升。
|
||||
使用锁时务必谨慎,如果不按照下面的规则使用自旋锁可能导致 CPU 占用率上升。
|
||||
|
||||
:::
|
||||
|
||||
自旋锁使用约定:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user