0%

谢谢那些喜欢我的人
我从来不认为这个问题是个问题, 直到昨天.

昨天晚上的时候, 我提交了一个RFC, 关于引入finally到PHP, 实现这个功能的出发点很简单, 因为我看见不少人的需求, 另外还有就是Stas说, 一直只看到讨论, 没看到有人实现. 于是我就给实现了.

发到邮件组以后, 一个开发组的同学Nikita Popov(nikic), 表示强烈反对这个RFC, 当然最初的论点他说了很多, 最后我们在线讨论的时候, 他表达了一个他的观点:

“PHP在请求结束后会释放所有的资源, 所以我们没有必要调用fclose,或者mysql_close来释放资源, PHP会替我们做”

并且他表示, 他从来都不会调用fclose, 认为fclose的存在只是为了继承C函数族.

我很惊讶, 我也不知道还有多少人是和他一样的想法, 所以我决定写这篇文章.

在PHP5.2以前, PHP使用引用计数(Reference count)来做资源管理, 当一个zval的引用计数为0的时候, 它就会被释放. 虽然存在循环引用(Cycle reference), 但这样的设计对于开发Web脚本来说, 没什么问题, 因为Web脚本的特点和它追求的目标就是执行时间短, 不会长期运行. 对于循环引用造成的资源泄露, 会在请求结束时释放掉. 也就是说, 请求结束时释放资源, 是一种部补救措施(backup).

然而, 随着PHP被越来越多的人使用, 就有很多人在一些后台脚本使用PHP, 这些脚本的特点是长期运行, 如果存在循环引用, 导致引用计数无法及时释放不用的资源, 则这个脚本最终会内存耗尽退出.

所以在PHP5.3以后, 我们引入了GC, 也就是说, 我们引入GC是为了解决用户无法解决的问题.

这个是历史, 我简单介绍下, 现在让我们回头来看开头的问题, 是不是因为PHP会在请求结束后释放所有的资源, 于是我们就可以不用手动释放呢?

看一个例子:
Mysql最大连接数(mysql.max_connections)

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$db = mysql_connect() ;
$resut = mysql_query();
// process result...
usleep(500);

//mysql_close($db); let's say, you didn't call to this

// other logic, assuming it costs 5s
sleep(5);

exit(0); //finish

上面的例子, 我们会保持一个和Mysql的连接5秒钟, 这样的脚本对于一般的应用来说没有关系, 但是对于一个请求量很大的脚本来说, 会导致一个致命问题:

比如一个繁忙的应用, 每秒要处理来自用户的1000个请求, 那么5秒钟请求多少个? 5 * 1000 = 5000, 而Mysql有最大连接数限制(mysql.max_connections), 这个数字一般不超过2000, 默认的会更低:(mysql.max_connections),

那么, 这样代码会导致你的应用, 根本无法正常提供服务. 而如果我们在对Mysql的处理完成后就关闭这个连接, 那么就不会触发这个问题.

而我们在实践中, 遇到过一个更加实际的问题, 看下面的例子:

1
2
3
4
5
6
<?PHP
$mmc = new Memcached();
$mysql = mysql_connect();
//process
mysql_close($mysql);
$mmc->close();

这是一个真实的教训, 代码如上面所示, 突然有一天我们的Mysql出现了问题, 导致连接Mysql的耗时增大, 然后就导致, 一个脚本对Memcached连接占用过长, 最后Memcache因为连接数太多, 就拒绝服务了..

所以, 我们一定要让连接代价最高的资源, 最先初始化.

系统最大句柄 (/proc/sys/fs/file-max)

这个很简单, 如果你持续打开句柄, 而不释放, 那么你有可能触发系统最大句柄限制, 对于进程来说, 自己还有进程可打开句柄数限制(ulimit -n).

系统调用是昂贵的(System call is expensive)

PHP之所以会在请求结束后正确的释放掉所有的资源, 内存, 这是因为当我们在脚本中使用新的内存的时候, PHP会向OS申请一大块内存(ZEND_MM_SEG_SIZE大小), 然后分给你你需要的合适的一块小内存.

