事务、变量以及触发器
事务
需求:
一张表是银行账户表,有A 用户 给 B 用户转账,B账户增加,A账户减少
问题:
当A用户执行完转账操作的时候,A用户的账上减少两千元钱之后,银行的系统断电了,那么B用户的账户上实际上钱的数量没有任何的增加,那么不管是A用户还是B用户都有很大的损失,那么我们应该如何来解决这个问题呢?
解决方案:
A 减少钱,但是不要立即修改书表,一定要看B 收到了钱之后,同时修改数据表
事务安全:
概念:
transaction一系列要发生的连续操作,一种保护连续操作同时满足(实现)的一种机制
事务安全的意义:
保证数据操作的完整性
事务操作
分类:
自动事务(默认的),手动操作;
手动事务流程:
开启事务:
- 告诉系统以下所有的操作(写入)不要直接写到数据表中 ,我们应该先存放到书屋日志当中去,在一定程度上保证数据操作的安全性。
Start transaction;
- 刘备账户减少
- 孙权账户增加
关闭事务:
- 选择性的将日志文件中操作的结果保存到数据表中(同步)或者说直接清空事务日志(原来的操作全部清空);
- 提交事务:同步数据表(操作成功)commit;
- 回滚事务:直接清空事务日志(失败)rollback;
注意:我们要知道,当事务操作成功的时候,我们再怎么rollback都已经无效了
支持事务安全的免费的引擎只有innodb;
事务操作的原理:
事务开启之后,所有的数据操作都会临时保存到事务日志里面去,事务只有在得到commit命令之后,才会将命令同步到数据表中去,其他的任何情况都会清空事务日志。这就在一定的程度上保证事务的安全性。
回滚点
概念:在某个成功的操作完成之后,后续的左右操作有可能成功 有可能失败,但是不管是否成功,前面的操作都已经成功,那么我们可以在当前成成的位置设置一个点,可以共后续的失败的操作都回到这个位置,而不是返回所有操作,这个点我们 就将之称为回滚点。
设置回滚点基本语法:savepoint 回滚点名字;
回到回滚点基本语法:rollback to 回滚点名字;
自动回滚事务
在mysql中:默认的都是自动的事务处理,用户操作完之后会直接输入到数据表中
自动事务是系统通过autocommit 变量来控制的。
Show variables like 'autocommit;
开始和关闭自动事务
- 开启自动事务的操作
set autocommit = 1;
-
关闭自动事务的操作
set autocommit = 0;
事务的特性
Atomic原子性:
事务的操作是一个整体,是不可分割的,要么全部关闭,要么全部开启。
Consistancy一致性:
事务操作的前后,数据表中的数据是不会改变的,只有我们在commit之后才会将我们操作的数据保存到数据表中去
Isolation隔离性:
事务的操作是相互各部不受影响的
Durability持久性:
数据一旦提交,不可改变,永久的改变表的数据
- 锁机制"innodb默认是行锁,但是如果在数据操作的过程中,没有使用索引字段,那么系统会自动全表进行检索数据,自动升级为表锁
- 行锁:只有当前行被锁住 ,别的用户不能操作
- 表锁:整张表被锁住,别的用户不能操作
=》这具体又是为什么呢?因为开启事务的用户在更新数据的时候,使用的是name,而name这个字段是没有添加索引的,在这种情况下,数据的更新就上升到去整张表查询name符合条件的记录,就上升到了表锁。这样来看,其他的用户就肯定无法对数据进行操作。
- 那么怎么了来解锁呢? 只有当开启事务的用户解锁之后,才能进行操作,在开启事务的用户解锁之前,本用户会有一定的等待时间,如果超过这个等待时间还没有解锁的话,操作就会失败。
什么时候使用事务呢?
基本上我们的操作只有在与钱有关的时候,我们就会使用事务日志,比如说i,我们银行的账户系统就会使用事务安全,因为这个在一定程度上保证我们所做的操作的安全性。
变量
系统变量:
- 系统预先定义好的变量,大部分时候用户根本不需要使用系统变量:系统变量是用来控制服务器的表现,如:autocommit、auto_increment、increment等
- 查看所有的系统变量 Show variabales;
- 查看具体的变量值 : 任何一个有数据返回的内容都是由select 查看 Select @@变量名;
-
修改系统变量
分类:会话级别和全局级别
会话级别:临时修改,当次数据库的操作有效
Set 变量名 = 值;
Set @@ 变量名 = 值;
全局级别:一次修改,永久生效。而且会对所有客户生效;
Set global 变量名 = 值;
自定义变量:
定义自定义变量:
基本语法: set @变量名 = 变量值;
自定义变量也类似于系统变量的查看;
查看自定义变量:
Select @变量名字;
注意:在mysql中 '='不是赋值符号,而是比较符号,我们在定义变量的时候,使用的赋值符号通常使用的是 ':='
Mysql中允许从数据表中查看数据,然后赋值给变量两种方式:
方案一:边赋值边查看结果 select @变量名 := 字段名 from 数据源; 如果使用等号会直接变成比较;
方案二:直接给变量赋值:只有赋值,不看结果,但是要求很严格:数据的记录只允许获取一条记录,因为mysql不支持数组,Select 字段列表 from 表名 where条件 into 变量列表;
触发器
概念:
- trigger,事先为表绑定好一段代码,当表中的某些内容发生改变的时候(增删改)系统会自动触发该代码,然后执行
- 内涵:事件类型、触发时间、触发对象
- 事件类型:增删改,三种类型:insert 、delete 、 update
- 触发时间:前后 before 和after
- 触发对象:表中的每一条记录;
一张表中只能有一种触发时间的一种类型的触发器,一张表最多有六个触发器
触发器的创建:
在生气了中没有大括号,小括号,中括号,都是用对应的字母符号来代替
基本语法:
- 临时修改语句结束符号:
Delimiter 自定义符号:后续的代码中碰到自定义的代码就结束
Create trigger 触发器名字 触发时间 事件类型 on 表名 for each row
Begin
--代表的是左大括号,里面就是触发器的内容,每行的内容都必须使用结束符:分号
End --代表的是右大括号,代表的是整个触发器内容的结束。
--语句结束符
自定义符号
--将临时自定义的符号修改回来
Delimiter ;
触发器的查看:
Show triggers;
我们还可以查看触发器的创建语句
Show create trigger 触发器名字:
注意:所有的触发器都会保存到一张表中Information_schema.triggers;
触发器的使用:
问题:以上的实例中出现了一个问题:就是当前商品的订单成功录入的时候,,库存减少的不是订单中的商品,而是固定死的商品,这显然不符合我们的需求
解决方案:
触发器:不需要手动调用,而是当某种情况发生的时候名,就会自动调用。
触发器的更改&删除:
触发器的修改,只能先删除才能修改
- 删除触发器:drop trigger;
- 触发器记录:不管触发器是否触发了,只要某种操作准备执行,系统就会将当前遥操作记录的当前状态和即将执行之后的状态分别保留下来,供触发器使用:其中要操作的当前状态保存到old中,将操作之后的可能状态保存到new中 Old代表的就是旧记录,但是不代表任何时候old都有记录,在插入的时候,old是没有记录的。
New代表的是新纪录,删除的时候是没有新纪录的。
注意:old和new都是代表记录本身,任何一条记录有了数据,还有字段名字。
使用方式:old.字段名 /new.字段名; new是假设之后发生的结果;
注意:如果,触发器内部是有一条sql语句,那么我们可以省略begin 和 end语法规则:create trigger 触发器名字 触发时间 事件类型 on 表名 for each row
一条sql指令;
触发器的意义:
可以很好的协调表内数据处理顺序和关系。但是从java角度出发,触发器会加强数据库的维护强度,所以我们一般较少使用触发器。