当前位置: 首页 > news >正文

MySQL 用户管理

重点:

视图,函数,存储过程,触发器,事件( 了解 )

用户管理,密码管理

grant revoke 权限管理

MySQL 架构( 了解 )

存储引擎:MyISAM 和 InnoDB 的区别( 重点 )

MVCC 工作机制( 了解 )

索引 B+Tree 结构

管理索引,创建索引

explain profile

锁机制,事务 ACID 特性

事务隔离级别

事务日志,错误日志

3.8)VIEW 视图

视图:虚拟表,保存有实表的查询结果,相当于别名。

利用视图,可以隐藏表的真实结构,在程序中利用视图进行查询,可以避免表结构的变化,而修改程序,降低程序和数据库之间的耦合度。

官方定义:视图是指计算机数据库中的视图,是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。

创建方法:

// 创建视图CREATE VIEW view_name [(column_list)]AS select_statement[WITH [CASCADED | LOCAL] CHECK OPTION]

查看视图定义:

SHOW CREATE VIEW view_name     # 只能看视图定义SHOW CREATE TABLE view_name    # 可以查看表和视图

删除视图:

// 删除视图DROP VIEW [IF EXISTS]view_name [, view_name] ...[RESTRICT | CASCADE]

注意:视图中的数据事实上存储于 "基表" 中,因此,其修改操作也会针对基表实现;其修改操作受基表限制

范例:

// 由于多表查询的命令很长MariaDB [hellodb]> select st.name,co.Course,sc.score from students st inner join scores sc on st.stuid=sc.stuid inner join courses co on sc.courseid=co.CourseID;+-------------+----------------+-------+| name        | Course         | score |+-------------+----------------+-------+| Shi Zhongyu | Kuihua Baodian |    77 || Shi Zhongyu | Weituo Zhang   |    93 || Shi Potian  | Kuihua Baodian |    47 || Shi Potian  | Daiyu Zanghua  |    97 || Xie Yanke   | Kuihua Baodian |    88 || Xie Yanke   | Weituo Zhang   |    75 || Ding Dian   | Daiyu Zanghua  |    71 || Ding Dian   | Kuihua Baodian |    89 || Yu Yutong   | Hamo Gong      |    39 || Yu Yutong   | Dagou Bangfa   |    63 || Shi Qing    | Hamo Gong      |    96 || Xi Ren      | Hamo Gong      |    86 || Xi Ren      | Dagou Bangfa   |    83 || Lin Daiyu   | Taiji Quan     |    57 || Lin Daiyu   | Jinshe Jianfa  |    93 |+-------------+----------------+-------+15 rows in set (0.00 sec)// 因此我们可以使用创建视图的方式 ( 简化命令 )// '创建视图' ( 类似将上述命令创建别名 )MariaDB [hellodb]> create view v_st_co_sc as select st.name,co.Course,sc.score from students st inner join scores sc on st.stuid=sc.stuid inner join courses co on sc.courseid=co.CourseID;Query OK, 0 rows affected (0.00 sec)// 视图会默认生成一张虚拟表MariaDB [hellodb]> show tables;+-------------------+| Tables_in_hellodb |+-------------------+| classes           || coc               || courses           || scores            || students          || teachers          || toc               || v_st_co_sc        |                # 创建的视图 ( 也就是一张虚拟表 )+-------------------+8 rows in set (0.00 sec)// 我们可以直接 select 查询该视图内容MariaDB [hellodb]> select * from v_st_co_sc;+-------------+----------------+-------+| name        | Course         | score |+-------------+----------------+-------+| Shi Zhongyu | Kuihua Baodian |    77 || Shi Zhongyu | Weituo Zhang   |    93 || Shi Potian  | Kuihua Baodian |    47 || Shi Potian  | Daiyu Zanghua  |    97 || Xie Yanke   | Kuihua Baodian |    88 || Xie Yanke   | Weituo Zhang   |    75 || Ding Dian   | Daiyu Zanghua  |    71 || Ding Dian   | Kuihua Baodian |    89 || Yu Yutong   | Hamo Gong      |    39 || Yu Yutong   | Dagou Bangfa   |    63 || Shi Qing    | Hamo Gong      |    96 || Xi Ren      | Hamo Gong      |    86 || Xi Ren      | Dagou Bangfa   |    83 || Lin Daiyu   | Taiji Quan     |    57 || Lin Daiyu   | Jinshe Jianfa  |    93 |+-------------+----------------+-------+15 rows in set (0.00 sec)------     // 查看表状态 ( 可以得知该表是视图 )MariaDB [hellodb]> SHOW TABLE STATUS LIKE 'v_st_co_sc'\G*************************** 1. row ***************************Name: v_st_co_scEngine: NULLVersion: NULLRow_format: NULLRows: NULLAvg_row_length: NULLData_length: NULLMax_data_length: NULLIndex_length: NULLData_free: NULLAuto_increment: NULLCreate_time: NULLUpdate_time: NULLCheck_time: NULLCollation: NULLChecksum: NULLCreate_options: NULLComment: VIEW            # 视图Max_index_length: NULLTemporary: NULL1 row in set (0.001 sec)[root@centos8 ~] ls /var/lib/mysql/hellodb/

简单点说就是:视图是一个 sql 的别名,也可以说是个 sql 的封装

够不够简单?

别名大家都知道,张三外号叫 法外狂徒。外号就是别名。

视图能干嘛用,主要用途是什么?

那我们什么时候用到它?都不懂应用场景,我了解他有个 P 用。

他的应用场景大多在于一些复杂的 sql 身上。就好比关联表定义表的别名,然后方便去关联条件。

比如权限管理,用户需要关联角色、权限。那么写 sql 就较长看起来也复杂一点。那使用视图就可以方便去操作,直接调用视图即可查看。

采购人员,可以需要一些与其有关的数据,而与他无关的数据,对没有任何意义,我们可以根据这一实际情况,专门为采购人员创建一个视图.

以后他在查询数据时,只 select * from “{视图名}” 就可以了。( 简单且安全 )

3.9)FUNCTION 函数

函数:分为 系统内置函数 自定义函数

参考:MySQL 函数 | 菜鸟教程

