数据库考点之事务、事件

如题:2019年4月

分析:三题都答错,可见对这块的无知....。

1、什么是事务?什么又是事件?

用户定义的完整的工作单元,要么全部执行,要么全部不执行,以此保证数据的一致性,实现多用户,并发操作。

事件:详见扩展:事件操作

事件是用来执行定时任务的一组SQL集,在时间到时会触发。
一个事件可调用一次,也可周期性的启动,由一个特定的事件调度器线程来管理的。
事件取代了原先只能由操作系统的计划任务来执行的工作,而且MySQL的事件调度器可以精确到每秒钟执行一个任务,而操作系统的计划任务(如:Linux下的CRON或Windows下的任务计划)只能精确到每分钟执行一次。

2、特征:

  • 原子性(Atomicity)

一个事务的多个数据库操作是一个不可分隔的原子单元,只有所有的操作执行成功,整个事务才提交,事务中任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库返回到初始状态。

  • 一致性(Consistency)

事务执行完毕后,由一个一致性状态转到另一个一致性状态,是以一致性为基础的逻辑操作,以此保证数据不会被破坏。

  • 隔离性(Isolation)

在并发数据操作时,不同的事务拥有各自数据空间,彼此独立。一个事务的执行不受其他事务的干扰。

数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性越好,但并发性越弱。

  • 持久性(Durabiliy)

事务提交后,对数据库改变是永久性的,即故障,也能恢复。

以上就是事务的ACID特征,书上没有说明ACID是啥,挺突兀的。

3、事务并发带来的问题,典型三种

可类比操作系统对线程的并发控制。

  • 丢失更新

同时读同一数据并修改,当一个事务提交或撤销,覆盖另一事务已经提交的结果。

  • 不可重复读(Unrepeatable Read)

指A事务读取了B事务已经提交的更改数据,当事务A再次读时,无法得到与前一次读数据一致的数据。

  • 脏读(Dirty Read)

事务(A)读取另外事务(B)尚未提交的更改数据,并在读取的数据的基础上操作。如果恰巧 B事务回滚,那么 A事务读到的数据根本是不被承认的。

4、如何解决并发操作带来的问题,方法之一 锁

  • 锁的本质:

允许或阻止一个事务对一个数据的存取特权,22填空题的答案

  • 锁的类型:

​​​​​​​A、共享锁(读锁)Shared Lock
针对同一块数据,多个读操作可以同时进行而不会互相影响。
B、排他锁(写锁)Exculusive Lock
当前写操作没有完成前,阻断其他写锁和读锁。

  • 锁的粒度,详见后面扩展:mysql锁机制

按锁的粒度划分,锁可分为表级锁、行级锁、页级锁。
A、行级锁
开销大,加锁慢,会出现死锁,锁定力度最小,发生锁冲突的概率最低,并发度高。
B、表级锁
开销小,加锁快,不会出现死锁,锁定力度大,发生冲突所的概率高,并发度低。
C、页面锁
开销和加锁时间介于表锁和行锁之间,会出现死锁,锁定力度介于表和行行级锁之间,并发度一般。

D、对整个数据库加锁

开销低,控制简单,不会出现死锁,并发性最低

  • 锁的级别:详见扩展:锁级别设置

​​​​​​​SQL标准定义了4类隔离级别,包括了一些具体规则,用来限定事务内外的哪些改变是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。

0级封锁:不重写其他非0级封锁事务的未提交的更新数据。

Read Uncommitted(读取未提交内容)
本隔离级别,事务可以读取其他未提交事务的执行结果。读取未提交的数据,也被称之为脏读(Dirty Read)。

1级封锁:不允许重写未提交的更新数据,防止更新丢失。

Read Committed(读取提交内容)
大多数数据库系统的默认隔离级别(但不是MySQL默认的)。事务只能读取其他事务已经提交的执行结果。本隔离级别支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

2级封锁,被封锁的事务即不重写也不读未提交的更新数据,防止了读脏数据。

Repeatable Read(可重读)
MySQL默认的事务隔离级别,会给查询的记录做快照,直到事务结束。确保同一事务的多个实例在并发读取数据时,会看到同样的数据行,会导致幻读(Phantom Read)。幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了幻读问题。

3级封锁,不读未提交的更新数据,也不写(包括读操作)未提交的数据。防止了不可重读问题。保证了多事务的可串行化