当你不使用这块小内存的时候, PHP也不会返还给OS, 而是保留下来给后续的处理使用.

我们知道, malloc(3)会导致系统调用(brk(2))(当然也可能是mmap, 我们此处不考虑这个细节, thanks to 华裔), 而系统调用是昂贵的.

所以, 如果你使用完了资源不及时释放, 那么后续的逻辑如果请求内存, PHP发现之前申请的一大块内存已经分光了, 它就只好再次向OS发起malloc调用, 得到一块新的大内存. 并且它还需要对这个大内存做一些标记处理..

而如果你使用完资源, 及时释放的话, 那么下次脚本申请内存的时候, 你之前归还的内存块就可以被重复利用, 那么也许你的整个脚本只需要和OS申请一次内存.

内存峰值(Memory peak usage)

这个和上面的有一定的关系, 当你使用完资源就释放, 然后后续又使用这样的资源. 那么PHP的内存占用会是:

资源+1 -> 资源-1 -> 资源+1 -> 资源-1 (峰值是1)

而如果你是等到PHP请求结束再释放:

资源+1 -> 资源 + 1 …. -> 资源 -1 -> 资源 – 1 (峰值是2)

也就说, 一个良好的编写的脚本可能要比一个瞎写的脚本, 要省很多峰值内存..

考虑一个极端情况, 对一个很繁忙的服务器来说, 比如有10个PHP进程, 每个PHP进程最大1G内存, 而服务器只有8G内存.

结论 (conclusion)

结论很明显, 我开头也说过了, 我从来不认为这个是个问题.

这里说一句, 如果你买了一本PHP的书, 它告诉你: “不用在PHP主动释放资源, 因为PHP会帮你释放”的话, 我建议你, 烧了它.

http://www.laruence.com/2012/08/06/2681.html

你这么擅长安慰他人,一定度过了很多自己安慰自己的日子吧

基本概念

CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
那么CSRF到底能够干嘛呢?你可以这样简单的理解:攻击者可以盗用你的登陆信息,以你的身份模拟发送各种请求。攻击者只要借助少许的社会工程学的诡计,例如通过QQ等聊天软件发送的链接(有些还伪装成短域名,用户无法分辨),攻击者就能迫使Web应用的用户去执行攻击者预设的操作。例如,当用户登录网络银行去查看其存款余额,在他没有退出时,就点击了一个QQ好友发来的链接,那么该用户银行帐户中的资金就有可能被转移到攻击者指定的帐户中。
所以遇到CSRF攻击时,将对终端用户的数据和操作指令构成严重的威胁;当受攻击的终端用户具有管理员帐户的时候,CSRF攻击将危及整个Web应用程序。

CSRF的攻击过程

要完成一次CSRF攻击,受害者必须依次完成两个步骤 :
1.登录受信任网站A,并在本地生成Cookie 。
2.在不退出A的情况下,访问危险网站B。
看到这里,读者也许会问:“如果我不满足以上两个条件中的任意一个,就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站,特别现在浏览器都是支持多tab的。
你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。
上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
因此对于用户来说很难避免在登陆一个网站之后不点击一些链接进行其他操作,所以随时可能成为CSRF的受害者。
CSRF攻击主要是因为Web的隐式身份验证机制,Web的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的

如何预防CSRF

CSRF的防御可以从服务端和客户端两方面着手,防御效果是从服务端着手效果比较好,现在一般的CSRF防御也都在服务端进行。
服务端的预防CSRF攻击的方式方法有多种,但思想上都是差不多的,主要从以下2个方面入手:
1、正确使用GET,POST和Cookie;
2、在非GET请求中增加伪随机数;

为每个用户生成一个唯一的cookie token,所有表单都包含同一个伪随机值,这种方案最简单,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败,但是由于用户的Cookie很容易由于网站的XSS漏洞而被盗取,所以这个方案必须要在没有XSS的情况下才安全。
每个请求使用验证码,这个方案是完美的,因为要多次输入验证码,所以用户友好性很差,所以不适合实际运用。
不同的表单包含一个不同的伪随机值,我们在4.4小节介绍“如何防止表单多次递交”时介绍过此方案,复用相关代码,实现如下:

生活总是有很多出人意料的事情,比如,你以为我要举个例子。

应用前提

1
2
3
4
5
分支里面的代码如果没有提交commit ,那么切换到其他分支下还是可以看
到(git status)这个分支下的代码.

但是如果我们现在想要切换到别的分支但是同时又不想提交commit我们的代码
该如何处理?

git stash

1
2
3
在你切换分支前,运行:git stash 就可以了
当你在其他分支改好了代码并切换回当前分支的时候,请git stash pop

相关命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
git stash
保存当前的工作进度。会分别对暂存区和工作区的状态进行保存

git stash save "message..."
这条命令实际上是第一条 git stash 命令的完整版

git stash list
显示进度列表。此命令显然暗示了git stash 可以多次保存工作进度,并用在恢复时候进行选择

git stash pop [--index] [<stash>]
如果不使用任何参数,会恢复最新保存的工作进度,
并将恢复的工作进度从存储的工作进度列表中清除。
如果提供参数(来自 git stash list 显示的列表),则从该 <stash> 中恢复。恢复完毕也将从进度列表中删除 <stash>。
选项--index 除了恢复工作区的文件外,还尝试恢复暂存区。

git stash apply [--index] [<stash>]
除了不删除恢复的进度之外,其余和 git stash pop 命令一样

git stash clear
删除所有存储的进度

某天,你无端想起一个人,她曾让你对明天有所期许,但是却完全没有出现在你的明天里。

简要说明

1
2
3
4
5
6
7
8
一个高性能的支持丰富数据结构的 NoSQL 数据库, 用于替代 Redis.
基于google/leveldb 开发SSDB是一个开源的高性能数据库服务器,
使用Google 的 LevelDB作为存储引擎, 大家有可能没听过leveldb的名字,
但是淘宝的开源nosql tair大家应该有所耳闻吧,他也是基于leveldb做的开发。
ssdb支持T级别的数据, 同时支持类似Redis中的zset和hash等数据结构,
在同时需求高性能和大数据的条件下, 是一个可以代替Redis的方案.
ssdb是一个持久化存储的KV系统,和Memcached、Redis这种内存型的KV系统不同,
ssdb不会像Redis一样狂吃内存,而是将大部分数据存储到磁盘上。

安装

1
2
3
4
5
6
wget --no-check-certificate https://github.com/ideawu/ssdb/archive/master.zip
unzip master
cd ssdb-master
make
# optional, install ssdb in /usr/local/ssdb
sudo make install

启动

1
2
3
4
5
# start master
./ssdb-server ssdb.conf

# or start as daemon
./ssdb-server -d ssdb.conf

使用

1
2
3
4
5
6
<?php
require_once('SSDB.php');
$ssdb = new SimpleSSDB('127.0.0.1', 8888);
$resp = $ssdb->set('key', '123');
$resp = $ssdb->get('key');
echo $resp; // output: 123

关于leveldb

1
2
3
4
LevelDB是google开源的一个key-value存储引擎库,类似于开源的Lucene索引库一样。
其他的软件开发者可以利用该库做二次开发,来满足定制需求。
LevelDB采用日志式的写方式来提高写性能,但是牺牲了部分读性能。
为了弥补牺牲了的读性能,一些人提议使用SSD作为存储介质。

说明

1
2
修改ssdb.conf文件,把ip改成0.0.0.0,允许外网访问
高级应用可以查看主从这一块儿

http://ssdb.io/zh_cn/

“跑呀跑呀跑呀跑呀,拼命努力着追上前面那个被目光期许的自己,生怕抓不住时光,只有和你一起的时候,才觉得不如就这样老了吧,也不算太辜负。”
### CGI
1
2
3
4
5
6
7
8
9
CGI英文全程是 Command Gateway Interface,通常翻译为公共网关接口,
HTTP服务器与机器上的其他程序进行通信的一个接口。
这个“其他程序”可以是使用任何计算机语言进行编 写,例如phppythonperl等等。
它通过CGI这个接口从HTTP服务器取得输入,然后把运行结果又通过CGI这个接口交给HTTP服务器, 而HTTP服务器把这个结果送给浏览器。

