MySQL (八)

1 事务

  • 需求:有一张银行账户表,A用户给B用户转账,A账户先减少,B账户增加,但是A操作完之后断电了。
  • 解决方案:A减少钱,但是不要立即修改数据表,B收到钱之后,同时修改数据表。
  • 事务:一系列要发生的连续的操作。
  • 事务安全:一种保护连续操作同时满足(实现)的机制,事务安全的意义:保证数据操作的完成性。
  • 示例SQL脚本
-- 创建一个账户表
CREATE TABLE my_account(
       id int primary key auto_increment,
    number CHAR(16) NOT NULL COMMENT ‘账户‘,
    NAME VARCHAR(20) NOT NULL COMMENT ‘姓名‘,
    money DECIMAL(10,2) DEFAULT 0.0 COMMENT ‘账户余额‘
);
-- 插入数据
INSERT INTO my_account VALUES (null,‘0000000000000001‘,‘张三‘,1000);
INSERT INTO my_account VALUES (null,‘0000000000000002‘,‘李四‘,2000);

-- 张三转账
UPDATE my_account SET money = money - 1000 WHERE NAME = ‘张三‘;

    • 张三一转完钱,就退出了系统,然后,可怕的是,李四没有收到,那么张三就少了这1000元,很可怕,如果天下银行都这么办,估计银行早就倒闭了。那怎么办,那就是要进行事务操作。  

1.1 事务操作

  • 事务操作有两种:自动事务(默认的)和手动事务。
  • 手动事务:操作流程

    • ①开启事务(start transaction):告诉系统以下所有的操作(写)不要直接写入到数据库,先存放到事务日志。 

    • ②进行事务操作:一系列的操作(李四借钱给张三)。

      • 李四账户减少
-- 事务操作:1李四账户减少1000
UPDATE my_account SET money = money -1000 WHERE NAME = ‘李四‘;

SELECT * FROM my_account;

我们在开启一个客户端,会发现如下的状况。

      • 张三账户增加    
-- 事务操纵:2张三账户增加1000
UPDATE my_account SET money = money +1000 WHERE NAME = ‘张三‘;
SELECT * FROM my_account;

我们如果再开启一个客户端,会发生如下状况

    • 关闭事务:选择性的将事务日志文件中的操作结果保存到数据表(同步)或直接清空事务日志(原来的操作全部清空)。

      • 提交事务(commit):同步数据表(操作成功)    
-- 提交事务
COMMIT;

当提交完事务的时候,我们会发现再开启一个客户端,两边的数据是一样的。

      • 回滚事务(rollback):直接清空日志表(操作失败)    

1.2 事务原理

  • 事务操作原理:事务开启之后,所有的操作都会临时保存到事务日志,事务日志只有在得到commit命令才会同步到数据库表,其它任何情况都会清空事务日志(rollback,断电,断开连接)。

1.3  回滚点

  • 回滚点:在某个成功的操作完成之后,后续的操作有可能成功或失败,但是不管成功还是失败,前面的操作都已经成功;那么就可以在当前成功的位置,设置一个点,供后续失败操作返回到该位置,而不是返回所有操作,这个点就是回滚点。
  • 设置回滚点:savepoint 回滚点名字。
  • 回到回滚点:rollback to 回滚点名字。
-- 开启事务
START TRANSACTION;

-- 事务处理1:张三发工资
UPDATE my_account SET money = money + 10000 WHERE NAME = ‘张三‘;

-- 设置回滚点
SAVEPOINT sp1;

-- 银行扣税
UPDATE my_account SET money = money - 10000 * 0.5 WHERE NAME = ‘李四‘;

-- 回滚到回滚点
ROLLBACK TO sp1;

-- 继续给张三扣税
UPDATE my_account SET money = money - 10000 * 0.5 WHERE NAME = ‘张三‘;

-- 事务提交
COMMIT;