// 系统内置函数参考https://dev.mysql.com/doc/refman/8.0/en/sql-function-reference.htmlhttps://dev.mysql.com/doc/refman/5.7/en/sql-function-reference.html

自定义函数:user-defined function UDF,保存在 mysql.proc( MySQL8.0 中已经取消此表 )表中

举例:

系统内置函数

// version 返回数据库的版本号MariaDB [(none)]> select version();+----------------+| version()      |+----------------+| 5.5.68-MariaDB |+----------------+1 row in set (0.01 sec)// sum 函数返回指定字段的总和// 返回 students 表 age 字段的总和MariaDB [hellodb]> select sum(age) from students;+----------+| sum(age) |+----------+|      685 |+----------+1 row in set (0.00 sec)// count 函数返回查询的记录总数// 整个查询的目的是计算学生表中所有学生的年龄的总和除以学生的总数, 从而得到平均年龄.MariaDB [hellodb]> select sum(age)/count(*) from students; +-------------------+| sum(age)/count(*) |+-------------------+|           27.4000 |+-------------------+1 row in set (0.00 sec)// avg 函数返回一个表达式的平均值MariaDB [hellodb]> select avg(age) from students;+----------+| avg(age) |+----------+|  27.4000 |+----------+1 row in set (0.00 sec)

创建 UDF 语法

CREATE [AGGREGATE] FUNCTION function_name(parameter_name type,[parameter_name type,...])RETURNS {STRING|INTEGER|REAL}runtime_body

说明:

参数可以有多个,也可以没有参数

无论有无参数,小括号()是必须的

必须有且只有一个返回值

查看函数列表

SHOW FUNCTION STATUS;

查看函数定义

SHOW CREATE FUNCTION function_nameq

删除 UDF

DROP FUNCTION function_name

调用自定义函数语法

SELECT function_name(parameter_value,...)

范例:

创建自定义函数

参考:MySQL 自定义函数一文读懂_mysql自定义函数返回结果集-CSDN博客

含义:一组预先编译好的 SQL 语句的集合,理解成批处理语句。

1、提高代码的重用性

2、简化操作

3、减少了编译次数并且减少了和数据库服务器的连接次数,提高了效率。

// 无参 UDFCREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";// 有参数 UDFDELIMITER //CREATE FUNCTION deleteById(id SMALLINT UNSIGNED) RETURNS VARCHAR(20)BEGINDELETE FROM students WHERE stuid = id;RETURN (SELECT COUNT(*) FROM students);END//DELIMITER ;

// 创建自定义函数DELIMITER //CREATE FUNCTION deleteById(id SMALLINT UNSIGNED) RETURNS VARCHAR(20)BEGINDELETE FROM students WHERE stuid = id;RETURN (SELECT COUNT(*) FROM students);END//DELIMITER ;// 查看现有函数列表SHOW FUNCTION STATUS;

使用自定义函数

// 使用 自定义函数select deleteById(23);// 验证数据表select * from students;

范例:MySQL8.0 默认开启二进制不允许创建函数

// 默认 MySQL8.0 开启二进制日志, 而不允许创建函数mysql> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)mysql> select @@log_bin;+-----------+| @@log_bin |+-----------+|         1 |+-----------+1 row in set (0.00 sec)mysql> show variables like 'log_bin_trust_function_creators';+---------------------------------+-------+| Variable_name                   | Value |+---------------------------------+-------+| log_bin_trust_function_creators | OFF   |+---------------------------------+-------+1 row in set (0.00 sec)// 打开此变量允许二进制日志信息函数创建mysql> set global log_bin_trust_function_creators=ON;Query OK, 0 rows affected (0.00 sec)mysql> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";Query OK, 0 rows affected (0.01 sec)mysql> SHOW FUNCTION STATUS like 'simple%'\G*************************** 1. row ***************************Db: hellodbName: simpleFunType: FUNCTIONDefiner: root@localhostModified: 2021-02-01 21:28:41Created: 2021-02-01 21:28:41Security_type: DEFINERComment:character_set_client: utf8mb4collation_connection: utf8mb4_0900_ai_ciDatabase Collation: utf8_general_ci1 row in set (0.00 sec)

范例:Mariadb10.3 默认没有开启二进制日志,所以可以创建函数

// Mariadb 默认没有开启二进制日志, 所以可以创建函数[root@centos8 ~] vim /etc/my.cnf.d/mariadb-server.cnf[mysqld]log-bin[root@centos8 ~] systemctl restart mariadbMariaDB [hellodb]> select @@log_bin;+-----------+| @@log_bin |+-----------+|         1 |+-----------+1 row in set (0.000 sec)// 开启二进制功能后, 也不能创建函数MariaDB [hellodb]> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)MariaDB [hellodb]> show variables like 'log_bin_trust_function_creators';+---------------------------------+-------+| Variable_name                   | Value |+---------------------------------+-------+| log_bin_trust_function_creators | OFF   |+---------------------------------+-------+1 row in set (0.001 sec)// 修改变量允许创建函数MariaDB [hellodb]> set global log_bin_trust_function_creators=ON;Query OK, 0 rows affected (0.000 sec)MariaDB [hellodb]> CREATE FUNCTION simpleFun() RETURNS VARCHAR(20) RETURN "Hello World";Query OK, 0 rows affected (0.000 sec)MariaDB [hellodb]> SHOW FUNCTION STATUS\G*************************** 1. row ***************************Db: hellodbName: simpleFunType: FUNCTIONDefiner: root@localhostModified: 2021-02-01 21:32:23Created: 2021-02-01 21:32:23Security_type: DEFINERComment:character_set_client: utf8collation_connection: utf8_general_ciDatabase Collation: utf8_general_ci1 row in set (0.001 sec)

MySQL 中的变量

两种变量:系统内置变量和用户自定义变量

系统变量:MySQL 数据库中内置的变量,可用 @@var_name 引用

用户自定义变量分为以下两种

普通变量:在当前会话中有效,可用 @var_name 引用

局部变量:在函数或存储过程内才有效,需要用 DECLARE 声明,之后直接用 var_name 引用

自定义函数中定义局部变量语法

DECLARE 变量1[,变量2,... ]变量类型 [DEFAULT 默认值]