CGI 的出现让WEB从静态变为动态,随着web的越来越普及,很多的网站都需要有动态的页面,
以便与浏览者进行交互。CGI的缺点也越来越突出,因为HTTP 要生成一个动态页面,
系统就必须启动一个新的进程以运行CGI程序,
不断的fork是一项很消耗时间和资源的工作。

FastCGI

1
2
3
4
5
6
7
8
FastCGIFastCGI是可伸缩架构的CGI开放扩展,
其主要行为是将CGI解释器进程保持在内存中并因此获得较高的性能。
传统的CGI 解释器的反复加载是CGI性能低下的主要原因,
如果CGI解释器保持在内存中并接受FastCGI进程管理器调度,
则可以提供良好的性能、伸缩性等 。在上述情况中,你可以想象 CGI通常有多慢。
每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展并重初始化全部数据结构。
使用FastCGI,所有这些 都只在进程启动时发生一次。一个额外的好处是,
持续数据库连接(Persistent database connection)可以工作。

mod_php

1
2
3
4
5
6
7
8
9
10
11
12
在lamp体系中,对于apache端的php的配置,我们最常用的就是mod_php,
它把php作为apache一个内置的模块.让apache http服务器本身能够支持php语言,
不需要每一个请求就启动php解释器来解释php.

和把webserver与php绑定起来的方式不同,
fastcgi是http服务器与你的或其它机器上的程序进行“交谈”的一种工具,
相当于一 个程序接口。它可以接受来自web服务器的请求,解释输入信息,
将处理后的结果返回给服务器等。mod_fastcgi就是在apache下支持 fastcgi协议的模块。

在lamp体系中,mod_php是最常使用的工作方式。在这种模式下,
php被编译为apache的一个内置模块,在启动加载的时候,
当有一个php请求过来,直接在httpd进程里完成了php的解释运行,将结果返回。

mod_fastcgi

1
2
3
4
mod_fastcgi就是在apache下支持 fastcgi协议的模块。
fastcgi实例和apache分离开来,这两者可以分开来部署。
他们之间的通信通过tcp或者unix sock来完成。使用ext方式,
fastcgi实例是独立运行的。

FPM

1
2
3
FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,
对于高负载网站是非常有用的。

http://blog.shiliuvip.com/391.html
http://php.net/manual/zh/install.fpm.php

最初不相识,最终不相认
生成器允许你在 foreach 代码块中写代码来迭代一组数据而不需要在内存中创建一个数组, 那会使你的内存达到上限,或者会占据可观的处理时间。相反,你可以写一个生成器函数,就像一个普通的自定义函数一样, 和普通函数只返回一次不同的是, 生成器可以根据需要 yield 多次,以便生成需要迭代的值。 一个简单的例子就是使用生成器来重新实现 range() 函数。 标准的 range() 函数需要在内存中生成一个数组包含每一个在它范围内的值,然后返回该数组, 结果就是会产生多个很大的数组。 比如,调用 range(0, 1000000) 将导致内存占用超过 100 MB。 做为一种替代方法, 我们可以实现一个 xrange() 生成器, 只需要足够的内存来创建 Iterator 对象并在内部跟踪生成器的当前状态,这样只需要不到1K字节的内存。 ### 简单理解
1
2
3
4
5
6
官方的定义中:生成器就是简单的迭代器。
不同于标准的PHP迭代器,PHP的生成器并不要求你一定要在一个重量级的类中实现Iterator接口。
相反,生成器会按需求计算并交出迭代值。这对应用程序的性能有着深远的意义。想想吧,
一个标准的PHP迭代器通常都是基于内存中全部计算过的数据集进行迭代。这样做效率不高。
尤其是大量可计算的公式化数据集。使用生成器我们可以动态的计算并交出下一个值而不占用
宝贵的系统内存,这就是我们使用生成器的原因。
### 创建一个生成器
1
2
3
4
5
6
<?php  
function myGenerator() {
yield 'value1';
yield 'value2';
yield 'value3';
}
### 使用这个生成器
1
2
3
4
<?php  
foreach (myGenerator() as $yieldedValue) {
echo $yieldedValue, PHP_EOL;
}
结果: value1 value2 value3

