事务

事务指的是一组操作,要么执行成功,要么都执行失败

我们来看下面一个例子:

我去银行给朋友汇款,我卡上有1000元,朋友卡有1000元,我给朋友转账100元(无手续费)。如果我的钱刚被扣完,这时候网络突然断了,而朋友账户的钱又没加,怎么办?

我们来模拟一下这个操作:


mysql> create table user(
id int auto_increment primary key,
name varchar(32) not null default '',
salary int not null default 0
)charset=utf8; # 向表中插入数据
mysql> insert into user(name,salary) values ("qinyj",1000);
mysql> insert into user(name,salary) values ("jack",1000); # 此时我们打开两个终端 查看数据
# 一个终端代表qinyj,另一个代表jack
mysql> select * from user where name="qinyj"; mysql> select * from user where name="jack"; # 当我开始转账的时候在我的窗口进行操作
mysql> update user set salary=900 where name="qinyj";
# 这时候模拟网突然断了,转不了账了
# 我们再来查看qinyj的账户
mysql> select * from user where name="qinyj";
# 我们再来看jack的账户
mysql> select * from user where name="jack"; # 发现qinyj已经转账了,账户的钱已经少了100,但是jack的账户的钱却没有增加,那么这就造成了一个数据上的不安全。

模拟完上面的操作之后呢,我们来解决这个问题

解决这个问题就需要用到mysql的事务:

start transaction:使用事务

commit/rollback:提交事务/回滚事务

例子:

mysql> start transaction;	# 使用事务
Query OK, 0 rows affected (0.00 sec) mysql> update user set salary=900 where name="qinyj";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> update user set salary=1100 where name="jack";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0 mysql> commit; # 提交事务
Query OK, 0 rows affected (0.01 sec) # 如果在commit之前 所有转账sql已经执行完毕了,这时候突然断网了,那么mysql会默认执行rollback操作,将事务中所有操作回滚到使用事务之前的状态,保证了数据的安全
mysql> rollback; # 回滚提交
Query OK, 0 rows affected (0.00 sec) # 我们再来看两个账户的金额:
mysql> select * from user where name="qinyj"; mysql> select * from user where name="jack";

pymysql使用事务

import pymysql

conn = pymysql.connect(
host="192.168.32.130",
password="123",
user="root",
database="test",
charset="utf8"
) cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) try:
sql = "start transaction"
cursor.execute(sql) sql = "update user set salary=800 where name='qinyj'"
cursor.execute(sql) import time
print(".......")
time.sleep(20) sql = "update user set salary=1200 where name='jack'"
cursor.execute(sql)
sql = "commit"
cursor.execute(sql)
except Exception as e: print("事务处理失败")
sql = "rollback"
cursor.execute(sql) cursor.close()
conn.close()

那么我们来总结一下事务的特性特征:

  • 原子性:原子意思为最小的粒子,即不能再分的书屋,要么全部执行,要么全部取消,就像上面银行转账的例子。
  • 一致性:指事务发生前和发生后数据的总额依然匹配。
  • 隔离性:指得是某个事务的操作对其他事务不可见,隔离开来的。
  • 持久性:当事务完成后,影响应该保留下来,不能撤销,只能通过“补偿性事务”来取消之前的错误。

存储引擎

存储引擎负责MySQL中的数据的存储和提取。

MySQL存储引擎有很多,不同的存储引擎保存数据和索引的方式是不同的。每一种存储引擎都有它的优势和劣势

InnoDB存储引擎

InnoDB是默认的事务型存储引擎,也是最重要,使用最广泛的存储引擎。在没有特殊情况下,一般优先使用InnoDB存储引擎。

数据存储形式

使用InnoDB时,会将数据表分为.frm 和 idb两个文件进行存储。

锁的粒度

InnoDB采用MVCC(多版本并发控制)来支持高并发,InnoDB实现了四个隔离级别,默认级别是REPETABLE READ,并通过间隙锁策略防止幻读的出现。它的锁粒度是行锁。【通过MVCC实现,MVCC在稍后会进行介绍】

