#### MySQL存储引擎
* MySQL是插件式存储存储引擎,支持多种存储引擎
* 常见的存储引擎有:MyISAM, Aria, InnoDB, MRG\_MYISAM, CSV, BLACKHOLE, MEMORY, PERFORMANCE\_SCHEMA, ARCHIVE, FEDERATED
~~~objectivec
mysql> SHOW ENGINES; #查看支持多少种存储引擎
*************************** 1. row ***************************
Engine: FEDERATED #引擎名称
Support: NO #是否支持
Comment: Federated MySQL storage engine #简要注释
Transactions: NULL #是否支持事务功能
XA: NULL #是否支持分布式事务功能
Savepoints: NULL # 是否支持保存点功能
*************************** 2. row ***************************
~~~
...
* 存储引擎是表级别的概念,因此又称为“表类型”;不建议在同一个库中的表上使用不同的ENGINE;
~~~css
CREATE TABLE ... ENGINE[=]STORAGE_ENGINE_NAME ...
SHOW TABLE STATUS
~~~
#### 1\. InnoDB存储引擎
InnoDB存储引擎,把数据存储在一个文件中,是个黑盒,根varnish是一样,varnish中的数据缓存都存储在一个文件中,但其内部完全有自组织有序的结果从外部看来就是一个文件,内部可以有自己的元数据,数据是构建在文件系统之上的文件系统;而InnoDB也是这样,默认情况下可以将n张表放在一个表空间里,在外部看来就是一个表,其内部存放了n张表甚至存放了n张表的索引;不过把n张表的索引放在同一表中很难实现高级功能;比如像单表导入导出等;因此,这就是为什么在安装MariaDB时,都要求使用innodb\_file\_per\_table这表示每张表使用一个表空间;
InnoDB的表空间为了能跨文件系统(分区),InnoDB的表空间背后所对应的文件 可以不止一个,而且还可以自动增长;表空间刚创建时,就占用固定大小的空间,如果再许愿空间时,就又占用固定大小的空间,用不用都占用;可理解为是基于步进的方式进行划分;InnoDB将所有的表和索引放在一个表空间中;
如果所有表和数据都存储在一个表空间中时,表空间文件是存储在datadir定义的目录中的;
如果每张表单独存储在一个表空间中,则表空间文件是放置在数据库目录下,而不是数据目录下;例如有一个数据库叫mydb就相当于在数据库目录下创建一个mydb的目录而已;
当然数据库目录有可能在数据目录下的子目录;
~~~objectivec
MariaDB [(none)]> SHOW ENGINES\G;
...
*************************** 6. row ***************************
Engine: InnoDB
Support: DEFAULT
Comment: Percona-XtraDB, Supports transactions, row-level locking, and foreign keys
Transactions: YES
XA: YES
Savepoints: YES
~~~
* 数据存储于“表空间(table space)”中,是个黑盒:有两种管理方式:
(1) 所有数据库中的所有类型为InnoDB的表的数据和索引存储于同一个表空间中;
* 表空间文件:存储在datadir定义的目录下;
* 表现出的文件为:ibddata1,ibddata2,...
(2) 每个表单独使用一个表空间存储表的数据和索引;使用`innodb_file_per_table=ON`开启;
* 数据文件(存储数据和索引)名:tb1\_name.frm
* 每张表由2个文件组成:tb1\_name.ldb和tb1\_name.frm
* 文件存储于数据库目录中
注:基于第一种方式管理时,所有数据库的InnoDB表将使用同一个表空间,例如有10个库,每个库中有100张表,都放在同一个表空间中,于后期管理无益。
* InnoDB存储引擎是事务性存储引擎,适合处理大量的短期任务;
* 基于MVCC(Mutli Version Concurrenvy Contro,多版本并发控制)支持高并发,支持所有的四个隔离级别;默认支持间隙锁防止幻读;
* 使用聚簇索引(一般是主键索引);
* 一张表的聚簇索引只能有一个;索引在哪数据就在哪里
* 支持自适应hash索引;
* 锁粒度:行级锁,间隙锁;
注意:级别越高事务发生冲突性越小,事务安全性越高但并发性能就越低;
> 注:MVCC,multi version concurrency control:多版本并发访问控制,它就是类似于lvm的快照功能;也就意味着,当启动n个事务时,每一个事务,都针对于mysql当中的InnoDB存储引擎现有数据做一个快照; 每一个快照,通过快照过去访问时间点是一致的,所以现在要启动一个事务,就对InnoDB数据集做个快照,就在快照基础上做操作;因此有50个事务为了彼此间不受影响,每个事务启动一次做一个快照。
> 但是,这病不意味着就没有冲突,想象以下,如果第一个快照和第二个也快照了,两个操作同一个数据集,一个删了一行,而第二个事务把这个行改了,此时就会出现问题,所以,必须有隔离机制来实现所谓的事务隔离;
> 而事务隔离中最核心组件就是锁;这么一来事务也没法并发了,既然锁了,看上去事务同时启动,但是还得等待一个个完成;所以,隔离级别至关重要了;
* * *
> 另:percona公司对mysql做了二次开发,服务器版本为percona-server,把InnoDB改进为XtraDB存储引擎,mariadb使用了XtraDB引擎,但是名称依然叫InnoDB
##### 总结InnoDB引擎的特性:
* 存储数据:表空间
* 并发:MVCC,间隙锁
* 索引:聚集索引、辅助索引
* 性能:预读操作、自适应hash索引、插入操作缓存区
* 备份:支持热备
`SHOW ENGINE INNODB STATUS;`
#### 2\. MyISAM存储引擎
MyISAM内部的复杂机制很少,特别适应于读多写少的应用;但是,mysql自己的表,内部的元数据的库还是使用的MyISAM存储引擎;
MyISAM存储引擎最大特性是支持全文索引,全文索引指的是全文中的每一个关键字都可以被搜索;
MyISAM在崩溃后无法安全恢复,有可能会导致某些数据丢失,比如要插入一行数据,刚插入一般数据库崩溃,只能把刚插入的半行删了,保证数据是一致性的;解决办法是使用MyISAM表修复工具,会对全表扫描,一行行扫描,看哪一行中的数据不是完整的给它删了,所以这就是崩溃后的恢复,如果表要大的话,恢复时间会非常长;索引说可以接受较长时间的修复操作才能使用MyISAM;这个较长时间还是指的较小的表,如果表答可能修复一天都有可能。
MariaDB虽然支持MyISAM存储引擎但是,默认对于MyISAM而言使用的是Aria存储引擎,其实就是MyISAM的增强版,支持崩溃后的安全恢复;
MyISAM存储引擎的文件,表和索引是独立存放的;索引可看出来使用的是非聚集索引;因此,每一个索引的叶子节点,都是个指针,指向了真正数据所在的位置;这就类似于书中的目录和后面正文的关系;
对于InnoDB,每张表使用两个文件一个是用来存储数据和索引的.ibd文件,一个是用来存储表格式的.frm格式的文件;而对于MyISAM,每张表有三个文件且都放在数据库目录下而不是datadir=指定的目录下,也就是说的datadir指定的目录下的子目录里;
* tbl\_name.frm:表格式定义;
* tbl\_name.MYD:数据文件;
* tbl\_name.MYI:索引文件;
~~~objectivec
MariaDB [(none)]> SHOW ENGINES\G;
*************************** 5. row ***************************
Engine: MyISAM
Support: YES
Comment: MyISAM storage engine
Transactions: NO
XA: NO
Savepoints: NO
~~~
##### 总结MyISAM存储引擎特性:
* 加锁好并发:支持表级锁
* 修复:只能手动或自动修复(使用工具)、但可能会丢失数据;并不是安全恢复
* 索引:使用的是非聚集索引
* 支持延迟更新索引:只是为了提高性能
* 支持表压缩:压缩后表数据不能修改
##### 行格式:
`{DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT}`
* `dynamic:` 动态行
* `fixed`:固定行
* `compressed:`压缩行
* `compact:`紧致行
* `redundent:`冗余行
态还是固定行取决于表中字段的类型,例如字段的类型是varchar类型长度是可变的,如果某一字段使用varchar类型,每行可以不同的长度;行长度不一样管理很麻烦,性能比较低;行的长度一样只需根据距离来判断下一行在什么位置就可以了;
**以上InnoDB和MyISAM是mysql中最为经典的两种存储引擎;**
~~~ruby
MariaDB [hellodb]> SHOW ENGINES; #查看所有支持的存储引擎
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| Engine | Support | Comment | Transactions | XA | Savepoints |
+--------------------+---------+----------------------------------------------------------------------------+--------------+------+------------+
| MEMORY | YES | Hash based, stored in memory, useful for temporary tables | NO | NO | NO |
| MRG_MYISAM | YES | Collection of identical MyISAM tables | NO | NO | NO |
| CSV | YES | CSV storage engine | NO | NO | NO |
| BLACKHOLE | YES | /dev/null storage engine (anything you write to it disappears) | NO | NO | NO |
| MyISAM | YES | MyISAM storage engine | NO | NO | NO |
| InnoDB | DEFAULT | Percona-XtraDB, Supports transactions, row-level locking, and foreign keys | YES | YES | YES |
| ARCHIVE | YES | Archive storage engine | NO | NO | NO |
| FEDERATED | YES | FederatedX pluggable storage engine |
MariaDB [hellodb]> SHOW GLOBAL VARIABLES LIKE '%STORAGE%'; #查看默认存储引擎
+------------------------+--------+
| Variable_name | Value |
+------------------------+--------+
| default_storage_engine | InnoDB |
| storage_engine | InnoDB |
+------------------------+--------+
~~~
#### 3\. 其他存储引擎
* CSV:将普通的CSV文件(字段基于逗号分隔)作为MySQL表使用;
* 所谓CSV文件:一个文件中也是有很多行组成,每一行有很多字段组成,而字段用逗号分隔,把整个文件当表使用;
* CVS文件好处在于可以使用grep、awk、sed工具直接处理,但是由于基于文本存储的,浮点型数据转换为文本字符串存储后会丢失精度
* CVS特别适合用于在多个不同的数据库之间共享数据时使用
* MRG\_MYISAM:由多个MyISAM表合并成的虚拟表
* 表可以分割成小表,就像zabbix中数据一样,把表分成多个小标按天存放,一天一张表,要想删除时,直接删除某天的表即可;每一天的表其实就是一个表分区table partion
* 要查询多张表是合并即可
* BLACKHOLE:类似于/dev/null,不真正存储任何数据,只会在特定场景中使用
* 对mysql而言blachole stroage engine相当于linux上的/dev/null,索引某张表的存储引擎是该类型,这个表存储的所有数据都不会产生任何IO,因为数据被丢弃了
* 只在特定的场景中使用:比如多级架构执行复制操作时;
* MEMORY:基于内存存储,支持hash索引,表级锁,常用语临时表;
* PERFORMANCE\_SCHEMA:类似于Linux/proc目录,用于存储mysql的性能数据;
* 是关于mysql性能各类统计的收集存储的表,只用来收集mysql运行中的统计数据,做性能评估,或者是有助于优化器优化;
* 表中的统计数据只对当前有效,一旦mysql停机,这个表就作废变为空的,启动后就会不断的填入很多收集到的与性能相关的数据
* 此存储引擎用处在于mysql为了达到一切皆sql表的目的,索引把它内部的统计数据基于sql接口进行输出了
* ARCHIVE:支持SELECT 和INSERT 操作,支持行级锁和专用缓存区;
* 用于数据永久存储并且当做数据仓库使用;不支持修改操作
* FEDERATED:类似于MRG\_MYISAM,不用支出在于MRG\_MYISAM所合并的多张表一定是同一个mysql服务器上的,甚至是同一个数据库中的多张表;但是FEDERATED能把两个数据库服务器上的表联合在一起使用
* 用于访问其它的远程的MySQL Server的代理接口,它通过创建一个到远程MySQL Server的客户端连接,并将查询语句传输至远程服务器执行;
* 自己本地没有表,但可以把这个当做接口,所有发给FEDERATED存储引擎表的所有语句,都会基于mysql连接发给另一个数据库服务器上另外一张表,而后完成数据存取;
注:FEDERATED也仅支持mariadb;是夸数据库服务器的角色
#### 4\. MariaDB支持的其他存储引擎
* OQGraph:支持实体存储
* Sphinx SE:搜索引擎
* 而mariadb支持sphinxSE存储引擎,意味着,这个表存储的所有数据都直接基于sphinxSE接口导入到sphinx存储里了;
* TokuDB:支持海量数据的存储引擎,支持原生分布式存储
* Cassandra:由facebook研发,分布式无中心的存储;
* mariadb支持把表存储Cassandra以后,没有在mysql本地存储,而是导入到Cassandra表中;
* CONNECT存储引擎
* SQUENCE存储引擎
#### MySQL事务
##### 并发控制:
锁是mysql实现并发访问控制的重要组件;
* 为什么要有锁机制:
任何文件或数据集只要支持并发访问模型,就必须基于锁机制对其机制进行控制;对mysql服务器,允许多个线程同时连进来支持做读写操作请求,这样多个查询语句就有可能只对同一个数据集进行,例如第一个线程对数据集中的某行做修改,第二个线程对同一个数据集中的同一行做查询,这样二者同时操作就会带来混乱;
所以,mysql为了能够实现并发访问中避免数据读写冲突,就必须施加所机制。
* 锁类型:
* 读锁:共享锁,可以共享给其他的读操作
* 写锁:独占所,其他操作不可读写
* 锁粒度:
* 表级锁:在表级别施加锁,并发性较低;
* 行级锁:在行级别施加锁,并发性较高;维持锁状态的成本较大;
* 页级锁(早些时候支持)
* 所策略: 在锁粒度及数据安全性之间寻求一种平衡机制;
* 存储引擎:每种存储引擎都可以自行实现其所策略和锁粒度
* MySQL Server:表级别,可自行决定,也允许显示请求;
* 根据所本身根据用户手动施加还是由服务器自动实现,锁又可以分两种类型:
* 显式锁:用火狐手动请求施加的锁
* 隐式锁:有存储引擎(或mysql服务器)自行根据需要施加的锁;
显示锁使用:
(1) LOCK TABLES 命令:锁定整张表或多张表
用法:LOCK TABLES tbl\_name \[\[AS\] alias\] lock\_type \[,tbl\_name \[\[AS\] alias \] lock\_type\] ...
lock\_type : 所类型 READ\[ LOCAL\] | \[LOW\_PRIORITY\] WRITE
tbl\_name: 锁名称
~~~css
UNLOCK TABLES; 解锁;
(2) FLUSH TABLES 命令:作用在于如果一张表被打开了,需要把内存中的所有数据都清到磁盘上,在把表关闭;
用法:FLUSH TABLES tbl_name[,...] [WITH READ LOCK] [FOR UPDATE]
WITH READ LOCK: 施加读锁
FOR UPDATE: 请求修改,即施加写锁
(3) SELECT 语句:锁定表中的某些行
用法:SELECT clause [FOR UPDATE] [WITH READ LOCK]
~~~
* * *
~~~csharp
示例:
MariaDB [(none)]> CREATE DATABASE testdb; #创建数据库
Query OK, 1 row affected (0.01 sec)
MariaDB [(none)]> USE testdb
Database changed
MariaDB [testdb]> CREATE TABLE tbl; #创建表
ERROR 1113 (42000): A table must have at least 1 column
MariaDB [testdb]> CREATE TABLE tbl (id INT NOT NULL ,name VARCHAR(50)); #插入数据
Query OK, 0 rows affected (0.05 sec)
MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (1,'TOM');
Query OK, 1 row affected (0.01 sec)
MariaDB [testdb]> SELECT * FROM tbl;
+----+------+
| id | name |
+----+------+
| 1 | TOM |
+----+------+
1 row in set (0.01 sec)
MariaDB [testdb]> LOCK TABLE tbl READ; #施加读锁
Query OK, 0 rows affected (0.00 sec)
另外启动一个线程:
MariaDB [(none)]> use testdb;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [testdb]> SELECT * FROM tbl;
+----+------+
| id | name |
+----+------+
| 1 | TOM |
+----+------+
1 row in set (0.00 sec)
MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (2,‘JERRY’); #插入数据被阻塞
线程1释放锁:
MariaDB [testdb]> UNLOCK TABLES;
Query OK, 0 rows affected (0.00 sec)
线程2插入数据成功:
MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (2,'JERRY');
Query OK, 1 row affected (0.01 sec)
~~~
##### 事务日志:
事务日志就是mysql数据文件之外的另外一个存储区域,这个存储区域带来的作用是:当一个事务型存储引擎在运行过程中,需要启动一个事务并完成数据修改时,所有的修改操作(由多个sql语句组成),每一次的操作所涉及到的数据修改,这个修改的操作要转换成底层存储引擎所支持的相关操作的操作过程,它会把每一次的sql语句所涉及的操作步骤,具体的过程记录在事务日志文件中。
注意,事务日志记录的是每一步的具体操作;例如,插入一行的数据是什么、插入什么位置、什么时候插入得等都记录下来;再例如,如果是修改几行,先修改哪行后修改哪行、几点开始修改、几点结束等等都记录下来;而且这个日志要能够重现操作就叫做事务日志。
一个事务型存储引擎它的操作借助于事务日志来保证其对应的事务特性;所以,任何事务型存储引擎的相关操作,默认不会直接写在数据库文件上,而是先写在事务日志中,并且事务日志为保证足够可靠,基本上很少在内存中缓冲,写完建基本比较差,都会先写在内存上,然后等过一会再同步到磁盘上;事务日志也有这段缓冲区,但这个缓冲区不能太大时间也不能太久,因为如果允许缓存5秒钟,系统崩溃最大会丢失5秒的数据,所以建议这个时间要足够短,一般为1秒钟同步到磁盘上一次;但是,同步越频繁性能就越差,数据可靠性就越高。
事务日志的每一步在记录时,还会把修改之前的原始数据内容也记录下来,这是为了支持undo和redo机制而记录的;即当记录的是修改数据时会把又该的数据之前的数据记录下来。假如,操作进行到一半服务器崩溃了,把修改的操作日志撤销了即可,因为还没有同步到磁盘上;如为例如保证数据的稳定性,一个大事务中间有可能事务还没完成,已经在事务日志记录了30个,再记录事务日志会先把一部分信息往磁盘上同步,开始真正修改原始数据了,这时如果崩溃,则只能把已经同步到表中的数据撤销,这就是undo机制;
还有一种情况是,比如一个事务有60个sql语句都写完了且都记录在事务日志中了,但只有气筒30个同步到了磁盘上,如果此时崩溃,则此时数据是不一致的;因为有些事务已经提交,但是没有存储到磁盘上,这样就必须把事务日志中为完成的语句同步到磁盘上,这就是redo机制;
同步的要做提交,没能完成的要做回滚,这就是崩溃后恢复。
如果日志文件非常大,恰好写满了崩溃,下次启动mysql时,必须把里面的所有语句统统同步到磁盘才能正常启动,;如果事务日志文件大道2G,为了能够把2G的语句同步到磁盘上,有可能mysql服务器启动半小时,所以为了避免崩溃后启动时间太长,把日志文件设置小一点;但是,有事会出现日志填满了,但是日志内容还没来的急同步到磁盘上,还有新的日志需要写进来,那么久在启动一个文件;也就是说日志文件一般启动2个或3个是轮转使用的,所谓轮转指的是第一个日志文件填满了就用第二个,同时把第一个日志文件同步到磁盘上,等第二个日志写满了就可以再使用第一个了,这样轮转使用,由多个事务日志文件组成的叫做事务日志组,日志组内至少应该有2个文件,但是多了同样不好。
事务日志文件和数据文件不应该放在同一磁盘上,因为会对磁盘写IO操作带来很大压力,影响其性能;分开存放比较理想,但是有些场景又要必须放在一起,例如基于逻辑卷操作时;
如果事务日志所在磁盘崩溃,则数据库数据无法保持一致;所以,要把事务日志磁盘做镜像;建议使用raid1;数据文件也很重要建议使用raid10;
* 事务:一组原子性的SQL查询,或者多个SQL语句组成了一个独立的工作单元
* 事务日志:将随机写转换为顺序写
`innodb_log_files_in_group`:一个日志组内有多少个日志文件,默认2个;
`innodb_log_group_home_dir`:日志组目录路径,当前目录就是datadir指定的路径
`innodb_log_file_size`:每一个InnoDB事务日志的大小,默认5M
`innodb_mirrored_log_groups`
修改配置文件,重启生效;这些参数,建议在mysql初始化时就要设置好再启动,而不能在启动后再修改参数是不理想的做法;
* ACID测试:从四个角度判断存储引擎是否支持事务
* A:automicity,原子性;整个事务中的所有操作要么全部成功执行,要么全部失败后回滚;
* C:consistency,一致性;数据库总是从一个一致性状态转换为另一个一致性状态;
* I:isolation,隔离性;一个事务所做出的操作在提交之前,是不能为其它事务所见的,隔离有多种级别,主要是为了并发,隔离级别一个有4个;
* D:durability,持久性;事务一旦提交,其所做的修改就会永久保存于数据库中;
注意:MyISAM存储引擎是不支持事务的,InnoDB支持事务,所以要想使用事务得确保使用的是InnoDB等支持事务的存储引擎;
* mysql默认把每个语句当做一个事务提交,可以手动关闭自动提交功能,手动来启动事务;
~~~css
启动事务:START TRANSACTION
结束事务:
(1)完成,提交:COMMIT
(2)未完成,回滚:ROLLBACK
回滚时如果做过时间点保存可以一点点回滚;
事务支持savepoint
SAVEPINIT identifier;设置保存点
ROLLBACK TO [SAVEPOINT] identifier;回滚到指定保存点,默认回滚到最开始处
RELEASE SAVEPOINT identifier;释放保存点
~~~
* * *
~~~ruby
示例:
查看是否开启自动提交:
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%commit%';
+-------------------------------------------+-------+
| Variable_name | Value |
+-------------------------------------------+-------+
| aria_group_commit | none |
| aria_group_commit_interval | 0 |
| autocommit | ON |
| innodb_commit_concurrency | 0 |
| innodb_flush_log_at_trx_commit | 1 |
| innodb_use_global_flush_log_at_trx_commit | ON |
+-------------------------------------------+-------+
autocommit=ON:自动提交,把每一个执行的语句当做一个事务,执行语句就提交,因为每一次事务提交都会导致数据要从事务日志缓冲区写到事务日志,随后还要从事务日志写到数据文件;这很可能会影响性能,而且很多时候多个语句才是一个事务;
因此可以使用set修改变量,关闭自动提交功能;
MariaDB [(none)]> SET @@SESSION.autocommit=OFF; #修改session级别的参数,关闭自动提交
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SHOW VARIABLES LIKE 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit | OFF |
+---------------+-------+
示例:
手动启动事务:
MariaDB [(none)]> START TRANSACTION;
MariaDB [(none)]> use testdb;
Database changed
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
+----+-------+
2 rows in set (0.00 sec)
MariaDB [testdb]> INSERT INTO tbl (id,name) VALUE (3,'LUCY');
Query OK, 1 row affected (0.01 sec)
MariaDB [testdb]> UPDATE tbl SET name='guojing' WHERE id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [testdb]> SELECT * FROM tbl;
+----+---------+
| id | name |
+----+---------+
| 1 | guojing |
| 2 | JERRY |
| 3 | LUCY |
+----+---------+
3 rows in set (0.00 sec)
MariaDB [testdb]> ROLLBACK; #手动回滚,结束事务
Query OK, 0 rows affected (0.01 sec)
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
+----+-------+
2 rows in set (0.00 sec)
示例2:
MariaDB [testdb]> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> INSERT INTO tbl VALUE (3,'LUCK'),(4,'MURNN');
Query OK, 2 rows affected (0.02 sec)
Records: 2 Duplicates: 0 Warnings: 0
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
+----+-------+
4 rows in set (0.00 sec)
MariaDB [testdb]> SAVEPOINT first; #做时间点,名称为first
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> UPDATE tbl SET name='guojing' WHERE id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
MariaDB [testdb]> SAVEPOINT second; #做第二个时间保存点,名称为second
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> INSERT INTO tbl VALUE (5,'HAHA');
Query OK, 1 row affected (0.00 sec)
MariaDB [testdb]> SELECT * FROM tbl;
+----+---------+
| id | name |
+----+---------+
| 1 | guojing |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
| 5 | HAHA |
+----+---------+
5 rows in set (0.00 sec)
MariaDB [testdb]> ROLLBACK TO second; #回滚到第二个保存点
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> SELECT * FROM tbl;
+----+---------+
| id | name |
+----+---------+
| 1 | guojing |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
+----+---------+
4 rows in set (0.00 sec)
MariaDB [testdb]> ROLLBACK TO first; #回滚到第一个保存点
Query OK, 0 rows affected (0.00 sec)
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
+----+-------+
4 rows in set (0.00 sec)
MariaDB [testdb]> COMMIT; 手动提交,结束事务
Query OK, 0 rows affected (0.01 sec)
~~~
* * *
**建议:手动显示请求和提交事务,不要使用自动提交功能**
#### 事务的隔离级别:
由低到高,分为4个级别:
* 第一级别:read-uncommitted;读未提交--> 会存在脏读;
看到数据可能是未提交的,别人回滚后,看到的数据不准确;
* 第二级别:read-committed;读提交--> 会产生不可重复读;
只有别人提交后才能看到数据,解决了脏读;
不可重复读,指的是同一事务中两次读取同一数据得到内容不一样;就是别人没提交时读到的内容,别人修改数据提交后又读到的,两次读取的结果不同;这就叫不可重复读;
* 第三级别:repeatable-read;可重读--> 会产生幻读;默认级别;
两次读取数据,只要自己没提交,不管别人提没提交,自己做一快照,如果启动事务时有三行数据,读的过程中只要自己不提交只有三行数据,但是,外衣别的事务提交了数据,例如新增了几个行,那几行明明在,但自己假装看不见,产生幻读;
* 第四级别:serializable;可串行化--> 性能较差;
如果别人没提交,读的数据是别人没提交的,要等待别人的事务完成才能读取到,有先有后,避免了幻读;
~~~ruby
查看默认事务隔离级别:
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%tx%';
+---------------+-----------------+
| Variable_name | Value |
+---------------+-----------------+
| tx_isolation | REPEATABLE-READ |
+---------------+-----------------+
设置隔离级别:
MariaDB [(none)]> SET @@global.tx_isolation='READ-COMMITTED';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SHOW GLOBAL VARIABLES LIKE '%tx%';
+---------------+----------------+
| Variable_name | Value |
+---------------+----------------+
| tx_isolation | READ-COMMITTED |
+---------------+----------------+
1 row in set (0.00 sec)
查看InnoDB存储引擎的状态信息:
MariaDB [testdb]> SHOW ENGINE innodb STATUS\G;
~~~
MySQL是通过MVCC机制来实现事务隔离级别控制的;为什么启动2个事务,基于PREPEATABLE-READ 隔离级别修改数据但还能看到之前的数据,就是因为自己启动了一个快照,而快照功能的创建,删除等等都是由事务功能mysql服务器自动在服务器级别进行管理的
~~~ruby
示例:两个线程,分别验证各个事务隔离级别的效果
(1)演示读未提交,两个线程控制台均设置事务隔离级别为读未提交,并关闭事务自动提交功能
MariaDB [testdb]> SET @@SESSION.tx_isolation='READ-UNCOMMITTED';
Query OK, 0 rows affected (0.00 sec)
MariaDB [(none)]> SET @@SESSION.autocommit=OFF;
Query OK, 0 rows affected (0.00 sec)
两边同时启动事务:
MariaDB [(none)]> START TRANSACTION;
线程1查看:
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
+----+-------+
4 rows in set (0.00 sec)
线程2插入数据:
MariaDB [testdb]> INSERT INTO tbl VALUE (5,'haha');
Query OK, 1 row affected (0.00 sec)
线程1再查看:
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
| 5 | haha |
+----+-------+
5 rows in set (0.00 sec)
线程2:回滚,结束事务:
MariaDB [testdb]> ROLLBACK;
Query OK, 0 rows affected (0.01 sec)
线程1再查看:
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
+----+-------+
4 rows in set (0.00 sec)
MariaDB [testdb]> COMMIT; #提交结束事务
Query OK, 0 rows affected (0.00 sec)
~~~
* * *
~~~ruby
示例:演示读提交
两个线程都改为读提交,并启动事务:
MariaDB [testdb]> SET @@SESSION.tx_isolation='READ-COMMITTED';
MariaDB [testdb]> START TRANSACTION;
线程1启动查询:
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
+----+-------+
4 rows in set (0.01 sec)
线程2插入数据未提交:
MariaDB [testdb]> INSERT INTO tbl VALUE (5,'haha');
Query OK, 1 row affected (0.02 sec)
线程1再查看数据未变化:
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
+----+-------+
4 rows in set (0.00 sec)
线程2提交事务:
MariaDB [testdb]> COMMIT;
Query OK, 0 rows affected (0.02 sec)
线程1再查看,数据发生变化
MariaDB [testdb]> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | MURNN |
| 5 | haha |
+----+-------+
5 rows in set (0.00 sec)
MariaDB [testdb]> COMMIT; #提交事务
~~~
* * *
~~~ruby
示例:演示幻读,可重复读
两个线程都修改事务级别为可重复读,并启动事务:
mysql> SHOW GLOBAL VARIABLES LIKE '%iso%';
+-----------------------+-----------------+
| Variable_name | Value |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)
mysql> SET @@SESSION.autocommit=OFF;
Query OK, 0 rows affected (0.02 sec)
线程1查看:
mysql> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | HAHA |
+----+-------+
4 rows in set (0.00 sec)
线程2删除1行(未提交):
mysql> DELETE FROM tbl WHERE id=2;
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM tbl;
+----+------+
| id | name |
+----+------+
| 1 | TOM |
| 3 | LUCK |
| 4 | HAHA |
+----+------+
3 rows in set (0.00 sec)
线程1查看,未发生变化:
mysql> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | HAHA |
+----+-------+
4 rows in set (0.00 sec)
线程2提交:
mysql> COMMIT;
Query OK, 0 rows affected (0.07 sec)
线程1再查看,扔然未变化:
mysql> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 2 | JERRY |
| 3 | LUCK |
| 4 | HAHA |
+----+-------+
4 rows in set (0.00 sec)
线程1提交事务后再查看数据发生变化:
mysql> COMMIT;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM tbl;
+----+------+
| id | name |
+----+------+
| 1 | TOM |
| 3 | LUCK |
| 4 | HAHA |
+----+------+
3 rows in set (0.00 sec)
~~~
* * *
~~~ruby
示例:演示可串行化
2个线程都设置事务隔离级别可串行化:
mysql> SET @@SESSION.transaction_isolation='SERIALIZABLE';
线程1查看:
mysql> SELECT * FROM tbl;
+----+-------+
| id | name |
+----+-------+
| 1 | TOM |
| 3 | LUCK |
| 4 | HAHA |
| 2 | JERRY |
+----+-------+
4 rows in set (0.00 sec)
线程2启动事务,并插入数据:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> INSERT INTO tbl VALUE (5,'HUANG RONG');
Query OK, 1 row affected (18.31 sec)
线程1启动事务并查看,被阻塞:
mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT * FROM tbl;
线程2提交事务:
mysql> COMMIT;
Query OK, 0 rows affected (0.03 sec)
线程1查看:
mysql> SELECT * FROM tbl;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
mysql> SELECT * FROM tbl;
+----+------------+
| id | name |
+----+------------+
| 1 | TOM |
| 3 | LUCK |
| 4 | HAHA |
| 2 | JERRY |
| 5 | HUANG RONG |
+----+------------+
5 rows in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
~~~
- php开发
- 常用技巧
- 字符数组对象
- php换行替换,PHP替换回车换行符的三种方法
- PHP 数组转字符串,与字符串转数组
- php将img中的宽高删除,PHP删除HTML中宽高样式的详解
- php去除换行(回车换行)的三种方法
- php 过滤word 样式
- php如何设置随机数
- 2个比较经典的PHP加密解密函数分享
- php怎么去除小数点后多余的0
- php中判断是一维数组还是二维数组的解决方案
- php 获取数组中出现次数最多的值(重复最多的值)与出现的次数
- PHP过滤掉换行符、特殊空格、制表符等
- PHP中json_endoce转义反斜杠的问题
- PHP过滤Emoji表情和特殊符号的方法
- PHP完美的提取链接正则
- php很牛的图片采集
- 日期处理
- php 获取今日、昨日、上周、本月的起始时间戳和结束时间戳的方法非常简单
- PHP指定时间戳/日期加一天,一年,一周,一月
- 使用php 获取时间今天明天昨天时间戳的详解
- php获得当月的节假日函数(包含周末,年度节假日)
- PHP获取本月起始和截止时间戳
- php 获取每月开始结束时间,php 获取指定月份的开始结束时间戳
- PHP获取今天,昨天,本月,上个月,本年 起始时间戳
- php、mysql查询当天,本周,本月的用法
- php获取两个时间戳之间相隔多少天多少小时多少分多少秒
- 毫秒级时间戳和日期格式转换
- php-倒计时
- 请求提交上传
- php+put+post,Curl和PHP-如何通过PUT,POST,GET通过curl传递json
- PHP put提交和获取数据
- PHP curl put方式上传文件
- 数据导入导出
- PHP快速导入大量数据到数据库的方法
- PHP快速导出百万级数据到CSV或者EXCEL文件
- PHP解析大型Excel表格的库:box/spout
- PHP导入(百万级)Excel表格数据
- PHP如何切割excel大文件
- 使用 PHP_XLSXWriter 代替 PHPExcel 10W+ 数据秒级导出
- 安装php扩展XLSXWriter
- 解决php导入excel表格时获取日期变成浮点数的方法
- xml处理
- PHP XML和数组互相转换
- php解析xml字符串
- php 生成vcf通讯录
- 文件操作相关
- php获取文件后缀的9种方法
- PHP判断远程文件是否存在
- PHP获取文件修改时间,访问时间,inode修改时间
- php获取远程文件大小教程
- php 读取文件并以文件方式下载
- php 把数字转化为大写中文
- 请求响应
- PHP 获取当前访问的URL
- 压缩
- php生成zip压缩包
- PHPMailer
- 整理PHPMailer 发送邮件 邮件内容为html 可以添加多个附件等
- 通达oa
- OA管理员密码忘了怎么办,这里教你分分钟搞定…
- 跨域
- php解决多站点跨域
- php设置samesite cookie,有效防止CSRF
- Chrome 配置samesite=none方式
- Cookie 的 SameSite 属性
- 图片
- php pdf首页截图,PHP_PHP中使用Imagick读取pdf并生成png缩略图实例,pdf生成png首页缩略图
- PHP -- 七牛云 在线视频 获取某一帧作为封面图
- PHP图片压缩方法
- 如何解决PHP curl或file_get_contents下载图片损坏或无法打开的问题
- php远程下载文章中图片并保存源文件名不变
- 详解PHP如何下载采集图片到本地(附代码实例)
- php如何将webp格式图片转为jpeg
- PHP获取远程图片的宽高和体积大小
- php 软件版本号比较
- 使用PHP通过SMTP发送电邮
- 常用正则表达式
- php如何用正则表达式匹配中文
- 用于分割字符串的 PHP preg_match_all 正则表达式
- 性能优化
- php.ini配置调优
- PHP 几种常见超时的设置方法
- PHP函数in_array、array_key_exists和isset效率分析
- php array push 和array_merge 效率谁高,php 通过array_merge()和array+array合并数组的区别和效率比较...
- php 两个数组取交集、并集、差集
- 设置PHP最大连接数及php-fpm 高并发 参数调整
- 小工具
- php 获取代码执行时间和消耗的内存
- PHP如何判断某项扩展是否开启
- centos7.x下php 导出扩展 XLSXWriter 安装
- php生成mysql数据库字典
- PHP 实现 word/excel/ppt 转换为 PDF
- composer的使用
- showdoc sqlite3 找回管理员密码
- php怎么将数组转为xml
- PHP抖音最新视频提取代码
- yii
- Yii2 如何获取Header参数?
- swoole
- Linux下搭建swoole服务的基本步骤
- 相关学习资料
- 带你学习swoole_process详解
- 按照官方文档 在win10下安装 docker for windows easyswoole镜像 挂载目录
- php常用框架
- Hyperf
- 常用算法PHP版
- thinkphp6
- TP6 事件绑定、监听、订阅
- Thinkphp 模板中输出HTML的变量
- Thinkphp6(操作SQL数据库)
- thinkphp6 mysql查询语句对于为null和为空字符串给出特定值处理
- Thinkphp 6 - 连接配置多个数据库并实现自由切换(详细过程及实例demo)
- TP框架中的Db::name 和 dB::table 以及 db('') 的区别
- thinkphp6.0模型篇之模型的软删除
- thinkphp6自定义日志驱动,增加显示全部请求信息
- 其他系统
- 微擎数据库字段字典
- Flutter实现微信支付和iOS IAP支付
- Flutter上线项目实战——苹果内购
- PHP接入苹果支付
- 调试
- php如何获取当前脚本所有加载的文件
- php跟踪所有调用方法,日志方法
- 解析phpstorm + xdebug 远程断点调试
- PHP XDEBUG调试 PHPSTORM配置
- 异常处理
- PHP 出现 502 解决方案
- php 语法解析错误 syntax error unexpected namespace T_NAMESPACE
- Composer 安装与使用
- 数据库相关
- php pdo怎么设置utf8
- php 如何根据最新聊天对用户进行排序
- php lic&fpm
- 让php程序在linux后台执行
- PHPcli模式和fpm模式优缺点在哪里?
- 运行模式
- php运行模式之cli模式
- 自己库
- php批量获取所有公众号粉丝openid
- 地图
- php 判断点在多边形内,php百度地图api判断地址是否在多边形区域内
- PHP,Mysql-根据一个给定经纬度的点,进行附近地点查询
- MySQL 根据经纬度查找排序
- PHP+MySQL获取坐标范围内的数据
- 【百度地图】删除指定覆盖物
- 百度地图多点+画连接线+数字标注
- laravel5.8
- laravel5.8(四)引入自定义常量文件及公共函数文件
- Lumen 查询执行SQL
- 使你的 Laravel 项目模块化
- Laravel 多条件 AND , OR条件组合查询
- Laravel 查询 多个or或者and条件
- laravel redis操作大全
- laravel中外部定义whereIn的用法和where中使用in
- lumen5.8
- 创建laravel5.8 lumen前后台api项目--记录请求和响应日志
- Laravel和Lumen开启SQL日志记录
- Laravel 5.8 常用操作(路径+日志+分页+其他操作)
- 升级php7.4 laravel lumen报错Trying to access array offset on value of type null
- Laravel 任务调度(计划任务,定时任务)
- laravel的command定时任务时间的设置
- Laravel任务调度的简单使用
- laravel单数据库执行事务和多数据库执行事务
- laravel中锁以及事务的简单使用
- 申请其他相关
- 小程序地理位置接口申请
- PHP高并发
- php 高并发下 秒杀处理思路
- 记录 PHP高并发 商品秒杀 问题的 Redis解决方案
- thinkphp3.2
- thinkphp3.2 数据库 AND OR连缀使用
- laravel
- laravel的联表查询with方法的使用
- laravel获取请求路由对应的控制器和方法
- Laravel 模型关联建立与查询
- Laravel多表(3张表以上)with[]关联查询,对关联的模型做条件查询(has,跟join一样结果 )
- Laravel模型属性的隐藏属性、显示属性和临时暴露隐藏属性用法介绍
- aravel获取当前的url以及当前的基础域名方法汇总
- Laravel 模型实现多库查询或者多表映射
- 关于 Laravel 的 with 多表查询问题
- Laravel 模型过滤(Filter)设计
- 懒加载、预加载、with()、load() 傻傻分不清楚?
- laravel模型$castsl属性
- Laravel Query Builder 复杂查询案例:子查询实现分区查询 partition by
- Laravel 模型关联、关联查询、预加载使用实例
- laravel 中with关联查询限定查询字段
- laravel 原生字段查询 whereRaw 和 where(DB::raw(''))
- lavarel - where条件分组查询(orWhere)
- 通过 Laravel 查询构建器实现复杂的查询语句
- 两个结果集合并成一个
- Laravel 对某一列进行筛选然后求和 sum()
- laravel怎么优雅的拼接where,处理whereIn与where数组查询的问题
- laravel查询时判断是否存在数据
- laravel中的whereNull和whereNotNull
- laravel框架中的子查询
- Laravel框架中 orwhere 多条件查询的使用
- Laravel中where的高级使用方法
- laravel复杂的数据库查询(事例)
- laravel多条件查询方法(and,or嵌套查询)
- Laravel 的 where or 查询
- Laravel 进行where 多个or和and的条件查询可用
- laravel Middleware 中间件 $next($request) 报错不执行问题
- 数据库
- mysql
- mysql联合索引(复合索引)详解
- MYSQL 清空表和截断表
- MySQL快速生成大量测试数据(100万、1000万、1亿)
- 提高mysql千万级大数据SQL查询优化30条经验(Mysql索引优化注意)
- MySQL常用命令
- MySQL(三)|《千万级大数据查询优化》第一篇:创建高性能的索引
- MySQL(一)|性能分析方法、SQL性能优化和MySQL内部配置优化
- MySQL(二)|深入理解MySQL的四种隔离级别及加锁实现原理
- MySQL(四)|《千万级大数据查询优化》第一篇:创建高性能的索引(补充)
- MySQL(五)|《千万级大数据查询优化》第二篇:查询性能优化(1)
- MySQL(六)|《千万级大数据查询优化》第二篇:查询性能优化(2)
- MySQL(七)|MySQL分库分表的那点事
- Mysql索引优化 Mysql通过索引提升查询效率(第二棒)
- MySQL查询的性能优化(查询缓存、排序跟索引)
- 【总结】MySQL数据库
- MySQL存储引擎、事务日志并发访问以及隔离级别
- 技巧
- 数据库 SQL查询重复记录 方法
- 替换数据库中某个字段中的部分字符
- mysql开启bin log 并查看bin log日志(linux)
- 分表分区
- 千万级别数据的mysql数据表优化
- MYSQL百万级数据,如何优化
- MySQL备份和恢复
- MySQL间隙锁死锁问题
- 小技巧
- 基础
- MySQL中sql_mode参数
- mysql数据库异常
- this is incompatible with sql_mode=only_full_group_by
- mysql安全
- MySQL数据库被比特币勒索及安全调整
- MongoDB
- sql查询
- MYSQL按时间段分组查询当天,每小时,15分钟数据分组
- 高级
- 基于 MySQL + Tablestore 分层存储架构的大规模订单系统实践-架构篇
- 数据库安全
- 服务器被黑,MySQL 数据库遭比特币勒索!该如何恢复?
- 数千台MySQL数据库遭黑客比特币勒索,该怎么破?
- MySQL 数据库规范
- MySQL数据库开发的36条铁律
- Elasticsearch
- 安装与配置
- ElasticSearch关闭重启命令
- 设置ES默认分词器IK analyzer
- 查询
- elasticsearch 模糊查询不分词,实现 mysql like
- elasticSearch多条件高级检索语句,包含多个must、must_not、should嵌套示例,并考虑nested对象的特殊检索
- elasticSearch按字段普通检索,结果高亮
- Elasticsearch 如何实现查询/聚合不区分大小写?
- 索引更新&刷新
- refresh与批量操作的效率
- Elasticsearch 删除type
- 分词器
- ElasticSearch最全分词器比较及使用方法
- 异常错误
- 解决ES因内存不足而无法查询的错误,Data too large, data for [<http_request>]
- linux
- 基本知识
- CentOS7.5 通过wget下载文件到指定目录
- 【CentOS】vi命令
- centos7查看硬盘使用情况
- CentOS7 查看目录大小
- Centos 7下查看当前目录大小及文件个数
- 普通用户sudo\su 到root免密码
- 普通用户切换到root用户下的免密配置方法
- linux 获取进程启动参数,linux查看进程启动及运行时间
- Linux 查看进程
- linux删除文件后不释放磁盘的问题
- Linux查找大文件命令
- linux 如何关闭正在执行的php脚本
- linux三剑客(grep、sed、awk)基本使用
- centos 卸载软件
- centos查看内存、cpu占用、占用前10,前X
- Centos 查看系统状态
- 异常
- 问题解决:Failed to download metadata for repo ‘appstream‘: Cannot prepare internal mirrorlist:...
- php相关
- centos 安装phpize
- Centos7.2下phpize安装php扩展
- 切换版本
- 运营工具
- 资深Linux运维工程师常用的10款软件/工具介绍
- 一款良心的终端连接工具
- 六款Linux常用远程连接工具介绍,看看哪一款最适合你
- Finalshell
- Linux Finalshell连接centos7和文件无显示问题
- WSL2:我在原生的Win10玩转Linux系统
- MobaXterm
- 运维
- linux服务器上定时自动备份数据库,并保留最新5天的数据
- Centos系统开启及关闭端口
- CentOS7开放和关闭端口命令
- Linux中查看所有正在运行的进程
- 防火墙firewall-cmd命令详解
- centos 7.8阿里云服务器挂载 数据盘
- Linux Finalshell连接centos7和文件无显示问题
- Centos7系统端口被占用问题的解决方法
- vi
- 如何在Vim/Vi中复制,剪切和粘贴
- 命令
- [Linux kill进程] kill 进程pid的使用详解
- 备份还原
- Linux的几种备份、恢复系统方式
- Linux系统全盘备份方法
- 相关软件安装
- linux下 lua安装
- python
- 升级pip之后出现sys.stderr.write(f“ERROR: {exc}“)
- lua
- centos源码部署lua-5.3
- deepin
- deepin20.6设置默认的root密码
- 任务相关
- 宝塔定时任务按秒执行
- CentOS 7 定时任务 crontab 入门
- centos7定时任务crontab
- Linux下定时任务的查看及取消
- Linux(CentOS7)定时执行任务Crond详细说明
- Linux 查看所有定时任务
- linux查看所有用户定时任务
- Linux 定时任务(超详细)
- 防火墙
- Centos7开启防火墙及特定端口
- CentOS防火墙操作:开启端口、开启、关闭、配置
- 生成 SSH 密钥(windows+liunx)
- 阿里云,挂载云盘
- 前端
- layui
- layui多文件上传
- layer.msg()弹框,弹框后继续运行
- radio取值
- layui-数据表格排序
- Layui select选择框添加搜索选项功能
- 保持原来样式
- layui表格单元如何自动换行
- layui-laydate时间日历控件使用方法详解
- layui定时刷新数据表格
- layer 延时设置
- layer.open 回调函数
- 【Layui内置方法】layer.msg延时关闭msg对话框(代码案例)
- layui多图上传图片顺序错乱及重复上传解决
- layer.confirm关闭弹窗
- vue
- Vue跨域解决方法
- vue 4.xx.xx版本降级至2.9.6
- vue-cli 2.x升级到3.x版本, 和3.x降级到2.x版本命令
- 最新版Vue或者指定版本
- Vue2.6.11按需模块安装配置
- jQuery
- jQuery在页面加载时动态修改图片尺寸的方法
- jquery操作select(取值,设置选中)
- 日历
- FullCalendar中文文档:Event日程事件
- js
- JS 之 重定向
- javascript截取video视频第一帧作为封面方案
- HTML <video> preload 属性
- jQuery使用ajax提交post数据
- JS截取视频靓丽的帧作为封面
- H5案例分享:移动端touch事件判断滑屏手势的方向
- JS快速获取图片宽高的方法
- win
- Windows环境下curl的使用
- Cygwin
- Windows下安装Cygwin及apt-cyg
- Cygwin 安装、CMake 安装
- mklink命令 详细使用
- Nginx
- Nginx高级篇-性能优化
- Nginx常用命令(Linux)
- linux+docker+nginx如何配置环境并配置域名访问
- Nginx的启动(start),停止(stop)命令
- linux 查看nginx 安装路径
- 安装配置
- Linux 查看 nginx 安装目录和配置文件路径
- 【NGINX入门】3.Nginx的缓存服务器proxy_cache配置
- thinkphp6.0 伪静态失效404(win下)
- 深入
- nginx rewrite及多upstream
- Nginx负载均衡(upstream)
- 专业术语
- 耦合?依赖?耦合和依赖的关系?耦合就是依赖
- PHP常用六大设计模式
- 高可用
- 分布式与集群
- Nginx 实践案例:反向代理单台web;反向代理多组web并实现负载均衡
- 容器
- Docker
- 30 分钟快速入门 Docker 教程
- linux查看正在运行的容器,说说Docker 容器常用命令
- Windows 安装Docker至D盘
- 配置
- win10 快速搭建 lnmp+swoole 环境 ,部署laravel6 与 swoole框架laravel-s项目1
- win10 快速搭建 lnmp+swoole 环境 ,部署laravel6 与 swoole框架laravel-s项目2
- docker 容器重命名
- Linux docker常用命令
- 使用
- docker 搭建php 开发环境 添加扩展redis、swoole、xdebug
- docker 单机部署redis集群
- Docker 退出容器不停止容器运行 并重新进入正在运行的容器
- 进入退出docker容器
- Docker的容器设置随Docker的启动而启动
- 使用异常处理
- docker容器中bash: vi: command not found
- OCI runtime exec failed: exec failed:解决方法
- docker启动容器慢,很慢,特别慢的坑
- 解决windows docker开发thinkphp6启动慢的问题
- 【Windows Docker】docker挂载解决IO速度慢的问题
- Docker的网络配置,导致Docker使用网路很慢的问题及解决办法
- golang工程部署到docker容器
- Docker 容器设置自启动
- 如何优雅地删除Docker镜像和容器(超详细)
- 5 个好用的 Docker 图形化管理工具
- Docker 可能会用到的命令
- Kubernetes
- 消息队列
- RabbitMQ
- php7.3安装使用rabbitMq
- Windows环境PHP如何使用RabbitMQ
- RabbitMQ学习笔记:4369、5672、15672、25672默认端口号修改
- Window10 系统 RabbitMQ的安装和简单使用
- RabbitMQ默认端口
- RabbitMQ可视化界面登录不了解决方案
- RocketMQ
- Kafka
- ActiveMQ
- mqtt
- phpMQTT详解以及处理使用过程中内存耗死问题
- MQTT--物联网(IoT)消息推送协议
- php实现mqtt发布/发送 消息到主题
- Mqtt.js 的WSS链接
- emqx
- 如何在 PHP 项目中使用 MQTT
- emqx 修改dashboard 密码
- 其他
- Windows 系统中单机最大TCP的连接数详解
- EMQX
- Linux系统EMQX设置开机自启
- Centos7 EMQX部署
- docker安装 EMQX 免费版 docker安装并配置持久化到服务器
- 实时数仓
- 网易云音乐基于 Flink + Kafka 的实时数仓建设实践
- 实时数仓-基于Flink1.11的SQL构建实时数仓探索实践
- 安全
- 网站如何保护用户的密码
- 关于web项目sessionID欺骗的问题
- php的sessionid可以伪造,不要用来做防刷新处理了
- DVWA-Weak Session IDs (弱会话)漏洞利用方式
- 保证接口数据安全的10种方案
- cookie和session的窃取
- 万能密码漏洞
- 黑客如何快速查找网站后台地址方法整理
- 网站后台万能密码/10大常用弱口令
- 万能密码漏洞02
- 大多数网站后台管理的几个常见的安全问题注意防范
- token可以被窃取吗_盗取token
- token被劫持[token被劫持如何保证接口安全性]
- PHP给后台管理系统加安全防护机制的一些方案
- php - 重新生成 session ID
- 隐藏响应中的server和X-Powered-By
- PHP会话控制之如何正确设置session_name
- Session攻击001
- PHP防SQL注入代码,PHP 预防CSRF、XSS、SQL注入攻击
- php25个安全实践
- php架构师 系统管理员必须知道的PHP安全实践
- 版本控制
- Linux服务器关联Git,通过执行更新脚本实现代码同步
- PHP通过exec执行git pull
- git 在linux部署并从windows上提交代码到linux
- git上传到linux服务器,git一键部署代码到远程服务器(linux)
- linux更新git命令,使用Linux定时脚本更新服务器的git代码
- git異常
- 如何解决remote: The project you were looking for could not be found
- git status显示大量文件修改的原因是什么
- PHPstorm批量修改文件换行符CRLF为LF
- git使用
- git常用命令大全
- centos git保存账户密码
- GIT 常用命令
- git怎样还原修改
- Git 如何放弃所有本地修改的方法
- Git忽略文件模式改变
- git: 放弃所有本地修改
- Git三种方法从远程仓库拉取指定的某一个分支
- 杂七杂八
- h5视频
- H5浏览器支持播放格式:H264 AVCA的MP4格式,不能转换为mpeg-4格式,
- iOS无法播放MP4视频文件的解决方案 mp4视频iphone播放不了怎么办
- h5点播播放mp4视频遇到的坑,ios的h5不能播放视频等
- 【Linux 并发请求数】支持多少并发请求数
- Linux下Apache服务器并发优化
- 缓存
- redis
- Linux启动PHP的多进程任务与守护redis队列
- 重启redis命令
- golang