本文是针对数据库的事务与锁,触发器,存储过程,自定义函数,游标,定时任务的基础学习记录。
一、事务与锁
基本描述:数据库的锁,数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性,(注意事项:首先,数据库类型要是InnoDB,其次,加锁必须跟事务同时使用)。
事务的四个特性:原子性,一致性,隔离性,持久性
应用场景:限量商品的买卖,锁定商品操作
(1)查看数据库引擎命令
show engines;
(2)更改表类型为支持事务的类型命令
ALTER TABLE table_name TYPE=INNODB/BDB;
(3)应用在TP5事例
public function index(){
//开启事务
Db::startTrans();
try{
//加锁
$res=Db::table('student')->lock(true)->select();
if($res){
//业务处理
$insert=['name'=>'遥不可及123','phone'=>123456,'sex'=>'男','age'=>12, 'province'=> '123', 'url'=> '123','status'=>'1'];
$result=Db::table('student')->insert($insert);
if(!$result){
Db::rollback();//事务回滚
return json(['state'=>-1,'msg'=>'操作失败事务回滚']);
}
}
sleep(1);
Db::commit();//事务提交
return json($res);
}catch (Exception $e){
Db::rollback();
return json(['state'=>-1,'msg'=>'获取失败']);
}
}
二、触发器
基本描述:触发器(TRIGGER)是由事件来触发某个操作。这些事件包括INSERT语句、UPDATE语句和DELETE语句。当数据库系统执行这些事件时,会激活促发其执行相应的操作。
(1)查看数据库版本
select version();
(2)显示触发器
SHOW TRIGGERS;
(3)删除触发器
DROP TRIGGER 触发器名;
(4)语法格式
CREATE TRIGGER 触发器名 BEFORE UPDATE
ON 表名 FOR EACH ROW
BEGIN
执行语句;
END;
(5)例子
CREATE TRIGGER test_trigger BEFORE UPDATE
ON test1_table FOR EACH ROW
BEGIN
insert into test2_table(testId,name,time)value(old.testId,old.name,old.UpdateTime);
END;
三、存储过程
基本描述:一系列数据库操作的集合,包括增删查改,同时也支持嵌套,可传入参数,但无返回值;
在实际开发中,可进行加密解密操作,安全性高;循环使用游标操作,sql语音较难;数据操作在Db层,极大提高了性能。
把查询结果赋值到变量,大部分情况下使用游标来完成,但是如果明确知道查询结果只有一行(例如统计记录的数量,某个字段求和等),其实可以使用set或into的方式来实现赋值。
AES_ENCRYPT(str,
k
e
y
)
=
>
加
密
A
E
S
D
E
C
R
Y
P
T
(
s
t
r
,
key)=>加密 AES_DECRYPT(str,
key)=>加密AESDECRYPT(str,key)=>解密
(1)创建存储过程
CREATE DEFINER=`root`@`%` PROCEDURE `productName`(openid varchar(50))
BEGIN
DECLARE openid_value VARCHAR(50);
set openid_value=openid;
update Egg_record_deal set money=1 where openid_RXD=openid_value;
END
(2)调用存储过程
CALL productName('1')
(3)删除存储过程
drop procedure productName;
四、自定义函数
基本描述:在复杂的业务处理以及安全系数较高的操作,可进行写自定义函数,把逻辑写在DB层,很好提高了处理效率。注意点,在navacat中创建自定义函数,在传入参数需要把函数类型的字段长度加上。
(1)例子
CREATE DEFINER=`root`@`%` FUNCTION `funcName`(`openid` varchar(50)) RETURNS int(10)
BEGIN
#Routine body goes here...
DECLARE openid_value VARCHAR(50);
DECLARE egg_num int(10);
set openid_value=openid;
select money into egg_num from Egg_record_deal where openid_RXD=openid_value;
RETURN egg_num;
END
注意:函数必须要有返回值,传入的参数不能和字段名相同。
五、游标
基本描述:
游标实际上是一种能从包括多条数据记录的结果集中每次提取一条记录的机制。
游标充当指针的作用,能遍历结果中的所有行,但他一次只指向一行。
作用是用于对查询数据库所返回的记录进行遍历,以便进行相应的操作。
游标不单独使用,通常与存储过程,函数一起使用。
(1)语法
//定义字段 field1,field2
DECLARE field1,field2 VARCHAR(50);
//定义计数器
DECLARE num int(10);
//创建游标
DECLARE cur_TXD CURSOR for select 数据库字段1 as field1,数据库字段1 as field2 from table where 条件;
//结束标志
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2=1;
select count(*) into num from table where 条件;
//赋值
set num = num+1;
//打开游标
open cur_TXD;
//开始游标循环
posLoop:LOOP
//结束标志1,若只设置1,不设置2,会出现循环的最后一条执行2次的情况,所有要设置结束标志2,具体情况没有去深究。
IF done2=1 THEN
LEAVE posLoop;
END IF;
//从游标中取出只field1,field2,需要和上面对应上,否则会报错。
FETCH cur_TXD into field1,field2;
结束标志2
set num = num-1;
if num = 0 then
LEAVE posLoop;
end if;
//业务操作
update table set 数据库字段1=field1 where 数据库字段2=field2;
END LOOP posLoop;
CLOSE cur_TXD;
六、定时任务
(1)查看配置,若是 OFF,需要开启,可操作
SHOW VARIABLES LIKE '%event_scheduler%';
SET GLOBAL event_scheduler = on;
下面是应用在项目的例子,可供参考
存储过程
2.存储过程 produre_everyday_TXD 支出统计
CREATE DEFINER=`root`@`%` PROCEDURE `produre_everyday_TXD`()
BEGIN
#Routine body goes here... AES_ENCRYPT(eggs_all,openid_RXD_1)select count(*) into num from Egg_record_deal where to_days(NOW()) - TO_DAYS(time_c) <= 1;
## 克恐蛋支出统计 统计昨天用户的交易情况Egg_record_deal表,写进Egg_record_totality表,加密 AES_ENCRYPT
## 具有操作将统计出来的eggs_news 和 Egg_record_totality原本有的egg 进行相加
DECLARE openid_TXD_1 VARCHAR(50);
DECLARE done2 int(10);
DECLARE eggs_value2 int(10);
DECLARE eggs_new2 int(10);
DECLARE eggs_all2 int(10);
DECLARE num2 int(10);
DECLARE cur_TXD CURSOR for select openid_TXD as openid_TXD_1,money as eggs_new2 from Egg_record_deal where to_days(NOW()) - TO_DAYS(time_c) <= 1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done2=1;
select count(*) into num2 from Egg_record_deal where to_days(NOW()) - TO_DAYS(time_c) <= 1;
set num2 = num2+1;
open cur_TXD;
posLoop:LOOP
IF done2=1 THEN
LEAVE posLoop;
END IF;
FETCH cur_TXD into openid_TXD_1,eggs_new2;
set num2 = num2-1;
if num2 = 0 then
LEAVE posLoop;
end if;
select AES_DECRYPT(eggs,openid_TXD_1) into eggs_value2 from Egg_record_totality where openid=openid_TXD_1;
set eggs_all2=eggs_value2+eggs_new2;
update Egg_record_totality set eggs=AES_ENCRYPT(eggs_all2,openid_TXD_1),times=times+1 where openid=openid_TXD_1;
END LOOP posLoop;
CLOSE cur_TXD;
END
自定义函数
CREATE DEFINER=`root`@`%` FUNCTION `egg_number`(openid_value VARCHAR(50) ) RETURNS int(11)
BEGIN
DECLARE eggs INT(11);
DECLARE eggs_TXD int(11) DEFAULT 0;
DECLARE eggs_RXD int(11) DEFAULT 0;
select money into eggs_TXD from v_Egg_TXD where openid = openid_value ;
select money into eggs_RXD from v_Egg_RXD where openid = openid_value;
set eggs = eggs_RXD - eggs_TXD;
RETURN eggs ;
END