事务

InnoDB是典型的事务型存储引擎,并且通过一些机制和工具,支持真正的热备份。

数据的存储特点

InnoDB表是基于聚簇索引建立的,聚簇索引对主键的查询有很高的性能,不过他的二级索引(非主键索引)必须包含主键列,索引其他的索引会很大。

MyISAM存储引擎

数据存储形式

MyISAM采用的是索引与数据分离的形式,将数据保存在三个文件中.frm.MYD,.MYIs。

锁的粒度

MyISAM不支持行锁,所以读取时对表加上共享锁,在写入是对表加上排他锁。由于是对整张表加锁,相比InnoDB,在并发写入时效率很低。

事务

MyISAM不支持事务。

数据的存储特点

MyISAM是基于非聚簇索引进行存储的。

其他

MyISAM提供了大量的特性,包括全文索引,压缩,空间函数,延迟更新索引键等。

进行压缩后的表是不能进行修改的,但是压缩表可以极大减少磁盘占用空间,因此也可以减少磁盘IO,从而提供查询性能。

全文索引,是一种基于分词创建的索引,可以支持复杂的查询。

延迟更新索引键,不会将更新的索引数据立即写入到磁盘,而是会写到内存中的缓冲区中,只有在清除缓冲区时候才会将对应的索引写入磁盘,这种方式大大提升了写入性能。

对比与选择

两种存储引擎各有各的有点,MyISAM专注性能,InnoDB专注事务。

如何在两种存储引擎中进行选择?

① 是否有事务操作?有,InnoDB。

②是否存储并发修改?有,InnoDB。

③是否追求快速查询,且数据修改较少?是,MyISAM。

④是否使用全文索引?如果不引用第三方框架,可以选择MyISAM,但是可以选用第三方框架和InnDB效率会更高。

我们在创建表的时候可以指定存储引擎,如果没有指定,默认在mysql5.5版本以上创建的表默认是InnoDB引擎

两个引擎的区别:

  • InnoDB:支持事务;支持行锁
  • MyIsam:不支持事务;支持表锁

查看当前默认存储引擎:

show engines;

在创建表的时候指定引擎:

create table test(id int auto_increment primary key)engine=InnoDB;
create table test(id int auto_increment primary key)engine=MyIsam;

在配置文件中指定:

default-storage-engine=INNODB

常见存储引擎以及使用场景:

  • InnoDB:事务处理应用程序,对于类似击飞系统或者对数据要求比较高的
  • MyIsam:对事务完整性,并发性要求不高,可以使用这个存储引擎。

视图

视图是一种虚拟存在的表,通俗的说 视图就是执行select语句后返回的结果。

增加视图:

create view 视图名 as sql语句

删除视图:

drop view 视图名

例子:

# 如果我们对下面的sql语句查询非常频繁并且这个sql非常长,那么我们可以创建出来一个视图
mysql> select * from user where name="qinyj"; # 创建视图
mysql> create view v1 as select * from user where name="qinyj";
Query OK, 0 rows affected (0.00 sec) # 再查看表,会看到有一个v1的表
show tables; # 那么我们如果想要去查第一个sql,并且这个sql非常长,又不想重新输入一遍,那么我们可以查这个视图,出来效果是一样的。
mysql> select * from v1;

触发器

假设现在有这样一个场景,有两张表,

订单表 库存表

当我们下一个订单的时候,订单表中需要增加一条记录,同时库存表中需要减1,这两个操作是同时发生的,并且前一个操作触发下一个操作,就可以使用触发器

使用方法:

增加触发器:

delimiter //
create trigger boy_before_insert_girl before insert on boy for each row
begin
insert into girl (girl_name) values ("aa");
end //
delimiter ;

例子:

mysql> delimiter //
mysql> create trigger boy_before_insert_girl before insert on boy for each row
-> begin
-> insert into girl (girl_name) values ("aa");
-> end //
Query OK, 0 rows affected (0.00 sec) mysql> delimiter ; # 结束符 mysql> show triggers\G; # 当我们在向boy表中插入数据的时候,我们再来查询girl表的数据会发现会多一条记录 mysql> insert into boy (boy_name) values ("qinyj");
Query OK, 1 row affected (0.01 sec)
mysql> select * from boy;
mysql> select * from girl;

删除触发器:

drop trigger 触发器名

存储过程

像一个SQL函数,一组sql语句集,存储过程就是一段预执行的sql语句,都是一组sql集,存储过程主动调用的时候才会执行。

创建存储过程:

delimiter //
create procedure p1()
begin
select * from boy where id=2;
end //
delimiter ;

查看存储过程:

mysql> show procedure status\G;

删除存储过程:

mysql> drop procedure p1;

调用存储过程:

mysql> call p1();

函数

参考:https://www.runoob.com/mysql/mysql-functions.html

备份

物理备份

可以使用percona-xtrabackup-2.0.7-552.rhel6.x86_64.rpm对mysql进行备份。

xtrabackup官方网址:https://www.percona.com/downloads/XtraBackup/

基本语法--多实例备份--语法解释:

  • --user=数据库用户

  • --password=数据库密码

  • --socket=指定socket

  • --default-file=指定配置文件

  • 最后面是存放位置

    例子:

    innobackupex --user=root --port=3306 --host=127.0.0.1 --defaults-file=/etc/my.cnf --defaults-group=mysqld3306 --stream=tar /usr/local/backup |gzip > 127.0.0.1_3306.tar.gz

全数据还原

  1. /etc/init.d/mysqld stop //停掉mysql
  2. mv /var/lib/mysql /var/lib/mysql_bak //数据目录备份
  3. mkdir -p /var/lib/mysql //重建数据目录
  4. --apply-log选项的命令是准备在一个备份上启动mysql服务
  5. --copy-back 选项的命令从备份目录拷贝数据,索引,日志到my.cnf文件里规定的初始位置
  6. innobackupex --defaults-file=/etc/my.cnf --user=root --apply-log /home/tank/backup/2014-09-18_16-35-12
  7. chown -R mysql.mysql /var/lib/mysql //改变文件所属
  8. /etc/init.d/mysqld stop //启动mysql

备份脚本