实例

  • Range生成器(糟糕的实现)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php  
function makeRange($length) {
$dataset = [];
for ($i = 0; $i < $length; $i++) {
$dataset[] = $i;
}

return $dataset;
}

$customRange = makeRange(1000000);
foreach ($customRange as $i) {
echo $i, PHP_EOL;
}

  • Range生成器(好的实现)
1
2
3
4
5
6
7
8
9
10
11
<?php  
function makeRange($length) {
for ($i = 0; $i < $length; $i++) {
yield $i;
}
}

foreach (makeRange(1000000) as $i) {
echo $i, PHP_EOL;
}

上面的例子并不实用。但是,联想一下所有你可能用来计算的数据集。序列数(例如斐波纳挈数)就是很典型的例子。同样你还可以遍历文件流资源。想象一下,如果你需要遍历一个4G的逗号分隔值(CSV)文件,而你的虚拟个人服务器(VPS)上PHP只分配了1G的内存。你根本没法把整个文件读取到内存中。

  • CSV生成器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php  
function getRows($file) {
$handle = fopen($file, 'rb');
if ($handle === false) {
throw new Exception();
}
while (feof($handle) === false) {
yield fgetcsv($handle);
}
fclose($handle);
}

foreach (getRows('data.csv') as $row) {
print_r($row);
}

接收参数

1
2
3
4
5
6
7
8
9
10
11
function printer()
{
while (true) {
printf("receive: %s\n", yield);
}
}

$printer = printer();

$printer->send('hello');
$printer->send('world');

说明

生成器的确使用了很少的内存却大大简化了某些任务。如果你需要更强大的功能诸如重置、快进、或者数据集的检索,你最好还是自定义一个实现Iterator interface接口的类,或者使用PHP现成的Standard PHP Library(SPL)迭代器。

yieldreturn 都会返回值,但区别在于一个 return 是返回既定结果,一次返回完毕就不再返回新的结果,而 yield 是不断产出直到无法产出为止。

http://blog.csdn.net/bandita/article/details/47723815
https://laravel-china.org/articles/1430/single-php-generator-complete-knowledge-generator-implementation-process

最孤独的,不是不能跟一个人在一起,而是根本不知道想跟谁在一起......

说明

PHP5开始支持了接口, 并且内置了Iterator接口, 所以如果你定义了一个类,并实现了Iterator接口,
那么你的这个类对象就是ZEND_ITER_OBJECT,否则就是ZEND_ITER_PLAIN_OBJECT.
对于ZEND_ITER_PLAIN_OBJECT的类,foreach会通过HASH_OF获取该对象的默认属性数组,然后对该数组进行foreach.
而对于END_ITER_OBJECT的类对象,则会通过调用对象实现的Iterator接口相关函数来进行foreach。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

/**
* Iterator模式的简单实现类
*/
class sample implements Iterator {
private $_items ;

public function __construct(&$data) {
$this->_items = $data;
}
public function current() {
return current($this->_items);
}

public function next() {
next($this->_items);
}

public function key() {
return key($this->_items);
}

public function rewind() {
reset($this->_items);
}

public function valid() {
return ($this->current() !== FALSE);
}
}

/** DEMO */
$data = array(1, 2, 3, 4, 5);
$sa = new sample($data);
foreach ($sa AS $key => $row) {
echo $key, ' ', $row, '<br />';
}

?>

适用范围

  • 使用返回迭代器的包或库时(如PHP5中的SPL迭代器)
  • 无法在一次的调用获取容器的所有元素时
  • 要处理数量巨大的无素时(数据库中的表以GB计的数据)
  • ……

举例

一般是使用foreach来使用迭代器,下面整理了一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php   
class sample implements Iterator
{
private $_items = array(1,2,3,4,5,6,7);

public function __construct() {
;//void
}
public function rewind() { reset($this->_items); }
public function current() { return current($this->_items); }
public function key() { return key($this->_items); }
public function next() { return next($this->_items); }
public function valid() { return ( $this->current() !== false ); }
}