Serializable(可串行化)
最高的隔离级别,对同一条记录读和修改的多个事务只能结束一个,才能开始下一个。
通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。在每个读的数据行上加上共享锁,可能导致大量的超时现象和锁竞争。

5、事务实例:

事务提交还是回滚,可以在事务结束处判断是否出现错误,如果出现,回滚。如果没有错误,提交事务。
使用自定义条件来决定事务是提交还是回滚。

  • 由错误决定事务提交或回滚

在存储过程中使用事务,在事务的末尾判断是否有错误,插入失败,则回滚事务。
创建两张表,存储ID、姓名、年龄,创建存储过程将A表的指定ID的记录转移到B表。

CREATE TABLE ta
(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(10),
age INT
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into ta values(1, '孙悟空', 500);
insert into ta values(2, '唐僧', 30);

CREATE TABLE tb
(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(10),
age INT
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into tb values(1, '孙悟空', 500);
insert into tb values(3, '猪八戒', 100);
CREATE PROCEDURE move(num INT)
BEGIN
DECLARE errorinfo INT DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET errorinfo=1;
START TRANSACTION;
INSERT INTO tb SELECT * FROM ta WHERE id=num;
DELETE FROM ta WHERE id=num;
IF errorinfo=1 
   THEN ROLLBACK;
ELSE
   COMMIT;
END IF;
END

将ID为2的记录从A表转移到B表​​​​​​​
call move(2);

  • 由自定义条件决定事务提交或回滚

创建两个表,每个表含账户、姓名、余额信息,创建一个存储过程,从A表中的一个账户转账一定金额到B表的一个账户,如果转出账户的余额不足,则回滚,否则提交。

create table accountA
(
account INT PRIMARY KEY NOT NULL,
name VARCHAR(10),
balance DOUBLE
)ENGINE=innoDB default CHARSET=utf8;

insert into accountA VALUES(1, '孙悟空', 10000);
insert into accountA VALUES(2, '唐僧', 20000);
create table accountB
(
account INT PRIMARY KEY NOT NULL,
name VARCHAR(10),
balance DOUBLE
)ENGINE=innoDB default CHARSET=utf8;

insert into accountB VALUES(1, '孙悟空', 10000);
insert into accountB VALUES(2, '唐僧', 20000);
CREATE PROCEDURE transfer(fromaccout INT,toaccount INT, num DOUBLE)
BEGIN
DECLARE m DOUBLE;
START TRANSACTION;
UPDATE accountB SET balance=balance + num WHERE account=toaccount;
UPDATE accountA SET balance=balance - num WHERE account=fromaccout;
SELECT balance INTO m from accountA WHERE account=fromaccout;
IF m < 0
   THEN ROLLBACK;
ELSE 
   COMMIT;
END IF;
END

从A表的账户2转出25000元到B表的账户2。
call transfer(2,2,25000);
此时A表的余额不足,回滚

扩展:

  • 事务类型:

A、自动提交事务
系统默认每个TRANSACT-SQL命令都是一个事务处理,由系统自动开始并提交。
B、隐式事务
不需要显示开始事务,需要显示提交,隐式事务是任何单独的INSERT、UPDATE 或者DELETE语句构成。当有大量的DDL和DML命令执行时会自动开始,并一直保持到用户明确提交为止。
SHOW VARIABLES 查看变量。
SET AUTOCOMMIT=0,关闭自动提交功能。
需要显示提交或者回滚。

update tablename set sname='孙悟空' where studentid='000000000000003';
commit;


rollback;
C、显示事务
显示事务是用户自定义事务,以START TRANSACTION(事务开始)开头,以 COMMIT(事务提交)或者 ROLLBACK(回滚事务)语句结束。

start transaction 
update tablename set sname='孙悟空' where studentid='000000000000003';
commit


rollback
D、分布式事务
跨越多个服务器的事务称为分布式事务。从MySQL5.03开始支持分布式事务。

  • 事务控制

A、开始事务
标记一个显式事务的开始点,即事务开始。其语法如下:
START { TRAN | TRANSACTION }
B、提交事务
标记一个成功的隐性事务或显式事务的结束,即事务提交。其语法如下:
COMMIT
C、回滚事务
将显式事务或隐性事务回滚到事务的起点或事务内的某个保存点。其语法如下:
ROLLBACK
D、事务设置
SET AUTOCOMMIT 可以修改当前连接事务提交方式。
SET AUTOCOMMIT=0,则需要明确的命令进行提交或者回滚。

锁级别设置

  • 事务隔离级别设置

用户可以用SET TRANSACTION语句改变单个会话或者所有新进连接的隔离级别。语法如下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
默认的行为(不带session和global)是为下一个(未开始)事务设置隔离级别。如果使用GLOBAL关键字,语句在全局对新开始创建的所有新连接设置默认事务级别,需要SUPER权限。使用SESSION关键字为将来在当前连接上执行的事务设置默认事务级别。 任何客户端都能自由改变会话隔离级别,或者为下一个事务设置隔离级别。
查询全局和会话事务隔离级别:

SELECT @@global.tx_isolation; 
SELECT @@session.tx_isolation; 
SELECT @@tx_isolation;

通过mySQL配置文件修改全局事务隔离级别,设置全局会话默认事务隔离级别。

[mysqld]
xxxxxxx
transaction-isolation=read-committed

重启mySQL服务,生效。
设置当前会隔离级别

SET  SESSION  TRANSACTION ISOLATION LEVEL  READ UNCOMMITTED
SET  SESSION  TRANSACTION ISOLATION LEVEL  READ COMMITTED
SET  SESSION  TRANSACTION ISOLATION LEVEL  REPEATABLE READ
SET  SESSION  TRANSACTION ISOLATION LEVEL  SERIALIZABLE
  • 事务隔离级别验证

不同会话的隔离级别

不同会话的事务隔离级别不同
在会话1终端查看当前会话的事务隔离级别
select @@tx_isolation
查询结果为:可重复读REPEATABLE-READ
设置当前会话事务隔离级别为READ UNCOMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
打开另一个SQL Manager终端作为会话2,查看当前会话的事务隔离级别
select @@tx_isolation
查询结果为:可重复读REPEATABLE-READ
创建一张表,含ID、姓名、年龄字段,用于验证不同的事务隔离级别。

CREATE TABLE ta
(
id INT NOT NULL PRIMARY KEY,
name VARCHAR(10),
age INT
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into ta values(1, '孙悟空', 500);
insert into ta values(2, '唐僧', 30);

SQL Manager Lite客户端的事务回滚机制失效,以下实验使用Navicat for MySQL客户端。

验证READ UNCOMMITTED隔离级别

打开一个会话1,设置事务隔离级别为READ UNCOMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
打开会话2,开始一个事务,更新ID为1的记录的age为1000。

start TRANSACTION;
update ta set age=1000 where id =1;

在会话1查看ta表中ID为1的信息,age已经为1000。
select * from ta;
会话1的事务隔离级别允许读取未提交的数据。
在会话2回滚事务
ROLLBACK;
会话1和会话2查询ta表中ID为1的记录,age为500

验证READ COMMITTED隔离级别

打开一个会话1,设置事务隔离级别为READ COMMITTED
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
打开会话2,开始一个事务,更新ID为1的记录的age为5000。

start TRANSACTION;
update ta set age=5000 where id =1;

在会话1查看ta表中ID为1的信息,age为500。
select * from ta;
会话1的事务隔离级别不允许读取未提交的数据。
在会话2提交事务
COMMIT;
会话1查询ta表中ID为1的记录,age为5000

验证REPEATABLE READ隔离级别

打开一个会话1,设置事务隔离级别为REPEATABLE READ
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ
在会话1,开始一个事务,查询ID为1的记录的age为5000。

start TRANSACTION;
SELECT * FROM ta where id =1;

在会话2更新ta表中ID为1的信息,age为1000。
UPDATE ta SET age=1000 WHERE id=1;
在会话2查看ta表中ID为1的信息,age已经为1000。
select * from ta WHERE id=1;
在会话1再次查看ta表中ID为1的信息,age仍旧为5000。
select * from ta WHERE id=1;
在会话1提交事务
COMMIT;
会话1查询ta表中ID为1的记录,age已经为1000。

验证SERIALIZABLE隔离级别

打开一个会话1,设置事务隔离级别为SERIALIZABLE
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE
打开会话2,开始一个事务,更新ID为1的记录的age为5000。

start TRANSACTION;
update ta set age=5000 where id =1;

在会话1开始一个事务,查看ta表中ID为1的信息,会话1处于等待状态。

start TRANSACTION;
select * from ta;

在会话2提交事务后,
COMMIT;
会话1查询SQL执行完毕,结果为5000。

mysql锁机制

MySQL的锁机制比较简单,最显著的特点是不同的存储引擎支持不同的锁机制。
MyISAM和MEMORY存储引擎采用表级锁。
InnoDB支持行级锁、表级锁,默认情况采用行级锁。

表级锁

  • 表级锁简介

MyISAM存储引擎和InnoDB存储引擎都支持表级锁。
MyISAM存储引擎支持表级锁,为了保证数据的一致性,更改数据时,防止其他人更改数据,可以人工添加表级锁。可以使用命令对数据库的表枷锁,使用命令对数据库的表解锁。
给表加锁的命令Lock Tables,给表解锁的命令Unlock Tables
MyISAM引擎在用户读数据自动加READ锁,更改数据自动加WRITE锁。使用lock Tables和Unlock Tables显式加锁和解锁。

  • 添加表级读锁 

打开会话1,创建表

CREATE TABLE tc
(
id INT,
name VARCHAR(10),
age INT
)ENGINE=MyISAM DEFAULT CHARSET=utf8;

插入两条记录:

insert into tc values(1, '孙悟空', 500);
insert into tc values(3, '猪八戒', 100);

对表加READ锁
lock tables tc read;
加锁后只可以查询已经加锁的表,
select * from tc;
查询没有加锁的表将失败
select * from ta;
打开会话2,对已经加锁的表进行查询,成功。
select * from tc;
对加锁的表tc进行更新操作,将失败
update tc set age=100 where id=1;
会话1中使用LOCK TABLE命令给表加了读锁,会话1可以查询锁定表中的记录,但更新或访问其他表都会提示错误;会话2可以查询表中的记录,但更新就会出现锁等待。
在会话1对表进行解锁,会话2的更新操作成功。
unlock tables;
在会话1,再次锁定表tc,后面带local参数。
lock tables tc read local;
Local参数允许在表尾并发插入,只锁定表中当前记录,其他会话可以插入新的记录
在会话2插入一条记录
insert into tc values(2, '唐僧', 20);
在会话1查看tc表的记录,无插入记录
select * from tc;

  • 设置表级锁并发性

READ锁是共享锁,不影响其他会话的读取,但不能更新已经加READ锁的数据。MyISAM表的读写是串行的,但是总体而言的,在一定条件下,MyISAM表也支持查询和插入操作的并发进行。
MyISAM存储引擎有一个系统变量concurrent_insert,用以控制其并发插入的行为,其值分别可以为0、1或2。
0:不允许并发操作
1:如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录,是MySQL的默认设置。
2:无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。
在MySQL配置文件添加,concurrent_insert=2,重启mySQL服务设置生效。

  • 验证表级锁的并发性

设置concurrent_insert为0
在会话1对表tc加锁
lock tables tc read local;
在会话2插入一条记录,此时tc表被锁定,进入等待
insert into tc values(4, '沙悟净', 30);
在会话1解锁表tc,此时会话2插入成功
unlock tables;

设置concurrent_insert为1
在会话1删除ID为3的记录
delete from tc where id=3;
在会话1对表tc加锁
lock tables tc read local;
在会话2插入一条记录,此时tc表被锁定,并且表中有空洞,进入等待
insert into tc values(5, '白骨精', 1000);
在会话1解锁表tc,此时会话2插入成功,此时表中已经没有空洞
unlock tables;
在会话1对表tc加锁
lock tables tc read local;
在会话2插入一条记录,插入成功,支持有条件并发插入
insert into tc values(6, '白骨精', 1000);
在会话1解锁表tc
unlock tables;

设置concurrent_insert为2
在会话1删除ID为5的记录,创造一个空洞
delete from tc where id=5;
在会话1对表tc加锁
lock tables tc read local;
在会话2插入一条记录,插入成功,支持无条件并发插入
insert into tc values(7, '蜘蛛精', 1000);
在会话1解锁表tc
unlock tables;

  • 添加表级写锁

添加表级写锁语法如下:
LOCK TABLES tablename WRITE;
不允许其他会话查询、修改、插入记录。

行级锁

  • 行级锁简介

InnoDB存储引擎实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control)。MVCC的优点是读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能。
在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。
快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。
当前读,读取的是记录的最新版本,并且当前读返回的记录都会加上锁,保证其他事务不会再并发修改。事务加锁,是针对所操作的行,对其他行不进行加锁处理。
快照读:简单的SELECT操作,属于快照读,不加锁。
select * from table where ?;
当前读:特殊的读操作,INSERT/UPDATE/DELETE,属于当前读,需要加锁。

select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;

以上SQL语句属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁)。

  • 验证快照读

打开会话1,创建一个表,含ID、姓名、年龄

CREATE TABLE td
(
id INT ,
name VARCHAR(10),
age INT
)ENGINE=innoDB DEFAULT CHARSET=utf8;

在插入两条记录

insert into td values(1, '孙悟空', 500);
insert into td values(2, '猪八戒', 100);

在会话1开始事务
start transaction;
在会话1查询ID位1的记录信息
select * from td where id =1;
打开会话2,更新ID为1的age为1000
update td set age=1000 where id=1;
在会话2查看ID为1的age已经更新为1000。
select * from td where id =1;
在会话1查看ID为1的age,仍然为500。
select * from td where id =1;
在会话1提交事务
COMMIT;
在会话1查看ID为1的age,已经为1000。

  • 验证当前读

在会话1开始事务
start transaction;
在会话1给select语句添加共享锁。
select * from td where id=1 lock in share mode;
在会话2,更新ID为1的age的值为100,进入锁等待
update td set age=100 where id=1;
在会话1提交事务
COMMIT;
会话2的更新操作成功。

  • 验证事务给记录加锁

在会话1开始事务
start transaction;
在会话1更新ID为1的age的值为500。
update td set age=500 where id=1;
在会话2开始事务
start transaction;
在会话2更新ID为2的age的值为1000,此时进入锁等待
update td set age=1000 where id=2;
td表没有指定主键,事务不支持行级锁。会话1的事务给整张表加了锁。
在会话1提交事务,此时会话2的修改成功
COMMIT;
在会话2提交事务,解除对表的锁定
COMMIT;
在会话1,给表的ID增加主键
alter table td add primary key(id);
在会话1开始事务
start transaction;
在会话1更新ID为1的age的值为5000
update td set age=5000 where id=1;
在会话2上开始事务
start transaction;
在会话2上修改ID为2的get的值为10000,更新成功,说明会话1只锁定了ID为1的行。
update td set age=10000 where id=2;
在会话2上更新ID是1的age值为100,出现等待。因为会话1给ID为1的行添加了独占锁。
update td set age=5000 where id=1;
在会话1提交事务
COMMIT;
在会话2提交事务
COMMIT;
在会话1查询,会话1和会话2对age列的修改都生效
select * from td;

  • 死锁的产生

A事务添加共享锁后,B事务也可以添加共享锁。A事务UPDATE锁定记录,处于等待中,于此同时B事务也UPDATE更新锁定的记录,就产生死锁。
在会话1开始事务
start transaction;
在会话1查询ID是1的记录,并添加共享锁。
select * from td where id=1 lock in share mode;
在会话2开始事务
start transaction;
在会话2查询ID是1的记录,并添加共享锁。
select * from td where id=1 lock in share mode;
在会话1更新ID为1的age值为,等待会话2释放共享锁
update td set age=200 where id=1;
在会话2更新ID为1的age为,会话2发现死锁,回滚事务。
update td set age=200 where id=1;
在会话1提交事务
COMMIT;

事件操作

  • 事件的优点

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

  • 事件的缺点

定时触发,不可以调用。

  • 件的适用场景

对于每隔一段时间就有固定需求的操作,如创建表,删除数据等操作,可以使用event来处理。

  • 事件的创建
CREATE
[DEFINER = { user | CURRENT_USER }]
EVENT [IF NOT EXISTS] event_name
ON SCHEDULE schedule
[ON COMPLETION [NOT] PRESERVE]
[ENABLE | DISABLE | DISABLE ON SLAVE]
[COMMENT 'comment']
DO event_body;

event_name :事件名,不能超64个字符,名字必须是当前Dateabase中唯一的,同一个数据库不能有同名的event。创建事件时,可以同时指定Schema,语法结构为:schema_name.eventname。使用event常见的工作是创建表、插入数据、删除数据、清空表、删除表。为了规范事件命名,事件名称需具备描述整个事件的能力。建议命名规则如下:动作名称(INTO/FROM_)表名_TIME,如每天插入表中记录事件命名,insert_into_tablename_day。
ON SCHEDULE schedule:计划任务
schedule:调度规则,规定事件的执行时间与执行规则。决定event的执行时间和频率(时间必须是将来的时间,过去的时间会出错),有AT和EVERY两种形式。
语法结构如下:

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}