1.4 自动事务

  • 在MySQL中:默认的都是自动事务处理,用户操作完全会立即同步到数据表中。
  • 自动事务:系统通过autocommit的变量空控制。
SHOW VARIABLES LIKE ‘autocommit‘;

  • 关闭自动事务:set autocommit = off;
SET autocommit = off;

  • 再次开启自动事务:set autocommit = on;

1.5 事务的特定(ACID)

  • 事务有四大特性:ACID

    • ①A:atomic,原子性,事务的整体是一个操作,不可分割,要么全部成功,要么全部失败。
    • ②C:consistency,一致性,事务操作的前后,事务表中的数据没有变化。
    • ③I:isolation,隔离性,事务操作是相互隔离不受影响的。
    • ④D:durability,持久性,数据一旦提交,不可该表,永久的改变数据表数据。  
  • 锁机制:innodb默认是行锁,但是如果在事务操作的过程中,没有使用到索引,那么系统会自动全表检索数据,自动升级为表锁。

    • 行锁:只有当前行被锁住,别的用户不能操作。
    • 表锁:整张表被锁住,别的用户不能操作。  

2 变量

  • 变量分为两种:系统变量和自定义变量。

2.1 系统变量

  • 系统变量:系统定义好的变量,大部分的时候用户根本不需要使用系统变量,系统变量是用来控制服务器的表现的,如autocommit等。
  • 查看系统变量
-- 查看所有系统变量
SHOW VARIABLES;
  • 查看具体的系统变量的值:select @@系统变量名;
select @@version,@@autocommit;

  • 修改系统变量

    • 修改系统变量分为两种:会话级别和全局级别

      • 会话级别:临时修改,当前客户端当次连接有效。    
set 变量 = 值;
      • 全局级别:一个修改,永久生效(多所有客户端都生效)    
set global 变量名 = 值;

2.2 自定义变量

  • 定义变量:

    • 系统为了区别是系统变量还是自定义变量,规定自定义变量前面必须加@  
set @变量 = 值;
    • 查看自定义变量  
slect @变量;
  • 在MySQL中,"="会默认的当做比较符号处理(很多地方),MySQL为了区分比较还是赋值的概念,重新定义了一个新的赋值符号: :=。当然,这个符号一般在SQL编程中使用。
  • MySQL允许从数据表中获取数据,然后赋值给变量,有两种方式。

    • ①边赋值,边查看结果  
select @变量名 := 字段名 from 数据源;-- 从字段中取值赋给变量名
    • ②只有赋值,没有结果,要求严格:数据记录最多只允许获取一条,MySQL不支持数组。  
select 字段名  from  数据源 [where 条件] into 变量列表
SELECT NAME FROM my_account WHERE id = 1 INTO @name;
SELECT @name;

  • 所有自定义变量都是会话级别:当前客户端当次连接有效。

3 触发器

  • 触发器:trigger,事先为某张表绑定好一段代码,当表中的某些内容发生改变的时候(增、删、改),系统会自动触发代码,执行。
  • 触犯器:事件类型、触发时间、触发对象。

    • 事件类型:增、删、改。
    • 触发时间:前后,before和after。
    • 触发对象:表中的每一条记录,针对行的。  
  • 一张表中只能有一种触发时间的一种类型的触发器,最多一张表有6个触发器。

3.1 创建触发器

  • 触发器基本语法:
-- 临时修改语句结束符
DELIMITER 自定义符号:后续代码中只有碰到自定义符号才算结束

CREATE TRIGGER 触发器名字 触发时间 事件类型 ON 表名 FOR EACH ROW
BEGIN -- 代表左大括号 开始

-- 里面就是触发器的内容:每行内容都必须使用;结束

END  -- 代表右大括号 结束
-- 语句结束符
自定义符号

-- 将邻水修改修正过来
DELIMITER ;
  • 示例脚本:
CREATE TABLE goods(
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20) NOT NULL,
    price DECIMAL(10,2) DEFAULT 1,
    inv INT COMMENT ‘库存数量‘
);