说明:局部变量的作用范围是在 BEGIN...END 程序中,而且定义局部变量语句必须在 BEGIN...END 的第一行定义

为变量赋值语法

SET parameter_name = value[,parameter_name = value...]

SELECT INTO parameter_name

范例:

DELIMITER //CREATE FUNCTION addTwoNumber(x SMALLINT UNSIGNED, y SMALLINT UNSIGNED)RETURNS SMALLINTBEGINDECLARE a, b SMALLINT UNSIGNED;SET a = x, b = y;RETURN a+b;END//DELIMITER ;

范例:

.....DECLARE x int;SELECT COUNT(*) FROM tdb_name INTO x;RETURN x;END//

范例:自定义的普通变量

// 方法 1MariaDB [hellodb]> select count(*) from students into @num;// 方法 2MariaDB [hellodb]> select count(*) into @num from students;// 查看变量MariaDB [hellodb]> select @num;+------+| @num |+------+|   24 |+------+1 row in set (0.000 sec)

3.10)PROCEDURE 存储过程

存储过程:多表 SQL 的语句的集合,可以独立执行,存储过程保存在 mysql.proc 表中

存储过程 优势

存储过程把经常使用的 SQL 语句或业务逻辑封装起来,预编译保存在数据库中,当需要时从数据库中直接调用,省去了编译的过程,提高了运行速度,同时降低网络数据传输量。

存储过程与自定义函数的区别

存储过程实现的过程要复杂一些,而函数的针对性较强

存储过程可以有多个返回值,而自定义函数只有一个返回值

存储过程一般可独立执行,而函数往往是作为其他 SQL 语句的一部分来使用

无参数的存储过程执行过程中可以不加 (),函数必须加 ()

创建存储过程

CREATE PROCEDURE sp_name ([ proc_parameter [,proc_parameter ...]])

routime_body

proc_parameter : [IN|OUT|INOUT] parameter_name type

说明:其中 IN 表示输入参数,OUT 表示输出参数,INOUT 表示既可以输入也可以输出;param_name 表示参数名称;type 表示参数的类型。

查看存储过程列表

SHOW PROCEDURE STATUS

查看存储过程定义

SHOW CREATE PROCEDURE sp_name

调用存储过程

说明:当无参时,可以省略 "()",当有参数时,不可省略 "()"

CALL sp_name ([ proc_parameter [,proc_parameter ...]])

存储过程修改

ALTER 语句修改存储过程只能修改存储过程的注释等无关紧要的东西,不能修改存储过程体,所以要修改存储过程,方法就是删除重建。

删除存储过程

DROP PROCEDURE [IF EXISTS] sp_name

范例

// 创建无参存储过程delimiter //CREATE PROCEDURE showTime()BEGINSELECT now();END//delimiter ;CALL showTime;

范例

// 创建含参存储过程: 只有一个 IN 参数// 这个存储过程的作用: 根据传入的学生 ID 从学生表中选择对应的学生记录delimiter //CREATE PROCEDURE selectById(IN id SMALLINT UNSIGNED)BEGINSELECT * FROM students WHERE stuid = id;END//delimiter ;// 执行  call selectById(2);

testlog.sql

create table testlog (id int auto_increment primary key,name char(10),salary int default 20);delimiter $$create procedure sp_testlog()begin  declare i int;set i = 1;while i <= 100000 doinsert into testlog(name,salary) values (concat('wang',FLOOR(RAND() * 100000)),FLOOR(RAND() * 1000000));set i = i +1;end while;end$$delimiter ;

// 列出现有的存储过程SHOW PROCEDURE STATUS;// 执行存储过程call sp_testlog;// 验证select count(*) from testlog;        // 获取表 testlog 中的记录总数select * from testlog limit 10;      // 用于从表 testlog 中选择前 10 条记录

范例

delimiter //CREATE PROCEDURE dorepeat(n INT)BEGINSET @i = 0;SET @sum = 0;REPEAT SET @sum = @sum+@i;SET @i = @i + 1;UNTIL @i > n END REPEAT;END//delimiter ;CALL dorepeat(100);SELECT @sum;

范例

// 创建含参存储过程: 包含 IN 参数和 OUT 参数delimiter //CREATE PROCEDURE deleteById(IN id SMALLINT UNSIGNED, OUT num SMALLINT UNSIGNED)BEGINDELETE FROM students WHERE stuid >= id;SELECT row_count() into num;END//delimiter ;call deleteById(20,@Line);SELECT @Line;// 说明: 创建存储过程 deleteById, 包含一个 IN 参数和一个 OUT 参数.// 调用时, 传入删除的 ID 和保存被修改的行// 数值的用户变量 @Line,select @Line; 输出被影响行数#row_count() 系统内置函数// 用于存放前一条SQL修改过的表的记录数

流程控制

存储过程和函数中可以使用流程控制来控制语句的执行

IF:用来进行条件判断。根据是否满足条件,执行不同语句。

CASE:用来进行条件判断,可实现比IF语句更复杂的条件判断。

LOOP:重复执行特定的语句,实现一个简单的循环。

LEAVE:用于跳出循环控制,相当于 SHELL 中 break。

ITERATE:跳出本次循环,然后直接进入下一次循环,相当于 SHELL 中 continue。

REPEAT:有条件控制的循环语句。当满足特定条件时,就会跳出循环语句。

WHILE:有条件控制的循环语句。

3.11)TRIGGER 触发器

触发器 的执行不是由程序调用,也不是由手工启动,而是由事件来触发、激活从而实现执行。

触发器的工作原理 可以通过一个实例来解释。

假设我们有两张数据库表,一张是 订单表,另一张是 库存表

这两张表都有一个名为 "num" 的字段,代表 数量

当有人下单购买商品时,我们可以 创建一个触发器 来监控订单表中 "num" 字段的新值。一旦有新数据插入,触发器就会自动执行操作,将库存表中相应商品的 "num" 字段值减去订单中的数量。这样,我们就可以确保库存的实时更新,并避免超卖的情况发生。

注意:我们通常不会选择使用 MySQL 服务器来执行触发器。因为 MySQL 服务器承载了大量的处理任务,为了避免过度的负载和效率问题,我们仅将其用于基本的增删改查操作。对于触发器等其他类型的任务,我们更倾向于将其分散到其他服务器上执行,例如 Java 后端应用服务器。这种做法有助于优化系统性能并确保稳定运行。