AT timestamp,用来完成单次的计划任务。
EVERY n quantity [STARTS timestamp] [ENDS timestamp],用来完成重复的计划任务。
时间戳可以是任意的TIMESTAMP 和DATETIME 数据类型,时间戳需要大于当前时间。
在重复的计划任务中,时间(单位)的数量可以是任意非空(Not Null)的整数式,时间单位是关键词:YEAR,MONTH,DAY,HOUR,MINUTE 或者SECOND。
AT timestamp一般用于只执行一次,一般可以使用当前时间加上延后的一段时间,例如:AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR;也可以定义一个时间常量,例如:AT '2006-02-10 23:59:00';EVERY interval一般用于周期性执行,可以设定开始时间和结束时间。
ON COMPLETION [NOT] PRESERVE:事件到期后的操作,默认事件到期后会自动删除。如果想保留事件使用ON COMPLETION PRESERVE;如果不想保留事件,可以设置ON COMPLETION NOT PRESERVE。
[ENABLE | DISABLE]:参数Enable和Disable表示设定事件的状态。Enable表示系统将执行事件,Disable表示系统不执行事件。
[COMMENT 'comment']:增加注释,注释会出现在元数据中,存储在information_schema表的COMMENT列,最大长度为64个字节。'comment'表示将注释内容放在单引号之间,建议使用注释以表达更全面的信息。
event_body:事件体,可以是单行SQL语法,或是BEGIN……END语句块,或是存储过程。

  • 事件调度器的开启