INSERT INTO goods VALUES (NULL,‘iphone6‘,2680,100);
INSERT INTO goods VALUES (NULL,‘iphone6s‘,2880,100);

CREATE TABLE `order`(
    id INT PRIMARY KEY AUTO_INCREMENT,
    g_id INT NOT NULL COMMENT ‘商品id‘,
    g_number INT COMMENT ‘商品数量‘
);
  • 创建触发器
-- 触发器:订单生成一个,商品库存减少一个
 -- 临时修改语句结束符
DELIMITER /
CREATE TRIGGER after_order AFTER INSERT ON `order` FOR EACH ROW
BEGIN
    UPDATE goods SET inv = inv -1 WHERE id = 2;

END
-- 结束触发器
/
-- 修改临时语句结束符
DELIMITER ;

3.2 查看触发器

  • 查看所有触发器或者模糊匹配
show triggers like ‘pattern‘;

  • 查看触发器创建语句
show create trigger after_order;

  • 所有的触发器都会保存在information_schema.triggers表中。

3.3 使用触发器

  • 触发器:不需要手动调用,当某种情况发生的时候会自动触发。
  • 插入订单
SELECT * FROM goods;

INSERT INTO `order` VALUES (NULL,1,2);
SELECT * FROM goods;

    • ①触犯器的确工作了:订单生成了后,对应的商品表的商品数量减少了。②当前商品减少了,并不是订单中产生的商品;而是固定死的商品(触发器不合适)。  

3.4 修改触发器&删除触发器

  • 触发器不能被修改,只能先删除,再新增新的触发器。
drop trigger 触发器名字;

3.5 触发器记录

  • 触发器记录:不管触发器是否触发了,只要当某种操作准备执行,系统就会将当前要操作记录的当前状态和即将执行之后新的状态给分别保留下来,供触发器使用。其中,要操作当前状态保存到old中,操作之后的可能状态保存给new。

  • old代表的是旧记录,new代表的是新记录。

    • 删除的时候是没有new的,而插入的时候是没有old的。  
  • old和new都是代表记录本身:任何一条记录除了有数据,还有字段名称

    • 使用方式:old.字段/new.字段。  
DELIMITER $$

CREATE

    TRIGGER `after_order` AFTER INSERT ON `order`
    FOR EACH ROW BEGIN
    UPDATE goods SET inv = inv -new.g_number WHERE id = new.g_id;
END;
$$

DELIMITER ;
SELECT * FROM goods;

INSERT INTO `order` VALUES (NULL,1,2);

时间: 2024-10-10 16:15:21

MySQL (八)的相关文章

mysql八:ORM框架SQLAlchemy

阅读目录 一 介绍 二 创建表 三 增删改查 四 其他查询相关 五 正查.反查 一 介绍 SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果. 1.安装 pip3 install sqlalchemy  2.架构与流程 #1.使用者通过ORM对象提交命令 #2.将命令交给SQLAlchemy Core(Schema/Types SQL Express

使用c3p0与DBCP连接池,造成的MySql 8小时问题解决方案

本文提供了对c3p0与DBCP连接池连接MySql数据库时, 8小时内无请求自动断开连接的解决方案.首先介绍一下我在项目(c3p0连接池)中遇到的问题,后面还提供了使用DBCP连接池的解决方案. 项目环境: Java Web项目框架为Spring MVC+JPA,使用c3p0连接池,发布环境为Tomcat 7 错误描述: 项目运行一段时间(大概几个小时)之后访问时会出现第一次访问报错,再次访问正常的现象,且多次出现此问题. 报错日志: [plain] view plaincopy org.spr

MySQL 5.6对已有Mysql单实例的机器,再添加mysql数据库,实现单机多实例