创建触发器

CREATE [DEFINER = { user | CURRENT_USER }]TRIGGER trigger_nametrigger_time trigger_eventON tbl_name FOR EACH ROWtrigger_body

说明:

trigger_name:触发器的名称

trigger_time:{ BEFORE | AFTER },表示在事件之前或之后触发

trigger_event:{ INSERT |UPDATE | DELETE },触发的具体事件

tbl_name:该触发器作用在表名

范例:

// 创建表CREATE TABLE student_info (stu_id INT(11) NOT NULL AUTO_INCREMENT ,stu_name VARCHAR(255) DEFAULT NULL,PRIMARY KEY (stu_id));// 创建表CREATE TABLE student_count (student_count INT(11) DEFAULT 0);// 学生数量初始值: 0INSERT INTO student_count VALUES(0);// ( 创建触发器 )// 在向学生表 INSERT 数据时, 学生数增加+1CREATE TRIGGER trigger_student_count_insertAFTER INSERTON student_info FOR EACH ROWUPDATE student_count SET student_count=student_count+1;// ( 创建触发器 )// DELETE 学生时, 学生数减少-1CREATE TRIGGER trigger_student_count_deleteAFTER DELETEON student_info FOR EACH ROWUPDATE student_count SET student_count=student_count-1;// 插入数据验证insert student_info(stu_name)values('alice');select * from student_info;select * from student_count;// 插入数据验证insert student_info(stu_name)values('bob');select * from student_count;// 删除数据验证delete from student_info where stu_id >=2;select * from student_info;select * from student_count;[root@centos8 ~] cat /var/lib/mysql/hellodb/trigger_student_count_delete.TRNTYPE=TRIGGERNAMEtrigger_table=student_info[root@centos8 ~] cat /var/lib/mysql/hellodb/trigger_student_count_insert.TRNTYPE=TRIGGERNAMEtrigger_table=student_info[root@centos8 ~] cat /var/lib/mysql/hellodb/student_info.TRG

查看触发器

// 在当前数据库对应的目录下, 可以查看到新生成的相关文件: trigger_name.TRN,table_name.TRGSHOW TRIGGERS;+------------------------------+--------+--------------+--------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+| Trigger                      | Event  | Table        | Statement                                              | Timing | Created | sql_mode | Definer        | character_set_client | collation_connection | Database Collation |+------------------------------+--------+--------------+--------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+| trigger_student_count_insert | INSERT | student_info | UPDATE student_count SET student_count=student_count+1 | AFTER  | NULL    |          | root@localhost | utf8                 | utf8_general_ci      | latin1_swedish_ci  || trigger_student_count_delete | DELETE | student_info | UPDATE student_count SET student_count=student_count-1 | AFTER  | NULL    |          | root@localhost | utf8                 | utf8_general_ci      | latin1_swedish_ci  |+------------------------------+--------+--------------+--------------------------------------------------------+--------+---------+----------+----------------+----------------------+----------------------+--------------------+2 rows in set (0.00 sec)// 查询系统表 information_schema.triggers 的方式指定查询条件, 查看指定的触发器信息USE information_schema;MariaDB [information_schema]> SELECT  * FROM triggers WHERE trigger_name='trigger_student_count_insert';+-----------------+----------------+------------------------------+--------------------+----------------------+---------------------+--------------------+--------------+------------------+--------------------------------------------------------+--------------------+---------------+----------------------------+----------------------------+--------------------------+--------------------------+---------+----------+----------------+----------------------+----------------------+--------------------+| TRIGGER_CATALOG | TRIGGER_SCHEMA | TRIGGER_NAME                 | EVENT_MANIPULATION | EVENT_OBJECT_CATALOG | EVENT_OBJECT_SCHEMA | EVENT_OBJECT_TABLE | ACTION_ORDER | ACTION_CONDITION | ACTION_STATEMENT                                       | ACTION_ORIENTATION | ACTION_TIMING | ACTION_REFERENCE_OLD_TABLE | ACTION_REFERENCE_NEW_TABLE | ACTION_REFERENCE_OLD_ROW | ACTION_REFERENCE_NEW_ROW | CREATED | SQL_MODE | DEFINER        | CHARACTER_SET_CLIENT | COLLATION_CONNECTION | DATABASE_COLLATION |+-----------------+----------------+------------------------------+--------------------+----------------------+---------------------+--------------------+--------------+------------------+--------------------------------------------------------+--------------------+---------------+----------------------------+----------------------------+--------------------------+--------------------------+---------+----------+----------------+----------------------+----------------------+--------------------+| def             | hellodb        | trigger_student_count_insert | INSERT             | def                  | hellodb             | student_info       |            0 | NULL             | UPDATE student_count SET student_count=student_count+1 | ROW                | AFTER         | NULL                       | NULL                       | OLD                      | NEW                      | NULL    |          | root@localhost | utf8                 | utf8_general_ci      | latin1_swedish_ci  |+-----------------+----------------+------------------------------+--------------------+----------------------+---------------------+--------------------+--------------+------------------+--------------------------------------------------------+--------------------+---------------+----------------------------+----------------------------+--------------------------+--------------------------+---------+----------+----------------+----------------------+----------------------+--------------------+1 row in set (0.00 sec)

删除触发器

DROP TRIGGER trigger_name;

3.12)Event 事件

3.12.1)Event 事件介绍

事件(event)是 MySQL 在相应的时刻调用的过程式数据库对象。( 类似于操作系统的计划任务 )

一个事件可调用一次,也可周期性的启动,它由一个特定的线程来管理的,也就是所谓的 "事件调度器"。

事件和触发器类似,都是在某些事情发生的时候启动。当数据库上启动一条语句的时候,触发器就启动了,而事件是根据调度事件来启动的。由于它们彼此相似,所以事件也称为临时性触发器。

事件取代了原先只能由操作系统的计划任务来执行的工作,而且 MySQL 的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务( 如:Linux 下的 CRON 或 Windows下 的任务计划 )只能精确到每分钟执行一次。

事件的优缺点