#!/bin/bash
# Version V1.1
###############################################
# 保留备份的天数
DAY=3
#等待n秒后再执行备份
wait=60
#是否开启增量备份默认0为开启1为关闭
open_increase_bak=1
#全备时间点
default_time=4
#设置不进行备份的时间点
exclude_time="0 5"
############################################### #载入环境变量,否则无法找到/usr/local/mysql/bin/mysql路径 source /etc/profile DBIP="127.0.0.1" DBUSER="xxx" DBPWD="root" DATE=`date +%F_%H-%M` Hour=`date '+%H'` PORT=`netstat -tunlp|grep mysql |awk '{print $4}'|awk -F: '{print $2}'` MYCNF="/etc/my.cnf" LOG_FILE="/home/msbakscript/logs/xtrabackup.log" BACKUP_PATH="/usr/local/hero_all_backup" MYSQL_LOG="/home/msbakscript/logs/mysql.log" INNOBACKUPEX="/usr/bin/innobackupex" bak_log="/home/msbakscript/logs/mysqlbak.log" MYSQL_PATH="/usr/local/mysql/var" HOST=$(awk -F= '/IPADDR=/ {print $2}' /etc/sysconfig/network-scripts/ifcfg-eth1) CHECKPOINT=$(awk '/to_lsn/ {print $3}' /usr/local/hero_all_backup/xtrabackup_checkpoints 2>/dev/null) all_bak=("$HOST"_"$DATE") increase_bak=("$HOST"_"$DATE""-increase") if [ $# -eq 0 -o $# -eq 1 -o $# -eq 2 ];then echo "OK" > /dev/null else echo "sh $0 allbakfile 或者 sh $0 allbakfile incbakfile" exit 1 fi [ ! -d ${BACKUP_PATH} ] && mkdir -p ${BACKUP_PATH} [ ! -d /home/msbakscript/logs ] && mkdir -p /home/msbakscript/logs if [ -z "`/sbin/pidof -s mysqld`" ];then echo "mysqld is not running" exit 1 fi if [ `rpm -qa |grep -c xtrabackup-0.9-2.rhel4` -eq 1 ];then rpm -e xtrabackup-0.9-2.rhel4 fi if [ ! -f /usr/bin/innobackupex ];then echo "xtrabackup is not installed" rpm -i --nodeps http://122.228.194.133:8080/percona-xtrabackup-2.0.7-552.rhel5.x86_64.rpm elif [ -f /usr/bin/innobackupex ] && [ `ps -ef|grep -v grep |grep -c /usr/bin/innobackupex` -ge 1 ];then echo "xtrabackup process already exist." exit 1 fi complete_bak () { cd ${BACKUP_PATH} ${INNOBACKUPEX} --user=${DBUSER} --password=${DBPWD} --port=${PORT} --host=${DBIP} --defaults-file=${MYCNF} --stream=tar ${BACKUP_PATH}/ 2>>${LOG_FILE} |gzip >${BACKUP_PATH}/${all_bak}_${P ORT}.tar.gz if [ $? -eq 0 ] && [ `tail -10 "${LOG_FILE}" | grep -ic "completed OK"` -eq 1 ];then tar zxvfi ${BACKUP_PATH}/${all_bak}_${PORT}.tar.gz xtrabackup_checkpoints echo "${all_bak}_${PORT}.tar.gz backup successed" >>${bak_log} echo -en "ok\n${all_bak}_${PORT}.tar.gz" >${MYSQL_LOG} sh /home/msbakscript/redis_backup.sh chown nobody.nobody * else echo "${all_bak}_${PORT}.tar.gz backup failed" >>${bak_log} echo -e "failure\n${all_bak}_${PORT}.tar.gz" >${MYSQL_LOG} exit 1 fi } complete_bak increase_bak () { cd ${BACKUP_PATH} if [ ! -f ${BACKUP_PATH}/xtrabackup_checkpoints -o -z ${BACKUP_PATH}/xtrabackup_checkpoints ];then echo "xtrabackup_checkpoints does not exist" >>/{LOG_FILE} complete_bak exit 0 fi ${INNOBACKUPEX} --user=${DBUSER} --password=${DBPWD} --port=${PORT} --host=${DBIP} --defaults-file=${MYCNF} --no-timestamp --incremental --throttle=30 ${BACKUP_PATH}/${increase_bak}_${PORT } --incremental-lsn=${CHECKPOINT} >>${LOG_FILE} 2>&1 if [ $? -eq 0 ] && [ `tail -10 "${LOG_FILE}" | grep -ic "completed OK"` -eq 1 ];then tar zcfi ${increase_bak}_${PORT}.tar.gz ${increase_bak}/ rm -rf ${increase_bak}_${PORT} echo "${increase_bak}_${PORT}.tar.gz backup successed" >>${bak_log} echo -e "ok\n${increase_bak}_${PORT}.tar.gz" >${MYSQL_LOG} else echo "${increase_bak}_${PORT} backup failed" >>${bak_log} echo -e "failure\n${increase_bak}_${PORT}.tar.gz" >${MYSQL_LOG} exit 1 fi
} increase_bak del_bakfile () { for dbfile in `find "${BACKUP_PATH}/" -name "[0-9]*.tar.gz" -type f -mtime +${DAY}`; do rm -f ${dbfile} done } del_bakfile bakmysql () { for i in ${exclude_time[@]};do [ "${Hour}" -eq "$i" ] && exit 0 done if [ "${Hour}" -eq "${default_time}" ];then complete_bak elif [ "${Hour}" -ne "${default_time}" -a ${open_increase_bak} -eq 0 ];then increase_bak else exit 0 fi } bakmysql case $# in 0) bakmysql del_bakfile ;; 1) if [ "$1" = "all" ];then complete_bak del_bakfile elif [ "$1" = "inc" ];then increase_bak del_bakfile else echo "sh $0 all or sh $0 inc" && exit 0 fi ;; esac