一.需求: 对已有Mysql单实例的机器,再添加两个mysql数据库,实现单机多实例. 一个绑定在端口3306,另外两个绑定在端口3307,3308: 数据分别存放在/data/mysqldata./data/mysqldata2./data/mysqldata3 三个实例均采用InnoDB作为默认的存储引擎,字符编码采用UTF-8: 三个实例均采用相同的性能优化配置参数: MySQL的源码安装请看我的另一篇博客http://yylinux.blog.51cto.com/8831641/1677

MYSQL的单机多实例部署

Centos6.6安装并配置单机多实例的MYSQL数据库 本文介绍安装单机多实例的MYSQL数据库的环境如下: 系统平台环境:Centos6.6 Mysql软件包:Mysql-5.5.32.tar.gz 一:安装MYSQL需要的依赖包和编译软件 #yum install ncurses-devel libaio-devel -y 二:安装编译MYSQL需要的软件(mysql5.2版本以后都需要使用cmake来编译安装MYSQL) #rpm -ivh cmake-2.8.12.2-4.el6.x8

mysql 5.5源码包安装

注:由于mysql5.5的源码包安装与mysql之前的版本安装方法不同,故写一篇随笔记录.5.5的版本不再是./configure make make install 这里用到了cmake了,cmake是一个跨平台的编译工具. 注意: mysql-5.5以后的版本不能使用make编译,只能使用cmake工具编译安装. cmake指定编译选项的方式不同于make . "./configure" 与 "cmake . "相似 "./configure --he

MySQL 常用基础命令

一.启动与关闭 1.1 Linux下启动mysql 的命令: a. rpm包安装:service mysqld start b. 源码包安装:/usr/local/mysql/bin/mysqld_safe --user=mysql & 1.2 Linux下重启mysql 的命令: a. rpm包安装:service mysqld restart b. 源码包安装: 先关闭mysql /usr/local/mysql/bin/mysqladmin -uroot -p shutdown 再启动my

使用c3p0与DBCP连接池,造成的MySql 8小时问题解决方式

本文提供了对c3p0与DBCP连接池连接MySql数据库时. 8小时内无请求自己主动断开连接的解决方式.首先介绍一下我在项目(c3p0连接池)中遇到的问题,后面还提供了使用DBCP连接池的解决方式. 基本问题解决 项目环境: Java Web项目框架为Spring MVC+JPA,使用c3p0连接池,公布环境为Tomcat 7 错误描写叙述: 项目执行一段时间(大概几个小时)之后訪问时会出现第一次訪问报错,再次訪问正常的现象.且多次出现此问题. 报错日志: org.springframework

MySQL 基础常用命令

一.启动与关闭 1.1 Linux下启动mysql 的命令: a. rpm包安装:service mysqld start b. 源码包安装:/usr/local/mysql/bin/mysqld_safe --user=mysql & 1.2 Linux下重启mysql 的命令: a. rpm包安装:service mysqld restart b. 源码包安装: 先关闭mysql /usr/local/mysql/bin/mysqladmin -uroot -p shutdown 再启动my

【MySQL】mysql root密码忘记怎么办?

MySQL忘记密码了怎么解决 笔者曾经有一次误删了mysqlroot用户,怎么办? 之前的解决方式是通过忽略授权表的方式重启mysql然后插入相关数据解决该问题的,但是这种方式需要重启mysql,会影响现有业务,那么有没有其他方式可以不重启MySQL就解决呢? 因为mysql的user表示MyISAM引擎的,因此我们可以通过修改对应的文件来解决这个问题.下面是本人在测试环境的一次演练,仅供参考. 一.查看现有用户 04:18:34 [email protected] [mysql]>select

centos7下使用mysql离线安装包安装mysql5.7

服务器环境: centos7 x64 需要安装mysql5.7+ 一.卸载CentOS7系统自带mariadb # 查看系统自带的Mariadb [root@CDH-141 ~]# rpm -qa|grep mariadb mariadb-libs-5.5.44-2.el7.centos.x86_64 # 卸载系统自带的Mariadb [root@CDH-141 ~]# rpm -e --nodeps mariadb-libs-5.5.44-2.el7.centos.x86_64 # 删除etc