MySQL默认关闭事件调度器。
查看事件调度器信息

show global variables like '%event_scheduler%';
SHOW PROCESSLIST;

开启事件调度器
set global event_scheduler=ON;
在MySQL的my.cnf配置文件中修改。
event_scheduler = 1 #或者ON  

  • 事件的查看
 SELECT * FROM mysql.event;
    SHOW EVENTS;
    SELECT * FROM information_schema.events;
  • 删除事件
DROP EVENT [IF EXISTS] eventname;
  • 禁用事件
ALTER EVENT eventname DSIABLE;
  • 开启事件
ALTER EVENT eventname ENABLE;
  • 事件的修改
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]

事件实例

  • 每隔一定时间插入一次记录

创建一个表
CREATE TABLE event_table(timeline TIMESTAMP);
创建一个事件,每隔1秒插入一条记录

CREATE EVENT insert_into_event_table_second
ON SCHEDULE EVERY 1 SECOND 
DO INSERT INTO schoolDB.event_table VALUES(CURRENT_TIMESTAMP);

过一定时间查看插入记录
select * from event_table;
停止事件
alter event insert_into_event_table_second disable;
删除事件
drop event insert_into_event_table_second;

  • 特定时间插入一条记录

创建一个事件在特定时间插入一条记录

CREATE EVENT insert_into_event_table_time
ON SCHEDULE AT TIMESTAMP '2018-04-11 21:27:30'
DO INSERT INTO schoolDB.event_table values(CURRENT_TIMESTAMP);

在特定时间后查看插入记录,已经插入记录
select * from event_table;

  • 特定时间清空表

创建一个事件,特定时间清空表,事件执行完后保留事件

CREATE EVENT truncate_event_table_time
ON SCHEDULE AT TIMESTAMP '2018-04-11 21:35:00'
ON COMPLETION PRESERVE
DO TRUNCATE TABLE schoolDB.event_table;

时间过后查询表的内容,已经清空
select * from event_table;

  • 某个事件段内定时清空表

创建一个事件,5天后开启,每天定时清空表,一个月后停止执行

CREATE EVENT truncate_event_table_day
ON SCHEDULE EVERY 1 DAY 
STARTS CURRENT_TIMESTAMP + INTERVAL 5 DAY
ENDS CURRENT_TIMESTAMP + INTERVAL 1 MONTH
ON COMPLETION PRESERVE
DO TRUNCATE TABLE schoolDB.event_table;
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guangod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值