优点:一些对数据定时性操作不再依赖外部程序,而直接使用数据库本身提供的功能,可以实现每秒钟执行一个任务,这在一些对实时性要求较高的环境下就非常实用。

缺点:定时触发,不可以直接调用。

3.12.2)Event 管理

3.12.2.1)相关变量和服务器选项

MySQL 事件调度器由 event_scheduler 负责调用事件,它默认是关闭的。

这个调度器不断地监视一个事件是否要调用, 要创建事件,必须打开调度器。

服务器系统变量和服务器选项:

event_scheduler:默认值为 OFF,设置为 ON 才支持 Event,并且系统自动打开专用的线程。

范例:开启和关闭 event_scheduler

// 默认事件调度功能是关闭的// @@ 表示变量MariaDB [(none)]> select @@event_scheduler;+-------------------+| @@event_scheduler |+-------------------+| OFF               |+-------------------+1 row in set (0.000 sec)// 临时开启事件调度功能MariaDB [(none)]> set global event_scheduler=ON;Query OK, 0 rows affected (0.000 sec)// 开启事件调度功能后, 会自启动一个 event_scheduler 线程MariaDB [(none)]> show processlist;+----+-----------------+-----------+------+---------+------+------------------------+------------------+----------+| Id | User            | Host      | db   | Command | Time | State                  | Info             | Progress |+----+-----------------+-----------+------+---------+------+------------------------+------------------+----------+|  7 | root            | localhost | NULL | Query   |    0 | NULL                   | show processlist |    0.000 ||  8 | event_scheduler | localhost | NULL | Daemon  |    8 | Waiting on empty queue | NULL             |    0.000 |+----+-----------------+-----------+------+---------+------+------------------------+------------------+----------+2 rows in set (0.00 sec)// 临时关闭事件调度功能MariaDB [(none)]> set global event_scheduler=OFF;Query OK, 0 rows affected (0.000 sec)MariaDB [(none)]> show processlist;+----+------+-----------+------+---------+------+-------+------------------+----------+| Id | User | Host      | db   | Command | Time | State | Info             | Progress |+----+------+-----------+------+---------+------+-------+------------------+----------+|  7 | root | localhost | NULL | Query   |    0 | NULL  | show processlist |    0.000 |+----+------+-----------+------+---------+------+-------+------------------+----------+1 row in set (0.00 sec)// 持久开启事件调度[root@centos8 ~] vim /etc/my.cnf.d/mariadb-server.cnf[mysqld]event_scheduler=ON[root@centos8 ~] systemctl restart mariadb

3.12.2.2)管理事件

create event 语句创建一个事件。

每个事件 由两个主要部分组成

第一部分:是事件调度(event schedule),表示事件何时启动以及按什么频率启动

第二部分:是事件动作(event action ),这是事件启动时执行的代码,事件的动作包含一条 SQL 语句,它可能是一个简单地insert或者update语句,也可以使一个存储过程或者 benin...end 语句块,这两种情况允许我们执行多条 SQL。

一个事件可以是活动(打开)的或停止(关闭)的,活动意味着事件调度器检查事件动作是否必须调用,停止意味着事件的声明存储在目录中,但调度器不会检查它是否应该调用。在一个事件创建之后,它立即变为活动的,一个活动的事件可以执行一次或者多次。

创建 Event

CREATE[DEFINER = { user | CURRENT_USER }]EVENT[IF NOT EXISTS]event_nameON SCHEDULE schedule[ON COMPLETION [NOT] PRESERVE][ENABLE | DISABLE | DISABLE ON SLAVE][COMMENT 'comment']DO event_body;schedule:AT timestamp [+ INTERVAL interval] ...| EVERY interval[STARTS timestamp [+ INTERVAL interval] ...][ENDS timestamp [+ INTERVAL interval] ...]interval:quantity {YEAR | QUARTER | MONTH | DAY | HOUR | MINUTE |WEEK | SECOND | YEAR_MONTH | DAY_HOUR | DAY_MINUTE |DAY_SECOND | HOUR_MINUTE | HOUR_SECOND | MINUTE_SECOND}

说明:

event_name :创建的 event 名字,必须是唯一确定的

ON SCHEDULE:计划任务

schedule: 决定event的执行时间和频率( 注意时间一定要是将来的时间,过去的时间会出错 ),有两种形式 AT 和EVERY

[ON COMPLETION [NOT] PRESERVE]: 可选项,默认是 ON COMPLETION NOT PRESERVE 即计划任务执行完毕后自动 drop 该事件;ON COMPLETION PRESERVE 则不会 drop 掉

[COMMENT 'comment'] :可选项,comment 用来描述 event;相当注释,最大长度 64 个字节

[ENABLE | DISABLE]:设定 event 的状态,默认 ENABLE:表示系统尝试执行这个事件, DISABLE:关闭该事情,可以用 alter 修改

DO event_body: 需要执行的 sql 语句,可以是复合语句

提示:event 事件是存放在 mysql.event 表中

查看 Event

SHOW EVENTS [{FROM | IN} schema_name]

    [LIKE 'pattern' | WHERE expr]

注意:事件执行完即释放,如立即执行事件,执行完后,事件便自动删除,多次调用事件或等待执行事件,才可以用上述命令查看到。

修改 Event

ALTER[DEFINER = { user | CURRENT_USER }]EVENT event_name[ON SCHEDULE schedule][ON COMPLETION [NOT] PRESERVE][RENAME TO new_event_name][ENABLE | DISABLE | DISABLE ON SLAVE][COMMENT 'comment'][DO event_body]

注意:alter event 语句可以修改事件的定义和属性。可以让一个事件成为停止的或者再次让它活动,也可以修改一个事件的名字或者整个调度。然而当一个使用 ON COMPLETION NOT PRESERVE 属性定义的事件最后一次执行后,事件直接就不存在了,不能修改。

删除 Event

DROP EVENT [IF EXISTS] event_name

3.12.2.3)范例

范例:创建立即启动事件