逻辑备份

mysqldump工具:逻辑备份工具,适用所有存储引擎温备;支持完全或部分备份;对InnoDB存储引擎支持热备;Schema(数据库的定义)和数据存储在一起。

mysqldump参考:
https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html
语法:
mysqldump [OPTIONS] database [tables]
mysqldump [OPTIONS] –B DB1 [DB2 DB3...]
mysqldump [OPTIONS] –A [OPTIONS]
选项:
-A:备份所有库
-B db_name1,[db_name2,...]:备份指定库
-E:备份相关的所有event scheduler
-R:备份所有存储过程和存储函数
--triggers:备份表相关触发器,默认启用,用--skip-triggers,不备份触发器
--master-data={1|2}:
1:所备份的数据之前加一条记录为CHANGE MASTER TO语句,非注释,不指定默认为1
2:记录为注释的CHANGE MASTER TO语句,注意:此选项会自动关闭--lock-tables功能,自动打开--lock-all-tables功能(除非开启--single-transaction)
-F:备份前滚动日志,锁定表完成后,执行flush logs命令,生成新的二进制日志文件,配合-A时,会导致刷新多次数据库,在同一时刻执行转储和日志刷新,
则应同时使用--flush-logs和-x,--master-data或-single-transaction,此时只刷新一次;建议:和-x,--master-data或 --single-transaction一起使用
--compact 去掉注释,适合调试,生产不使用
-d:只备份表结构
-t:只备份数据,不备份create table
-n:不备份create database,可被-A或-B覆盖
--flush-privileges:备份前刷新授权表,备份mysql库或相关时需要使用
-f:忽略SQL错误,继续执行
--hex-blob:使用十六进制符号转储二进制列(例如,“abc”变为0x616263),受影响的数据类型包括BINARY, VARBINARY,BLOB,BIT
-q:不缓存查询,直接输出,加快备份速度
InnoDB建议备份策略:
mysqldump –uroot –A –F –E –R --single-transaction --master-data=1 --flush-privileges --triggers --hex-blob >$BACKUP/fullbak_$BACKUP_TIME.sql MyISAM建议备份策略:
mysqldump –uroot –A –F –E –R –x --master-data=1 --flush-privileges --triggers --hex-blob >$BACKUP/fullbak_$BACKUP_TIME.sql

补充

1、 null 和 空值有什么区别?

null 占用空间、空不占空间

在查询的时候:

count会忽略null的行数,但不会忽略空值

2、 约束条件限制了not null可以插入空值吗?

可以插入空值

不可以插入null

3、 null 和 空哪个查询效率更高

使用 is not null的时候可以过滤掉 null的值,但是空值过滤不掉

使用count会过滤掉null值,但不会过滤掉空值