$sa = new sample();
foreach($sa as $key => $val){
print $key . "=>" .$val;
}
?>

我做事三分钟热度,却也爱你那么久。
### 问题
1
使对象可以像数组一样进行foreach循环,要求属性必须是私有。

鸟哥给出的答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class sample implements Iterator
{
private $_items = array(1,2,3,4,5,6,7);

public function __construct() {
;//void
}
public function rewind()
{
reset($this->_items);
}
public function current()
{
return current($this->_items);
}
public function key()
{
return key($this->_items);
}
public function next()
{
return next($this->_items);
}
public function valid()
{
return ( $this->current() !== false );
}
}

$sa = new sample();
foreach($sa as $key => $val){
print $key . "=>" .$val.'<br>';
}

拓展说明

使用foreach只可以循环出数组的public属性,protected和private属性无法得到

1
2
3
4
5
6
7
8
9
10
11
12
13
class User
{
public $a = 'tom';
protected $b = 'lilei';
private $c = 'hanmeimei';
public function __construct()
{
}
}

foreach (new User() as $user){
echo $user.'<br>';
}

但是在类的内部可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class User
{
public $a = 'tom';
protected $b = 'lilei';
private $c = 'hanmeimei';
public function do_something() {
foreach($this as $key => $value) {
echo "$key => $value\n";
}
}
}

$user = new User();
$user->do_something();

http://www.laruence.com/2008/10/31/574.html

你走了好,不然总担心你要走。
### 实验环境 - laravel 5.1

实验步骤

  • 1.安装扩展包
1
composer require rcrowe/twigbridge
  • 2.在config/app.php下配置
1
2
3
4
5
6
7
8
'providers' => [
...
TwigBridge\ServiceProvider::class,
],
'aliases' => [
...
'Twig' => TwigBridge\Facade\Twig::class,
],
  • 3.发布配置文件,该操作会在config目录下新建一个专属twig的配置文件twigbrage.php
1
php artisan vendor:publish --provider="TwigBridge\ServiceProvider"
  • 4.开始使用
1
2
3
4
5
6
7
8
9
10
11
//返回视图
Route::get('test',function (){
$users = \App\User::all();
return view('hello',compact('users'));
});
//新建视图文件resources/views/hello.twig
<body>
{% for user in users %}
{{ user.name }}
{% endfor %}
</body>

参考

https://packagist.org/packages/rcrowe/twigbridge

答案很长,我准备用一生的时间来回答,你准备要听了吗?

简介

1
2
3
4
5
6
7
MySQL的内存表,表结构创建在磁盘上,数据存放在内存中,所以当MySQL启动着的时候,
这个表是存在的,数据也是存在的,当MySQL重启后,数据消失,表结构还存在(
临时表表结构及数据都在内存中)。内存表最大所需内存需要通过
max_heap_table_size=1024M设定,临时表最大所需内存需要通过tmp_table_size = 1024M
设定。当数据超过临时表的最大值设定时,自动转为基于磁盘的MyISAM表,
存储在指定的tmpdir目录,此时因需要进行IO操作,性能会大大下降,
而内存表不会,内存表满后,会提示数据满错误。

特征

1
2
3
4
内存表的表定义是存放在磁盘上的,扩展名为.frm, 重启不会丢失。
内存表的数据是存放在内存中的,重启会丢失数据。
MEMORY表使用一个固定的记录长度格式。
mysql重启后,主键、自增、索引仍然存在,只是数据丢失。

优点

1
内存表使用哈希散列索引把数据保存在内存中,因此具有极快的速度。

缺点

1
2
3
4
内存表不能包含BLOB或者TEXT列。
内存表不支持事务。
内存表是表锁,当修改频繁时,性能可能会下降。
内存表数据清空或删除表后占用内存不会自动释放。

基本操作

1
2
3
4
CREATE TABLE mem_table(  
id int(10),
num int(10)
) ENGINE=MEMORY;