MariaDB [(none)]> create database testdb;Query OK, 1 row affected (0.000 sec)MariaDB [(none)]> use testdbDatabase changed// 创建一个表记录每次事件调度的名字和事件戳MariaDB [testdb]> create table events_list(event_name varchar(20) not null, event_started timestamp not null);Query OK, 0 rows affected (0.005 sec)// 临时关闭事件调度功能MariaDB [testdb]> set global event_scheduler=0;Query OK, 0 rows affected (0.000 sec)MariaDB [testdb]> show variables like 'event_scheduler';+-----------------+-------+| Variable_name   | Value |+-----------------+-------+| event_scheduler | OFF   |+-----------------+-------+1 row in set (0.001 sec)// ( 创建一次性事件 )MariaDB [testdb]> create event event_now on schedule at now() do insert into events_list values('event_now', now());Query OK, 0 rows affected (0.001 sec)// 因为事件调度功能禁用, 所有表中无记录MariaDB [testdb]> select * from events_list;Empty set (0.000 sec)// 查看事件MariaDB [test]> show events\G*************************** 1. row ***************************Db: testdbName: event_nowDefiner: root@localhostTime zone: SYSTEMType: ONE TIMEExecute at: 2019-12-02 22:06:29Interval value: NULLInterval field: NULLStarts: NULLEnds: NULLStatus: ENABLEDOriginator: 1character_set_client: utf8collation_connection: utf8_general_ciDatabase Collation: latin1_swedish_ci1 row in set (0.001 sec)// 任务计划存放在 mysql.event 表中MariaDB [testdb]> select * from mysql.event\G*************************** 1. row ***************************db: testdbname: event_nowbody: insert into events_list values('event_now', now())definer: root@localhostexecute_at: 2020-02-19 02:46:04interval_value: NULLinterval_field: NULLcreated: 2020-02-19 10:46:04modified: 2020-02-19 10:46:04last_executed: NULLstarts: NULLends: NULLstatus: ENABLEDon_completion: DROPsql_mode:STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUB STITUTIONcomment:originator: 1time_zone: SYSTEMcharacter_set_client: utf8collation_connection: utf8_general_cidb_collation: latin1_swedish_cibody_utf8: insert into events_list values('event_now', now())1 row in set (0.000 sec)// 开启事件调度功能MariaDB [testdb]> set global event_scheduler=1;Query OK, 0 rows affected (0.000 sec)// 事件立即执行, 每秒插入一条记录MariaDB [testdb]> select * from events_list;+------------+---------------------+| event_name | event_started       |+------------+---------------------+| event_now  | 2019-12-02 22:07:11 |+------------+---------------------+1 row in set (0.001 sec)// 事件执行完成后自动删除MariaDB [testdb]> show events;Empty set (0.001 sec)

范例:创建每秒启动的事件

// ( 创建每秒执行的事件 )MariaDB [testdb]> CREATE EVENT event_every_second ON SCHEDULE EVERY 1 SECOND DO INSERT INTO events_list VALUES('event_now', now());MariaDB [testdb]> SHOW EVENTS\G*************************** 1. row ***************************Db: testdbName: event_every_secondDefiner: root@localhostTime zone: SYSTEMType: RECURRINGExecute at: NULLInterval value: 1Interval field: SECONDStarts: 2019-12-02 22:26:52Ends: NULLStatus: ENABLEDOriginator: 1character_set_client: utf8collation_connection: utf8_general_ciDatabase Collation: latin1_swedish_ci1 row in set (0.002 sec)// 事件是存放在 mysql.event 表中MariaDB [testdb]> select * from mysql.event\G*************************** 1. row ***************************db: testdbname: event_every_secondbody: INSERT INTO events_list VALUES('event_now', now())definer: root@localhostexecute_at: NULLinterval_value: 1interval_field: SECONDcreated: 2019-12-02 22:26:52modified: 2019-12-02 22:26:52last_executed: 2019-12-02 14:30:06starts: 2019-12-02 14:26:52ends: NULLstatus: ENABLEDon_completion: DROPsql_mode:STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTIONcomment:originator: 1time_zone: SYSTEMcharacter_set_client: utf8collation_connection: utf8_general_cidb_collation: latin1_swedish_cibody_utf8: INSERT INTO events_list VALUES('event_now', now())1 row in set (0.000 sec)MariaDB [testdb]> select *from events_list;+------------+---------------------+| event_name | event_started       |+------------+---------------------+| event_now  | 2019-12-02 22:07:11 || event_now  | 2019-12-02 22:26:52 || event_now  | 2019-12-02 22:26:53 || event_now  | 2019-12-02 22:26:54 || event_now  | 2019-12-02 22:26:55 || event_now  | 2019-12-02 22:26:56 || event_now  | 2019-12-02 22:26:57 || event_now  | 2019-12-02 22:26:58 || event_now  | 2019-12-02 22:26:59 || event_now  | 2019-12-02 22:27:00 || event_now  | 2019-12-02 22:27:01 || event_now  | 2019-12-02 22:27:02 || event_now  | 2019-12-02 22:27:03 || event_now  | 2019-12-02 22:27:04 || event_now  | 2019-12-02 22:27:05 || event_now  | 2019-12-02 22:27:06 || event_now  | 2019-12-02 22:27:07 || event_now  | 2019-12-02 22:27:08 || event_now  | 2019-12-02 22:27:09 || event_now  | 2019-12-02 22:27:10 |+------------+---------------------+20 rows in set (0.000 sec)MariaDB [testdb]> drop event event_every_second;Query OK, 0 rows affected (0.000 sec)MariaDB [testdb]> SHOW EVENTS\GEmpty set (0.001 sec)MariaDB [testdb]> select * from mysql.event\GEmpty set (0.000 sec)

3.13)MySQL 用户管理

相关数据库和表

元数据数据库: mysql

系统授权表: db, host, user,columns_priv, tables_priv, procs_priv, proxies_priv

用户帐号

'USERNAME'@'HOST'@'HOST': 主机名: user1@'web1.magedu.org'IP 地址或 Network通配符: %   _示例: wang@172.16.%.%  user2@'192.168.1.%'mage@'10.0.0.0/255.255.0.0'

创建用户:CREATE USER

新建用户的默认权限:USAGE

CREATE USER 'USERNAME'@'HOST' [IDENTIFIED BY 'password'];// 示例:create user test@'10.0.0.%' identified by 123456;create user test1@'10.0.0.0/255.255.255.0' identified by '123456';

举例:

// 创建用户 test 可以在 192.168.80.x 网段登录 ( 无密码 )create user test@'192.168.80.%';// 验证用户信息MariaDB [(none)]> select user,host,password from mysql.user;+------+--------------+----------+| user | host         | password |+------+--------------+----------+| root | localhost    |          || root | blog         |          || root | 127.0.0.1    |          || root | ::1          |          ||      | localhost    |          ||      | blog         |          || test | 192.168.80.% |          |+------+--------------+----------+7 rows in set (0.00 sec)// 远程主机登录验证mysql -utest -h192.168.80.130    ( 无密码远程登录 )

// 增加密码 ( 两种方式 )alter user test@'192.168.80.%' identified by '123456';update mysql.user set password=password('123456') where user='test';// 生效配置flush privileges;// 验证select user,host,password from mysql.user;// 远程主机登录验证mysql -utest -h192.168.80.130 -p123456    ( 基于密码远程登录 )

用户重命名:RENAME USER

RENAME USER old_user_name TO new_user_name;

删除用户:

DROP USER 'USERNAME'@'HOST'

范例:删除默认的空用户

DROP USER ''@'localhost';

修改密码

注意

新版 mysql 中用户密码可以保存在 mysql.user 表的 authentication_string 字段中

如果 mysql.user 表的 authentication_string 和 password 字段都保存密码,authentication_string 优先生效

// 方法 1, 用户可以也可通过此方式修改自已的密码// MySQL8.0 版本不支持此方法, 因为 password 函数被取消SET PASSWORD FOR 'user'@'host' = PASSWORD('password');  // MySQL8.0 版本支持此方法// 此方式直接将密码 123456 加密后存放在 mysql.user 表的 authentication_string 字段set password for root@'localhost'='123456';// 方法 2// 通用改密码方法, 用户可以也可通过此方式修改自己的密码, MySQL8 版本修改密码ALTER USER test@'%' IDENTIFIED BY '123456';// 方法 3// 此方式 MySQL8.0 不支持, 因为 password 函数被取消UPDATE mysql.user SET password=PASSWORD('password') WHERE clause;// mariadb 10.3update mysql.user set authentication_string=password('123456') where user='mage'// 此方法需要执行下面指令才能生效FLUSH PRIVILEGES; 

忘记管理员密码的解决办法( Linux 小技巧 )

注意:该技巧在生产环境尽量少操作,可能存在其他应用服务连接数据库的情况。你把密码一改,容易导致生产环境其他应用服务连接不上数据库。导致出现大问题。

启动 mysqld 进程时,为其使用如下选项

// 当启用这个选项时// MySQL/MariaDB 会在启动时跳过权限检查// 允许任何人以任何用户身份连接到数据库服务器, 而不需要提供密码。--skip-grant-tables// 这个选项禁用了 MySQL/MariaDB 服务器的网络远程连接功能// 通过本地套接字进行连接, 这在仅需本地访问而不希望通过网络远程连接时很有用--skip-networking

使用 UPDATE 命令修改管理员密码

关闭 mysqld 进程,移除上述两个选项,重启 mysqld

范例:Mariadb 和 MySQL5.6 版之前 破解 root 密码

[root@centos8 ~] vim /etc/my.cnf[mysqld]skip-grant-tables  skip-networking[root@centos8 ~] systemctl restart mysqld|mariadb[root@centos8 ~] mysql    ( 绕过了密码认证 )// 方法 1// mariadb 旧版和 MySQL5.6 版之前# 修改所有 user 字段为 root 的行信息MariaDB [(none)]> update mysql.user set password=password('123456') where user='root';MariaDB [(none)]> select user,host,password from mysql.user;+------+--------------+-------------------------------------------+| user | host         | password                                  |+------+--------------+-------------------------------------------+| root | localhost    | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 || root | blog         | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 || root | 127.0.0.1    | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 || root | ::1          | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |+------+--------------+-------------------------------------------+6 rows in set (0.00 sec)// mariadb 新版MariaDB [(none)]> update mysql.user set authentication_string=password('123456') where user='root';// 方法 2MariaDB [(none)]> flush privileges;    ( 刷新权限后再执行 )MariaDB [(none)]> alter user root@'localhost' identified by '123456';// 取消绕过密码认证配置[root@centos8 ~] vim /etc/my.cnf[mysqld]# skip-grant-tables         # skip-networking[root@centos8 ~] systemctl restart mysqld|mariadb[root@centos8 ~] mysql -uroot -p123456

范例:MySQL5.7 和 8.0 破解 root 密码

[root@centos8 ~] vim /etc/my.cnf[mysqld]skip-grant-tables  skip-networking  // MySQL8.0 不需要[root@centos8 ~] systemctl restart mysqld// 方法 1[root@centos8 ~] mysqlmysql> update mysql.user set authentication_string='' where user='root' andhost='localhost';// 方法 2mysql> flush privileges;// 再执行下面任意一个命令mysql> alter user root@'localhost' identified by '123456';mysql> set password for root@'localhost'='123456';// 取消绕过密码认证配置[root@centos8 ~] vim /etc/my.cnf[mysqld]# skip-grant-tables         # skip-networking[root@centos8 ~] systemctl restart mysqld[root@centos8 ~] mysql -uroot -p123456

范例:删库跑路之清空 root 密码方法( 测试环境使用 )

// 此方法适用于包安装方式的 MySQL 或 Mariadb[root@centos8 ~] systemctl stop mysqld[root@centos8 ~] rm -rf /var/lib/mysql/*[root@centos8 ~] systemctl start mysqld[root@centos8 ~] mysql

3.14)权限管理和 DCL 语句

3.14.1)权限类别

权限类别:

管理类

程序类

数据库级别

表级别

字段级别

管理类

CREATE USER

FILE

SUPER

SHOW DATABASES

RELOAD

SHUTDOWN

REPLICATION SLAVE

REPLICATION CLIENT

LOCK TABLES

PROCESS

CREATE TEMPORARY TABLES

程序类:针对 FUNCTION、PROCEDURE、TRIGGER

CREATE

ALTER

DROP

EXCUTE

库和表级别:针对 DATABASE、TABLE

ALTER

CREATE

CREATE VIEW

DROP INDEX

SHOW VIEW

