• Day 37 SQL基础(五)


    事务处理

    事务用于将某些操作的多个SQL作为原子性操作,一旦有某一个出现错误,即可回滚到原来的状态,从而保证数据库数据完整性

    开始事务

    start transaction

    标识事务的开始

    回滚事务

    rollback

    用来回退(撤销)SQL语句

    select * from users;
    start transaction;
    update users set age = 18 where id = 120;
    delete from users where name = 'tiny';
    rollback;
    select * from users;
    

    rollback只能在一个事务处理内使用,在执行一条start transaction命令之后

    提交事务

    commit

    一般的MySQL语句都是直接针对数据库表执行和编写的.这就是所谓的隐含提交,即提交(写或保存)操作是自动进行的.

    但是.在事务处理块中,提交不会隐含地进行.为进行明确的提交,使用commit语句

    start transaction;
    update users set age = 18 where id = 120;
    delete from users where name = 'tiny';
    commit;
    

    事务的特性

    • 原子性(Atomicity): 原子意为最小的粒子,即不能再分事务,要么全部执行,要么全部取消
    • 一致性(Consistency): 指事务发生前发生后,数据的总额依然匹配
    • 隔离性(Isolation): 简单点说,某个事务的操作对其他事务是不可见的
    • 持久性(Durability): 当事务完成后,其影响应该保留下来,不能撤销,只能通过'补偿性事务'来抵消之前的错误

    存储引擎

    什么是存储引擎

    MySQL中的数据用各种不同的技术存储在文件(或者内存)中。这些技术中的每一种技术都使用不同的存储机制、索引技巧、锁定水平并且最终提供广泛的不同的功能和能力。通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能。

    例如,如果你在研究大量的临时数据,你也许需要使用内存存储引擎。内存存储引擎能够在内存中存储所有的表格数据。又或者,你也许需要一个支持事务处理的数据库(以确保事务处理不成功时数据的回退能力)。

    这些不同的技术以及配套的相关功能在MySQL中被称作存储引擎(也称作表类型)。

    MySQL默认配置了许多不同的存储引擎,可以预先设置或者在MySQL服务器中启用。你可以选择适用于服务器、数据库和表格的存储引擎,以便在选择如何存储你的信息、如何检索这些信息以及你需要你的数据结合什么性能和功能的时候为你提供最大的灵活性。

    选择如何存储和检索你的数据的这种灵活性是MySQL为什么如此受欢迎的主要原因。其它数据库系统 (包括大多数商业选择)仅支持一种类型的数据存储

    遗憾的是,其它类型的数据库解决方案采取的“一个尺码满足一切需求”的方式意味着你要么就牺牲一些性能,要么你就用几个小时甚至几天的时间详细调整你的数据库。使用MySQL,我们仅需要修改我们使用的存储引擎就可以了。

    mysql5.6支持的存储引擎包括InnoDB、MyISAM、MEMORY、CSV、BLACKHOLE、FEDERATED、MRG_MYISAM、ARCHIVE、PERFORMANCE_SCHEMA。其中NDB和InnoDB提供事务安全表,其他存储引擎都是非事务安全表。

    各存储引擎的特性

    概览

    MySQL服务器采用了多层设计和独立模块,插件式存储引擎体系结构,允许将存储引擎加载到正在运新的MySQL服务器中,图中的Pluggable Storage Engines部分。采用MySQL服务器体系结构,由于在存储级别上(也就是Pluggable Storage Engines)提供了一致和简单的应用模型和API,应用程序编程人员和DBA可不再考虑所有的底层实施细节。因此,尽管不同的存储引擎具有不同的能力,应用程序是与之分离的。存储引擎就司职与文件系统打交道了。

    各种存储引擎的特性

    1. 并发性:某些应用程序比其他应用程序具有很多的颗粒级锁定要求(如行级锁定)。
    2. 事务支持:并非所有的应用程序都需要事务,但对的确需要事务的应用程序来说,有着定义良好的需求,如ACID兼容等。
    3. 引用完整性:通过DDL定义的外键,服务器需要强制保持关联数据库的引用完整性。
    4. 物理存储:它包括各种各样的事项,从表和索引的总的页大小,到存储数据所需的格式,到物理磁盘。
    5. 索引支持:不同的应用程序倾向于采用不同的索引策略,每种存储引擎通常有自己的编制索引方法,但某些索引方法(如B-tree索引)对几乎所有的存储引擎来说是共同的。
    6. 内存高速缓冲:与其他应用程序相比,不同的应用程序对某些内存高速缓冲策略的响应更好,因此,尽管某些内存高速缓冲对所有存储引擎来说是共同的(如用于用户连接的高速缓冲,MySQL的高速查询高速缓冲等),其他高速缓冲策略仅当使用特殊的存储引擎时才唯一定义。
    7. 性能帮助:包括针对并行操作的多I/O线程,线程并发性,数据库检查点,成批插入处理等。
    8. 其他目标特性:可能包括对地理空间操作的支持,对特定数据处理操作的安全限制等。

    各存储引擎的介绍

    InnoDB:MySql 5.6 版本默认的存储引擎。InnoDB 是一个事务安全的存储引擎,它具备提交、回滚以及崩溃恢复的功能以保护用户数据。InnoDB 的行级别锁定以及 Oracle 风格的一致性无锁读提升了它的多用户并发数以及性能。InnoDB 将用户数据存储在聚集索引中以减少基于主键的普通查询所带来的 I/O 开销。为了保证数据的完整性,InnoDB 还支持外键约束。

    MyISAM:MyISAM既不支持事务、也不支持外键、其优势是访问速度快,但是表级别的锁定限制了它在读写负载方面的性能,因此它经常应用于只读或者以读为主的数据场景。

    Memory:在内存中存储所有数据,应用于对非关键数据由快速查找的场景。Memory类型的表访问数据非常快,因为它的数据是存放在内存中的,并且默认使用HASH索引,但是一旦服务关闭,表中的数据就会丢失

    BLACKHOLE:黑洞存储引擎,类似于 Unix 的 /dev/null,Archive 只接收但却并不保存数据。对这种引擎的表的查询常常返回一个空集。这种表可以应用于 DML 语句需要发送到从服务器,但主服务器并不会保留这种数据的备份的主从配置中。

    CSV:它的表真的是以逗号分隔的文本文件。CSV 表允许你以 CSV 格式导入导出数据,以相同的读和写的格式和脚本和应用交互数据。由于 CSV 表没有索引,你最好是在普通操作中将数据放在 InnoDB 表里,只有在导入或导出阶段使用一下 CSV 表。

    NDB:(又名 NDBCLUSTER)——这种集群数据引擎尤其适合于需要最高程度的正常运行时间和可用性的应用。注意:NDB 存储引擎在标准 MySql 5.6 版本里并不被支持。目前能够支持

    MySql 集群的版本有:基于 MySql 5.1 的 MySQL Cluster NDB 7.1;基于 MySql 5.5 的 MySQL Cluster NDB 7.2;基于 MySql 5.6 的 MySQL Cluster NDB 7.3。同样基于 MySql 5.6 的 MySQL Cluster NDB 7.4 目前正处于研发阶段。

    Merge:允许 MySql DBA 或开发者将一系列相同的 MyISAM 表进行分组,并把它们作为一个对象进行引用。适用于超大规模数据场景,如数据仓库。

    Federated:提供了从多个物理机上联接不同的 MySql 服务器来创建一个逻辑数据库的能力。适用于分布式或者数据市场的场景。

    Example:这种存储引擎用以保存阐明如何开始写新的存储引擎的 MySql 源码的例子。它主要针对于有兴趣的开发人员。这种存储引擎就是一个啥事也不做的 "存根"。你可以使用这种引擎创建表,但是你无法向其保存任何数据,也无法从它们检索任何索引。

    视图

    视图是一个虚拟表(非真实存在),其本质根据SQL语句获取动态的数据集,并为其命名,用户使用时只需使用名称即可获取结果集,可以将该结果集当做表来使用.

    使用视图我们可以把查询过程中的临时表摘出来,用视图去实现,这样以后再想操作该临时表的数据是就无需重写复杂的SQL了,直接去视图中查找即可,但视图有明显的效率问题,并且视图是放在数据库中的,如果我们程序中使用的SQL过分依赖数据库中的视图,即强耦合,那就意味着扩展SQL极为不便,因此并不推荐使用

    创建视图

    create view users_view as select * from users;
    select * from users_view;
    

    删除视图

    drop view users_view
    

    修改视图

    alter view user_view as select * from users where id > 1000;
    

    我们不能够直接修改视图内是记录,而且在涉及多个表的情况下是根本无法修改视图中的记录的,但是当我们直接修改表内的记录时,视图中的记录也会发生相应的变化

    触发器

    触发器是MySQL响应一下任意语句而自动执行的一条MySQL语句(或位于BEGIN和END语句之间的一组语句):

    delete

    insert

    update

    其他MySQL语句不支持触发器

    创建触发器

    在创建触发器时,需要给出4条信息

    • 唯一的触发器名
    • 触发器关联的表
    • 触发器应该响应的活动
    • 触发器何时执行

    触发器用create trigger语句创建

    # 插入前
    CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 插入后
    CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 删除前
    CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 删除后
    CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 更新前
    CREATE TRIGGER tri_before_update_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    
    # 更新后
    CREATE TRIGGER tri_after_update_tb1 AFTER UPDATE ON tb1 FOR EACH ROW
    BEGIN
        ...
    END
    

    触发器无法由用户直接调用,而由对表的操作被动引发的

    删除触发器

    drop trigger newproduct;
    

    存储过程

    存储过程包含了一系列可执行的SQL语句,存储过程放于MySQL中,通过调用它的名字可以执行其内部的一堆SQL

    存储过程的优点:

    • 用于替代程序写的SQL语句,实现程序与SQL的解耦

    • 基于网络的传输,传别名的数据量小,而直接传sql数据量大

    缺点:

    • 程序员扩展功能不方便

    创建无参存储过程

    delimiter //
    create procedure p1()
    BEGIN
        select * from blog;
        INSERT into blog(name,sub_time) values("xxx",now());
    END //
    delimiter ;
    
    #在mysql中调用
    call p1() 
    
    #在python中基于pymysql调用
    cursor.callproc('p1') 
    print(cursor.fetchall())
    

    创建有参存储过程

    对于存储过程,可以接收参数,其参数有三种:

    in 仅用于传入参数用

    out 用于返回值

    inout 既可以传入又可以当作返回值

    # in:传入参数
    delimiter //
    create procedure p2(
        in n1 int,
        in n2 int
    )
    BEGIN
        
        select * from blog where id > n1;
    END //
    delimiter ;
    
    #在mysql中调用
    call p2(3,2)
    
    #在python中基于pymysql调用
    cursor.callproc('p2',(3,2))
    print(cursor.fetchall())
    
    # out:返回值
    delimiter //
    create procedure p3(
        in n1 int,
        out res int
    )
    BEGIN
        select * from blog where id > n1;
        set res = 1;
    END //
    delimiter ;
    
    #在mysql中调用
    set @res=0; #0代表假(执行失败),1代表真(执行成功)
    call p3(3,@res);
    select @res;
    
    #在python中基于pymysql调用
    cursor.callproc('p3',(3,0)) #0相当于set @res=0
    print(cursor.fetchall()) #查询select的查询结果
    
    cursor.execute('select @_p3_0,@_p3_1;') #@p3_0代表第一个参数,@p3_1代表第二个参数,即返回值
    print(cursor.fetchall())
    
    # inout:既可以传入又可以返回
    delimiter //
    create procedure p4(
        inout n1 int
    )
    BEGIN
        select * from blog where id > n1;
        set n1 = 1;
    END //
    delimiter ;
    
    #在mysql中调用
    set @x=3;
    call p4(@x);
    select @x;
    
    
    #在python中基于pymysql调用
    cursor.callproc('p4',(3,))
    print(cursor.fetchall()) #查询select的查询结果
    
    cursor.execute('select @_p4_0;') 
    print(cursor.fetchall())
    

    执行存储过程

    在MySQL中执行:

    -- 无参数
    call proc_name()
    
    -- 有参数,全in
    call proc_name(1,2)
    
    -- 有参数,有in,out,inout
    set @t1=0;
    set @t2=3;
    call proc_name(1,2,@t1,@t2)
    

    在python中基于pymysql执行:

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    import pymysql
    
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123', db='t1')
    cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
    # 执行存储过程
    cursor.callproc('p1', args=(1, 22, 3, 4))
    # 获取执行完存储的参数
    cursor.execute("select @_p1_0,@_p1_1,@_p1_2,@_p1_3")
    result = cursor.fetchall()
    
    conn.commit()
    cursor.close()
    conn.close()
    
    
    print(result)
    

    删除存储过程

    drop procedure proc_name;
    

    SQL函数

    MySQL提供了许多内置函数

    CHAR_LENGTH(str)
    		返回值为字符串str 的长度,长度的单位为字符。一个多字节字符算作一个单字符。
    		对于一个包含五个二字节字符集, LENGTH()返回值为 10, 而CHAR_LENGTH()的返回值为5。
    	
    	CONCAT(str1,str2,...)
    		字符串拼接
    		如有任何一个参数为NULL ,则返回值为 NULL。
    	FORMAT(X,D)
    		将数字X 的格式写为'#,###,###.##',以四舍五入的方式保留小数点后 D 位, 并将结果以字符串的形式返回。若 D 为 0, 则返回结果不带有小数点,或不含小数部分。
    		例如:
    			SELECT FORMAT(12332.1,4); 结果为: '12,332.1000'
    	INSTR(str,substr)
    		返回字符串 str 中子字符串的第一个出现位置。
    	LEFT(str,len)
    		返回字符串str 从开始的len位置的子序列字符。
    	LOWER(str)
    		变小写
    	UPPER(str)
    		变大写
    	LTRIM(str)
    		返回字符串 str ,其引导空格字符被删除。
    	RTRIM(str)
    		返回字符串 str ,结尾空格字符被删去。
    	SUBSTRING(str,pos,len)
    		获取字符串子序列
    	LOCATE(substr,str,pos)
    		获取子序列索引位置
    	REPEAT(str,count)
    		返回一个由重复的字符串str 组成的字符串,字符串str的数目等于count 。
    		若 count <= 0,则返回一个空字符串。
    		若str 或 count 为 NULL,则返回 NULL 。
    	REPLACE(str,from_str,to_str)
    		返回字符串str 以及所有被字符串to_str替代的字符串from_str 。
    	REVERSE(str)
    		返回字符串 str ,顺序和字符顺序相反。
    	RIGHT(str,len)
    		从字符串str 开始,返回从后边开始len个字符组成的子序列
    
  • 相关阅读:
    ThreadLocal垮线程池传递数据解决方案:TransmittableThreadLocal
    java steam 使用指南groupingBy进阶用法
    微言Netty:百万并发基石上的epoll之剑
    ES聚合查询详解(一)
    肝了一个月的Netty知识点(上)
    kafka 如何保证消息不丢失
    IO多路复用
    Java 重入锁
    Kotlin中的协程和多线程比较实验
    mysql性能排查思路
  • 原文地址:https://www.cnblogs.com/2222bai/p/11779042.html
Copyright © 2020-2023  润新知