MySQL其他和备份的更多相关文章

  1. 如何用SQL语句实现Mysql数据库的备份与还原

    以前一直做android客户端的项目,根本没有开发asp.net mvc的开发,现阶段做了一个模块,参数设置,以及数据库的备份与还原.其需求如下: 参数设置 本项参数设置为对自动数据备份进行设置,管理 ...

  2. 通过innobackupex实现对MySQL的增量备份与还原

    备份 增量备份是基于完整备份的,所以我们需要先做一次完整备份: innobackupex --password=test /backup/ 备注:test是我的MySQL服务的root用户的密码,/b ...

  3. mysql命令行备份数据库

    MySQL数据库使用命令行备份|MySQL数据库备份命令 例如: 数据库地址:127.0.0.1 数据库用户名:root 数据库密码:pass 数据库名称:myweb 备份数据库到D盘跟目录 mysq ...

  4. mysqldump常用于MySQL数据库逻辑备份

    mysqldump常用于MySQL数据库逻辑备份. 1.各种用法说明 A. 最简单的用法: mysqldump -uroot -pPassword [database name] > [dump ...

  5. 我的MYSQL学习心得 备份和恢复(详细)

    备份 逻辑备份方法 使用MYSQLDUMP命令备份 MYSQLDUMP是MYSQL提供的一个非常有用的数据库备份工具.mysqldump命令执行时将数据库备份成一个文本文件, 该文件中实际上包含了多个 ...

  6. 从MySQL全库备份中恢复某个库和某张表【转】

    从MySQL全库备份中恢复某个库和某张表 一.全库备份-A [root@mha2 backup]#mysqldump -uroot -p123456 --default-character-set=u ...

  7. MySQL二进制日志备份和恢复详解

    原文链接:http://www.showerlee.com/archives/681 ****经实践,该教程ok,特在此分享**** 基本概念 定义: 二进制日志包含了所有更新了数据或者已经潜在更新了 ...

  8. MySQL的数据备份以及pymysql的使用

    一.MySQL的数据备份 语法: # mysqldump -h 服务器 -u用户名 -p密码 数据库名 > 备份文件.sql #示例: #单库备份 mysqldump -uroot -p123 ...

  9. MYSQL数据库增量备份

    MySQL数据库增量备份,在这之前修改我们的数据库配置文件/etc/my.cnf开启bin-log日志功能即可.接下来是我参考了下网上的一些方法,自己写的,主要还是要能学到他的一些思路和方法. #fu ...

  10. [知了堂学习笔记]_Java代码实现MySQL数据库的备份与还原

    通常在MySQL数据库的备份和恢复的时候,多是采用在cmd中执行mysql命令来实现. 例如: mysqldump -h127.0.0.1 -uroot -ppass test > d:/tes ...

随机推荐

  1. JVM内核-原理、诊断与优化学习笔记(十一):JVM字节码执行

    文章目录 javap javap 举个

  2. Altium Designer 精心总结(转)

    https://blog.csdn.net/qq_29350001/article/details/52199356 设置铺铜间距规则,Electrical-Clearence_Poly设置如下,是铺 ...

  3. lasso数学解释

    lasso:是L1正则化(绝对值) 注:坐标下降法即前向逐步线性回归 lasso算法:常用于特征选择 最小角算法,由于时间有限没有去好好研究(其实是有点复杂,尴尬)

  4. centos 7 设置IP地址

    先说下安装方式:我是采用的最小化安装 虚拟机软件:vmware 设置IP有两种情况,动态IP和静态IP,下面分别说明两种IP地址的设置方法 1.动态IP 条件:路由设置了动态分配IP地址(一般默认是动 ...

  5. <面试题>学习面试

    1.代码中要修改不可变数据会出现什么问题? 抛出什么异常? 代码不会正常运行,抛出 TypeError 异常. # 比如修改元祖.会报错 TypeError: 'tuple' object does ...

  6. element-ui表格合计不显示&被遮挡问题

    step1:修改全局样式 .el-table{ overflow:visible !important; } .el-card__body { padding: 20px 20px 50px 20px ...

  7. moment 获取当前月日历

    获取当前月日历 <template> <div id="calendar"> <div class="top">{{date ...

  8. 将sparkStreaming的结果保存到S3

    将spark解析的结果保存到S3 这个和保存到本地的区别在于,你需要配置aws的key和密码,以及它的region,代码如下 package com.alo7.spark import java.ut ...

  9. JS对象 指定分隔符连接数组元素join() join()方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。

    指定分隔符连接数组元素join() join()方法用于把数组中的所有元素放入一个字符串.元素是通过指定的分隔符进行分隔的. 语法: arrayObject.join(分隔符) 参数说明: 注意:返回 ...

  10. css---6伪元素选择器

    after                   :在内容后边 <!DOCTYPE html> <html lang="en"> <head> & ...