WITH GRANT OPTION:能将自己获得的权限转赠给其他用户

数据操作

SELECT

INSERT

DELETE

UPDATE

字段级别

SELECT(col1,col2,...)

UPDATE(col1,col2,...)

INSERT(col1,col2,...)

所有权限

ALL PRIVILEGES 或 ALL

举例:

// 创建用户create user wangj@'192.168.80.%' identified by '123456';// 授权grant all on hellodb.* to wangj@'192.168.80.%';// 生效配置flush privileges;// 验证mysql -uwangj -h192.168.80.130 -p123456show databases;

// 创建用户并授权 ( MySQL 8.0 之前的版本 )GRANT ALL ON *.* TO root@'192.168.80.%' IDENTIFIED BY '123456';                // 授权所有数据库的操作权限GRANT ALL ON wordpress.* TO root@'192.168.80.%' IDENTIFIED BY '123456';        // 仅授权 WordPress 数据库的操作权限// 验证select user,host,password from mysql.user;

3.14.2)授权

参考:MySQL :: MySQL 5.7 Reference Manual :: 13.7.1.4 GRANT Statement

授权:GRANT

GRANT priv_type [(column_list)],... ON [object_type] priv_level TO 'user'@'host' [IDENTIFIED BY 'password'] [WITH GRANT OPTION];priv_type: ALL [PRIVILEGES]object_type:TABLE | FUNCTION | PROCEDUREpriv_level: *(所有库)  |*.*   | db_name.*  | db_name.tbl_name  | tbl_name (当前库的表) | db_name.routine_name(指定库的函数,存储过程,触发器)with_option: GRANT OPTION| MAX_QUERIES_PER_HOUR count| MAX_UPDATES_PER_HOUR count| MAX_CONNECTIONS_PER_HOUR count| MAX_USER_CONNECTIONS count

范例:

GRANT SELECT (col1), INSERT (col1,col2) ON mydb.mytbl TO 'someuser'@'somehost';GRANT ALL ON wordpress.* TO wordpress@'10.0.0.%' ;GRANT ALL PRIVILEGES ON *.* TO 'root'@'10.0.0.%'  WITH GRANT OPTION;// 创建用户和授权同时执行的方式在 MySQL8.0 取消了GRANT ALL ON wordpress.* TO wordpress@'192.168.8.%' IDENTIFIED BY 'magedu';GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.8.%' IDENTIFIED BY 'magedu' WITH GRANT OPTION;

3.14.3)取消权限

参考:MySQL :: MySQL 5.7 Reference Manual :: 13.7.1.6 REVOKE Statement

取消授权:REVOKE

REVOKE priv_type [(column_list)] [, priv_type [(column_list)]] ... ON [object_type] priv_level FROM user [, user] ...

范例:

REVOKE DELETE ON *.* FROM 'testuser'@'172.16.0.%';

3.14.4)查看指定用户获得的授权

Help SHOW GRANTS

SHOW GRANTS FOR 'user'@'host';

SHOW GRANTS FOR CURRENT_USER[()];

注意:

MariaDB 服务进程启动时会读取 mysql 库中所有授权表至内存

(1)GRANT 或 REVOKE 等执行权限操作会保存于系统表中,MariaDB 的服务进程通常会自动重读授权表,使之生效

(2)对于不能够或不能及时重读授权表的命令,可手动让 MariaDB 的服务进程重读授权表:

mysql> FLUSH PRIVILEGES;

3.15)MySQL 的图形化的远程管理工具

在 MySQL 数据库中创建用户并授权后,可以使用相关图形化工具进行远程的管理。

常见的图形化管理工具:

Navicat

SQLyog

3.15.1)Navicat 工具

3.15.2)SQLyog 工具

范例:

// 先创建用户并授权GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.8.%' IDENTIFIED BY 'magedu' WITH GRANT OPTION;

相关文章:

  • 基于SSM的便民自行车管理系统的开发与实现(有报告)。Javaee项目。ssm项目。
  • 如何从dockerhub 中运行一个简单项目
  • 基于单片机的智能寻光小车设计
  • P4408 [NOI2003] 逃学的小孩
  • C++ 11新特性之tuple
  • linux上部署ftp服务
  • Python:批量url链接保存为PDF
  • Flink 1.18.1的基本使用
  • 全面理解jvm
  • 板块零 IDEA编译器基础:第二节 创建JAVA WEB项目与IDEA基本设置 来自【汤米尼克的JAVAEE全套教程专栏】
  • 网络异常案例六_IP冲突
  • 【C语言】三子棋游戏实现代码
  • Java赋能:大学生成绩量化新篇章
  • 【机器学习】AAAI 会议论文聚类分析
  • Antd+React+react-resizable实现表格拖拽功能
  • @jsonView过滤属性
  • chrome扩展demo1-小时钟
  • ECS应用管理最佳实践
  • flutter的key在widget list的作用以及必要性
  • GitUp, 你不可错过的秀外慧中的git工具
  • maya建模与骨骼动画快速实现人工鱼
  • Mysql数据库的条件查询语句
  • PHP 7 修改了什么呢 -- 2
  • Python爬虫--- 1.3 BS4库的解析器
  • Redis 中的布隆过滤器
  • 回流、重绘及其优化
  • 机器人定位导航技术 激光SLAM与视觉SLAM谁更胜一筹?
  • 精彩代码 vue.js
  • 排序算法学习笔记
  • 前端js -- this指向总结。
  • 驱动程序原理
  • 一个JAVA程序员成长之路分享
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • 好程序员web前端教程分享CSS不同元素margin的计算 ...
  • 如何用纯 CSS 创作一个货车 loader
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • (八)五种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (差分)胡桃爱原石
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (五)网络优化与超参数选择--九五小庞
  • **python多态
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET/C# 编译期能确定的字符串会在字符串暂存池中不会被 GC 垃圾回收掉
  • .NET/C# 使用反射注册事件
  • .NET命名规范和开发约定
  • @SuppressWarnings注解
  • @test注解_Spring 自定义注解你了解过吗?
  • [ Linux 长征路第二篇] 基本指令head,tail,date,cal,find,grep,zip,tar,bc,unname
  • [14]内置对象
  • [Android]使用Git将项目提交到GitHub