- json文件用什么打开(怎么读取json文件)
- 简述springmvc的工作原理(简述springmvc框架执行流程)
- sql优化的方法及思路(sql语句优化5种方式)
- 在python中运算符/与//、%的区别(python中百分号的用法)
- linux find -name 模糊查询文件(linux查找文件命令find模糊查询)
- win10怎么都去不掉开机密码 注册表(win10取消开机密码设置)
- 什么是ftp服务器(简述FTP的工作原理)
- ps描边路径快捷键,ps怎么选区描边快捷键
- linux删除文件夹命令(Linux删除目录下所有文件)
- python使用方法(零基础快速学会简单使用Python)
- ps软件怎么使用(ps新手零基础入门教程)
- css隐藏元素的几种方法(position属性的值及含义)
- 一个c语言程序是由什么组成的(c语言基本语法)
- python语言属于什么语言(python属于什么类型编程语言)
- cookie如何自动获取(怎么获取网页cookie)
- 数据库查询表中所有数据(select查询语句有那些字句)
- ps自动保存的文件在哪个位置(ps文件点了不保存还能恢复吗)
- mysql查询所有的表(sql查询语句大全及实例)
- divmod函数(python中divmod函数是什么意思)
- 什么是私有云计算基础架构的基石(私有云有什么用)
- html是一种什么语言(html是一种编译型的编程语言吗)
- ps分辨率怎么调才清晰(ps最清晰的分辨率是)
- linux关闭防火墙命令(linux防火墙关闭端口命令)
- win10无线网卡检测不到(windows10无线网络图标不见了)
- linux删除用户和用户组(linux强制删除用户命令)
- margin-bottom什么意思( margin属性值 )
- socks是什么意思(Socket作用必知必会)
- win7系统c盘怎么清理(c盘怎么清理到最干净只保留系统)
- 什么是邮件服务器(邮件发送服务器是什么)
- iis工作原理(iis提供的服务有哪些)
- 什么是js(JavaScript),js(JavaScript)的基本特点
- hive和mysql的语法区别(hadoop是做什么的)
- 前端后端分别是什么意思(前端开发工程师是做什么的)
- HTML的正式名称是什么(html是什么的缩写)
- ps怎么用蒙版做遮挡效果快捷键(ps怎么加蒙版遮盖)
- mysql创建数据表的sql语句(mysql建立数据库的步骤)
- linux安装sh文件命令(linux常用基本命令实例)
- linux的特点有哪些(简述linux开发的特点)
- python基础知识点总结(python基础知识思维导图)
- linux怎么修改目录名(linux下mv命令的用法)
- 永久关闭防火墙linux(关闭防火墙代码)
- java面向对象三大特性(如何理解java的面向对象)
- 增删改查sql语句(sql查询语句大全及实例)
- 二维数组初始化行和列哪个可以省(java中二维数组的初始化)
- windows的任务栏可用于做什么(任务栏的基本作用是)
- ps怎么移动图片的某一部分(ps怎么移动图片到另一张图片)
- unicode字符什么意思(显示unicode控制字符是什么意思)
- 电脑开机蓝屏无法进入系统怎么办(电脑出现蓝屏英文要怎么处理)
- range在python中的用法(pycharm中range是什么意思)
- 强制关闭电脑程序的快捷键是什么(强制结束电脑任务按哪些键)
- ps撤销上一步操作的快捷键(photoshop撤销快捷键是什么)
- ps金色cmyk色值是多少(ps暗金色数值是多少)
- vue和react的区别以及优劣势(vue3和react哪个更值得学)
- python生成10个随机数并求和(随机生成10个1到100之间的整数)
- PHP文件是什么(php文件怎么打开)
- redis是什么语言开发的(一文详解Redis)
- web服务器是啥(简述web服务器的工作原理)
- win7防火墙无法更改设置(win7系统防火墙怎么强制关闭)
- d盘格式化了能正常使用吗(格式化d盘和e盘会影响系统吗)
- 比较运算符有哪些(比较运算符的作用是什么)
- win10设置每天自动开关机(win10怎么设置自动开机时间)
- 数据库事务的四大特性以及事务的隔离级别(数据库事务的四大特性及含义)
- windows无法访问共享文件夹(电脑无法访问别人的共享文件)
- 查看linux文件系统类型(简述Linux的文件系统)
- linux查看端口命令(查看端口连接情况的命令)
- Spring 框架是什么(spring框架工作原理)
- 电脑中的mac地址怎么能查到(电脑mac地址哪个是正确的)
- python爱心代码简单(python发射爱心代码)
- 电脑安全模式一直加载怎么办(开机一直显示正在启动windows)
- spyder和pycharm哪个好(spyder使用教程)
- MySQL防止sql注入(有哪些防止sql注入攻击方法)
- pho文件怎么打开(php文件用什么软件打开)
- python输出怎么换行输出(python换行输入代码)
- 在线png转ico工具(png图片怎么转换成ico)
- java标识符有哪些(什么是java中合法的标识符)
- linux查看磁盘空间 命令(linux查看磁盘空间剩余情况)
- photoshop正片叠底怎么用(ps怎么把图层正片叠底)
- windows操作系统是一种什么操作系统(关闭windows10相当于什么)
- ps锐化工具怎么让图更清晰(ps的锐化功能怎么用)
- mysql建表语句主键自增(mysql创建数据表语句大全)
- python字典的基本操作(python字典如何添加元素)
- python中eval用法(python中eval输出什么)
- python打印九九乘法表总结(用python实现打印99乘法表)
- win10隐藏任务栏快捷键(windows桌面底部任务栏隐藏)
- python列表排序方法从大到小(python中对列表进行排序)
- c语言和python先学哪个(C++和Python的区别)
- javascript和java有什么区别(javascript和java哪个好)
- html字体颜色怎么设置(html字体样式代码大全)
- 用python画爱心加名字(python制作超炫流星雨表白)
- ubuntu系统主要干嘛用(ubuntu能做什么)
- linux切换用户命令快捷键(linux怎么切换到root用户)
- fread函数的用法(c语言fread函数的用法)
- win7连接wifi找不到无线网络(电脑怎么找到wifi连接)
- 前端性能优化有哪些方法(前端项目性能优化思路)
- python输入一个整正数n判断是否素数(Python编写一个函数判断素数)
- python爬虫教程(非常详细)(简单python爬虫完整代码)
- mysql密码怎么查看root用户密码(mysql第一次怎么设置密码)
- win10本地组策略编辑器找不到(电脑没有gpedit.msc怎么办)
- 微信小程序是用什么语言开发出来的(如何开发微信小程序)
- 求余运算符%对操作数的要求是什么(c语言中取余数的运算符)
- ps新建背景透明怎么设置(ps怎么把白色背景改为透明)
- ps标尺工具怎么用(ps卡尺的认识与使用)
- ps字体加粗怎么调整(ps里面怎样把字体加粗)
- mysql workbench怎么建立数据库(mysqlworkbench使用教程图解)
- python求和公式怎么编程(python计算1到n的和)
- html背景图片怎么添加css(html背景图片铺满网页)
- align-items属性(align默认属性)
- html图片如何居中 css(html怎么居中显示图片)
- python class用法理解(python调用class)
- win10删除输入法在哪里(删除win10输入法的方法)
- 开源软件是什么意思?闭源呢(开源软件的定义)
- 删除表中的数据的sql命令是什么(删除数据库所有数据的语句)
- java语言是一种什么语言(java通俗说是什么)
- python eval()函数的作用是什么(python中eval函数怎么用)
- java三大体系分别是(java三大主流框架)
- 10个爱心代码编程python(哄女朋友开心的小代码python)
- linux重启命令(linux怎么重新启动)
- linux切换用户命令(linux怎么切换到root用户)
- Win10、Win11 安全中心打开(笔记本windows安全中心怎么打开)
- 什么是网络地址和主机地址(什么是主机地址)
- python中return的用法和搭配(举例说明return语句的用法)
- python阶乘怎么表示(python如何计算阶乘)
- mysql怎么启动命令行(mysql打开是什么样子的)
- python print输出保留两位小数(python基础知识点总结)
- python输出九九乘法表(用python代码实现九九乘法表)
- mysql删除语句delete(mysql语句大全及用法)
- php指的是什么(什么是php)
- 电脑蓝屏无法自动修复怎么办(surface开机蓝屏进不了系统)
- ajax的原理和实现步骤流程(ajax的优缺点及工作原理)
- iframe的用法HTML(iframe框架的基本语法)
- mysql事务的四大特性(mysql的事物的默认隔离级别)
- 硬盘分区教程win10合并(win10硬盘怎么重新分配空间)
- win7笔记本系统摄像头在哪里打开(笔记本win7摄像头怎么打开)
- c语言大小写字母转换编程(c语言中字母大小写转换算法)
- internet提供的最常用便捷的通讯服务是(internet提供的服务包括哪些)
- python中不等于符号怎么写(python中表示不等于的字符)
- 强制删除目录linux命令(linux删除整个目录的命令)
- 阶乘和的python程序代码(Python输入一个数求阶乘)
- Ubuntu是什么系统(ubuntu是什么软件)
- ps设计是干什么的(ps设计是什么专业)
- python2 print用法(python中print的用法例子)
- 以太网无法连接到internet怎么解决(电脑显示无法访问internet)
- java三大特性及其具体含义(Java的三大特点)
- C语言数据结构代码含义(数据结构c语言版怎么学)
- 前端优化性能的方法(前端提高页面性能优化)
- ps蒙版如何使用详细步骤(PS蒙版到底是什么)
- win10开机按f8没反应无法开机(电脑进不去系统按f8也没反应)
- java多态的理解(运行时多态)(java多态的应用场景)
- win7共享文件夹没有权限访问共享文件夹(Win7电脑共享怎么设置)
- 什么是javabean简述其特点(javabean优点有哪些)
- win10怎么设置任务栏透明度(Windows10任务栏透明)
- map在python中是什么意思(python中的map函数的用法)
- 前端三大框架优缺点(前端的三大框架哪个最值得学)
- win10文件夹单独设置密码(如何让文件夹打开时需要密码)
- linux新建一个文件夹命令(linux创建文本文件命令)
- linux文件权限有三种分别是什么(linux查看目录权限命令)
- win10企业版和专业版哪个好(win10正式版和专业版的区别)
- ps修改数字不留痕迹(如何修改图片中的文字)
- vue与nodejs的关系(node.js可以做什么)
- 什么是关系数据库数据操作的基础(关系型数据库是由什么组成的)
- windows和linux的区别及优缺点(linux系统适合日常使用吗)
- linux系统命令cd(linux20个常用命令)
- pycharm中文版界面设置(python设置中文界面两种方法)
- range函数的使用(range在python中什么意思)
- c语言double怎么用(c语言中float的用法举例)
- 什么是ASP.NET(asp是什么意思的缩写)
- win10一直收集错误重启进不去系统(win10系统老是收集错误信息)
- win10启动后黑屏不进入桌面(电脑启动不能进入系统怎么办)
- SQL数据库基本语句(数据库增删改查基本命令)
- 数据库的主要特点(简述数据库的定义与特点)
- javabean的含义(javabean的特点和作用)
- linux查看文件夹大小命令(Linux统计某一类文件的大小)
- len()函数在python中是什么意思(len()函数的功能是什么)
- linux cp命令复制文件到当前目录(linux常用命令复制文件)
- c语言是一种什么语言(c语言是高级语言还是低级语言)
- python定义函数的关键字(定义函数的规则)
- 盒子居中代码html(html网页文字居中代码)
- python函数定义与调用(Python函数的定义及作用详解)
- ps2021怎么加阴影有立体感(ps把平面图做出立体感)
- 随机密码生成python123(python随机生成六位数密码)
- php框架有哪些,php是不是彻底凉了
- ui设计好学吗要学多久(ui设计师需要掌握的技能)
- css选择器有哪几种(css基本选择器有哪些)
- css文本首行缩进2字符怎么设置(html中首行缩进怎么设置)
- 查看进程状态的命令(linux查看指定名称的进程)
- c语言强制类型转换的使用规则(c语言中强制转换语句)
- mysql update语句怎么写(mysql update select用法)
- python中print()的作用是什么(python如何在函数中print)
- 修改表的sql语句命令是(Sql中修改数据表结构语句)
- flag在python中的用法(python flag用法)
- 浏览器javascript怎么开启(如何启用javascript)
- mysql触发器的作用是什么(触发器的类型和作用)
- mysql启动命令windows(cmd中mysql怎么启动并连接)
- ps打字只有一个黑点和横线(ps文字周围有些黑点怎么弄)
- format函数python用法举例(format函数的使用方法)
- ps渲染和不渲染的区别图片对比(渲染图和效果图区别)
- 对于ui设计师的看法(高级ui设计师要具备的能力)
- 汇编语言和c语言哪个难(汇编语言和c语言区别大吗)
- win10系统怎么连接打印机扫描(win10连接打印机找不到设备)
- win10删除本地管理员账户后密码(win10系统如何删除管理员账户)
- ps文字描边快捷键(ps怎么选区描边快捷键)
- c语言程序的三种基本结构是顺序结构(c语言选择结构三种形式)
- ps2019如何调出中心点(ps中心点怎么调出来快捷键)
- 0xc0000225无法进系统win10(电脑出现错误代码0xc0000225)
- html添加图片的代码(html怎么指定图片位置)
- win7无线网络连接不见了怎么办(win7无线网服务怎么开启)
- java跟javascript有什么区别(java 面向对象怎么理解)
- windows audio被停止了怎么办(电脑音频不小心删了怎么恢复)
- c语言程序100例(写代码新手教程)
- mysql删除数据库命令(mysql数据库删除数据语句)
- linux修改文件权限的命令是什么(linux修改用户读写权限命令)
- ps怎么画一条直虚线(photoshop怎么把直线变成虚线)
- 阿里云服务器是干什么用的(自己有一台服务器能干什么)
- windows的桌面是指什么(在windows中桌面是指什么)
- ps文字描边怎么做(ps怎么给图像轮廓描边)
- linux是什么操作系统(linux开发是做什么)
- python内置的集成开发环境(最全的Python IDE 优缺点整理)
- python创建txt文件并写入输出在控制台怎么写(python一段文本写入txt文件)
- linux相对路径怎么写(linux绝对路径和相对路径怎么写)
- python框架有哪些(python开发框架有哪些)
- win10运行速度提高90%怎样提高win10开机速度(win10最强性能优化设置)
- win10网络图标变成了地球没有wifi(网络正常图标显示小地球)
- python中len()的用法(len在python中怎么找长度)
- ftp的功能有哪些(FTP的功能以及使用的协议)
- PS如果做副业难学吗(ps多久可以学会)
- ps从外面拖图片拖不进来win10(图片拖不进ps的解决方法)
- linux进入root权限命令(linux系统怎么进入root模式)
- html文件怎么打开(HTML的意义和作用)
- python中int()的用法(python中输入是int怎么写)
- win10电脑开启摄像头权限在哪里(电脑摄像头设置在哪里)
- php和java区别(java和php的优缺点)
- 什么叫java虚拟机(java虚拟机工作原理)
- .sh文件怎么运行 windows环境(windows执行sh文件命令)
- mysql5.5的安装完怎么打开(MySQL安装教程)
- python列表去重不改变顺序(python列表去重输入一个列表)
- json是什么语言(json对象是什么)
- 笔记本静电积累怎么解决(主机有静电怎么消除)
- 2022年linux查看防火墙状态命令(查看防火墙状态的命令)
- java和javascript有什么区别(JavaScript 与 Java 的关系)
- win10网络连接没有wifi选项(电脑只有以太网不显示WLAN)
- queryselector id用法(querySelector智能提示)
- php连接mysql访问方式(php访问mysql的五个基本步骤)
- linux复制文件夹命令(linux系统复制粘贴命令代码)
- Linux7.9重置root密码(linux系统设置root密码)
- win10win键按了没反应(键盘上的win键没反应怎么办)
- Linux给用户设置密码(Linux创建用户命令)
- mysql事务隔离级别设置(mysql事务隔离级别实现原理)
- 数据库索引的优缺点(数据库索引原理)
- c语言pow函数怎么用(pow在c语言中怎么用)
- python pop函数什么意思(pop语句python)
- win7笔记本摄像头在哪里打开摄像头(win7系统如何开启摄像头权限)
- java连接mysql数据库增删改查(怎么用mysql连接数据库)
- C#是C语言吗(C#是什么)
- py文件怎么打开(py格式用什么打开)
- 一个类只能有一个对象吗(一个类可以实例化多个对象吗)
- javascript和java有什么关系(javascript和java的区别)
- editplus怎么运行html程序(editplus写好了怎么运行)
- c语言大写字母换成小写(c语言大小写字母转换调用函数)
- linux grep命令详解(grep命令的详细使用方法)
- linux退出命令行模式(linux退出编辑模式命令)
- int在python中的用法(int在python中是什么意思)
- void在java中是什么意思(void在java中的用法)
- pythonrange函数的作用(简述range函数的使用规则)
- Linux MySQL数据库备份命令(linux下备份mysql数据库命令)
- 判断是不是闰年的python代码if(用python怎么判断闰年)
- define在c语言中是什么意思(c语言宏定义用法)
- surface平板模式有什么用(surface平板模式好用吗)
- win10怎么用命令提示符修复电脑(win10用命令符修复系统)
- mysql多表查询答案(mysql多表条件查询语句)
- mysql主从复制怎么实现(mysql主从复制读写分离原理)
- JAVA语言特点(java语言的基本特点)
- 关于svchost占用巨大内存的问题(彻底解决win10svchost占用内存过高)
- javabean是框架吗(javabean在系统中的作用)
- 苹果笔记本ps软件怎么用(ps软件使用教程)
- 什么是DNS服务器地址(手机dns怎么设置网速快)
- switch case语句例子(Python语言switch case用法举例)
- 什么叫数据库代码怎么写(谈谈自己对数据库的理解)
- dbf文件可以用word打开吗(dbf格式用什么打开)
- button属性和方法详解(Python中button控件的属性和事件)
- 什么是命令行终端(Linux命令行方式是什么意思)
- ppt怎么做超级链接啊(word里目录和内容怎么做超级链接)
- java在线编程工具(java知识点总结归纳)
- win7如何添加打印机到电脑(win7如何添加共享打印机)
- 电脑不能正常启动windows怎么办(笔记本电脑开机无法进入桌面系统)
- win7如何安装打印机到电脑上(win7电脑怎么安装打印机驱动程序)
- 如何使用photoshop处理图像(photoshop使用方法)
- win10远程桌面无法连接到远程计算机(电脑远程连接不上是什么原因)
- 邮件服务器是什么意思(邮件服务器的概念)
- win7电脑开机蓝屏怎么办(win7开机蓝屏无法进入系统)
- linux设置默认网关命令(linux怎么配置网关)
- 什么是cms系统(cms开发大白话)
- ipv4与ipv6的区别史上最详细(ipv4和ipv6的主要技术区别)
- http的header是什么(header元件作用)
- asp是什么文件的扩展名(asp文件怎么直接从网页打开)
- DNS服务器是什么意思(dns一般设置成什么)
- jpeg和jpeg2000的区别(jpeg和jpg一样吗手机怎么转换)
- xml是什么格式的文件怎么打开(xml文件怎么生成)
- ps反向选区快捷键是什么快捷键(ps图片反选快捷键)
- html文件怎么打开有网页效果(html文件怎么转换成word文档)
- javascript是干什么的(什么是Javascript)
- 在python中运算符/与//、%的区别(python运算符优先级顺序)
- ps背景颜色怎么换快捷键(ps怎么只调背景颜色)
- python是一种什么语言(python和c++学哪个好)
- eclipse中文字体大小设置(eclipse字体大小设置英文版)
- dreamweaver是什么软件类型(dreamweaver网页制作成品软件推荐)
- ps如何换证件照背景颜色(ps换背景教程详细步骤)
- 学linux能干什么工作(linux一般用来做什么)
- 如何做网站网页(怎样做一个网站)
- ip地址怎么判断正确(标准的ip地址格式)
- tup在python中什么意思(pythontuple是什么类型)
- ps怎么换背景颜色不影响到人物(ps更换照片背景颜色)
- javascript和java有什么关系(javascript跟java哪个吃香)
- maven怎么用(Maven的作用)
- ps如何调整照片大小和像素(ps修改图片像素大小)
- 浏览器javascript:void(O)是什么意思(js点击事件onclick用法)
- dom是什么属性(网络dom是什么意思)
- python中+=是什么意思(2**3表示什么python)
- import是什么意思(import在python中的用法)
- windows的任务栏可用于什么程序(在windows中任务栏的作用)
- c语言||和&&什么意思(c语言中&&的优先级)
- unix和linux的区别和联系(linux一般用来做什么)
- ps怎么填充背景色(ps怎么填充画布背景色)
- 色阶的快捷键是什么键(ps常用快捷键)
- ps复制快捷键ctrl加什么(ps新建图层的快捷键是什么)
- wps如何添加脚注(如何修改脚注编号格式)
- 安卓微信黑色模式怎么调(微信显示黑色背景怎么调)
- px是什么单位(px是什么意思)
- pscs6是哪一年的版本(初学者用ps cc还是cs6)
- linux查看系统版本号命令(linux服务器怎么看系统版本)
- voip音量什么意思(什么是voip通话功能)
- php用什么软件来编程(php文件怎么在浏览器运行)
- ps人像精修人脸步骤教程(ps怎么修图基本步骤)
- linux解压zip命令(linux常用打包压缩命令)
- JAVA随机数的方法(java随机数random概率)
- 一个c程序是由什么组成的(c语言的特点)
- ps怎么反选选区(ps反向选择怎么用)
- php自学要学多久(php和python哪个学起来简单一点)
- js语言是什么(js是干什么的)
- eof在c语言中怎么用(eof在c语言中怎么输入)
- c++编译器(目前最流行的编程软件)
- 羽化快捷键ps(ps羽化功能在哪里找)
- win10家庭版安装密钥(重装系统激活windows密钥)
- linux查看进程内存占用命令(linux常用基本命令实例)
- 502badgateway是什么意思?怎么解决(502 bad gateway是什么原因)
- ps背景颜色怎么填充快捷键(照片ps换底色最简单方法)
- php是什么语言(php可以做前端吗)
- mongodb和mysql的区别 性能对比(mongodb mysql性能比较)
- python中def函数的用法(python中def怎么用)
- excel中SQRT是什么意思(sqrt在excel中的作用)
- c语言中的/和%表示什么意思(c语言里的符号大全)
- linux创建目录的命令(linux怎么创建目录和文件)
- CSS3有哪些新特性(列举5个css3新增的属性)
- mysql数据库增删改查基本语句(sql增删改查基本语法)
- 云服务器有什么用(服务器通俗易懂的解释)
- 删除数据库的sql语句(清空当前数据库的命令是什么)
- linux查看端口占用进程(linux常用命令查看端口命令)
- c语言的三种基本数据类型(c语言选择结构三种形式)
- pg数据库是关系型数据库吗(pg数据库基础知识)
- python和c语言的区别大吗(python和c++学哪个好)
- html居中代码怎么写(实现整个html居中最简单方法)
- python中set()函数的用法(python基础知识入门)
- c语言中的/和%表示什么意思(c语言代码大全和详细解释)
- markdown是干嘛用的(markdown格式什么意思)
- python随机生成数字个数(python如何产生一个随机数)
- cpu多线程是什么意思(多线程应用场景例子)
- aspnet是什么语言(asp.net是一种语言吗)
- python主要是做什么的(python有什么用)
- linux修改ip地址的命令(命令修改ip地址)
- linux查看日志的三种命令(linux查看服务器系统日志)
- win10桌面图标间距恢复默认(win10桌面图标间距过大怎么调节)
- python环境变量的配置win10(python环境变量配置教程)
- python用什么编辑器好(python用什么软件编辑)
- Java jsp是什么(jsp的英文全称是什么)
- linux查看端口占用情况(linux如何查看端口是否被占用)
- win10一键锁屏快捷键(电脑如何一键熄灭屏幕快捷键)
- NoSQL数据库具有以下几个特点(nosql数据库的优势和劣势)
- pdf是啥意思(如何转化为pdf格式)
- ps改尺寸大小和像素快捷键(ps把图片修改成指定尺寸)
- html是一种标记语言吗(html底层是什么语言)
- 打印机共享启用网络发现保存不了(更改高级共享设置无法保存修改)
- ps曲线快捷键是什么(ps如何调整颜色曲线快捷键)
- ps一寸照片的尺寸是多少像素(一寸照片尺寸比例怎么调整)
- win10本地安全策略怎么打开(win10安全模式如何修复电脑)
- 删除文件命令Linux(Linux强制删除文件夹命令)
- SQL查询语句大全集锦(sql数据库查询语句例子)
- mysql删除表命令(删除数据库中已经存在的表)
- ajax技术主要功能是什么(javascript是干嘛的)
- linux删除文件夹及其中的所有文件应该使用命令(linux删除当前文件夹命令)
- python是一种什么类型的编程语言(python脚本文件扩展名为)
- 盖印图层和合并图层有什么区别(对盖印图层的描述正确的是)
- JAVA是应用软件吗(java编程是什么)
- win10桌面文件夹路径更改(win10桌面是哪个文件夹)
- mysql常用的索引类型(列举mysql中所有的索引类型)
- mysql修改表中一行数据(MySQL删除表中指定数据)
- 什么是javaweb技术开发(javaweb是什么)
- python的特点有哪些(python语言的5个主要特点)
- mysql和oracle的语法区别有什么(mysql和oracle的sql语句区别)
- 什么是pr剪辑(pr职位是干嘛的)
- 桌面路径改到d盘为什么改不回去了(电脑桌面文件路径怎么改回来)
- ps格式有哪些(详解PS中常见的图片格式)
- ps怎么恢复工具栏初始界面(ps怎么回到初始设置)
- c程序的基本结构单位是(大学c++编程题库及答案)
- sublimetext运行python(sublime配置python环境)
- mysql导致索引失效的情况(数据库索引失效的场景)
- ps反选在哪里(ps里的反向选择快捷键)
- sql优化常用的几种方法(数据库优化方面的经验)
- python生成随机数的模块(python中如何生成随机数)
- html怎么添加图片为背景(html怎么用img添加图片路径)
- python定义变量类型(python如何定义一个变量范围)
- linux查看cpu使用率百分比(linux获取cpu使用率的命令)
- c/s架构和b/s架构的优缺点(c/s架构和b/s架构测试有什么不同)
- linux打开文件夹命令(linux命令查看文件内容)
- 图片格式jpeg和jpg一样吗(jpg格式和jpeg格式是一样的吗)
- 编程难不难学(编程自学能学会吗)
- ps正片叠底怎么使用(ps绘画正片叠底怎么使用)
- python输出语句print格式(pythonprint怎么输出变量)
- filezillaserver使用教程(filezilla远程传输文件)
- 固态硬盘坏了如何修理(固态硬盘损坏会出现什么现象)
- ctrl+d是什么快捷键Excel(做表格按到了ctrl加d怎么办)
- linuxvi编辑器常用命令(linuxvi编辑器命令查找)
- 简述引入css样式表的三种方式(用css和div制作网页的html的代码)
- mac可以开机但进不去系统(苹果电脑开机转圈圈无法启动)
- python多行注释是什么(pythonidea注释多行代码)
- windows10关闭自动更新(笔记本windows自动更新怎么关闭)
- 编程好学吗要学多久(从零开始学编程难吗)
- nodejs一般用来做什么(nodejs的作用是什么)
- linux查看ip命令(Linux查看自己电脑的IP地址)
- def在python中的用法(def在python中的例题)
- python求n的阶乘代码(python中n的阶乘三种方法)
- c语言定义一串数组(c语言数组的定义方法及规则)
- 最小化当前窗口的快捷键是什么(电脑桌面窗口最小化快捷键)
- mysql删除所有数据库(怎样彻底删除数据库SQL)
- h5页面是什么意思(h5页面和网页有什么区别)
- html超链接怎么跳转到指定的页面(html怎么超链接到指定网址)
- c语言字符常量的合法表示(c语言字符串常量定义)
- ps的羽化快捷键在哪里(怎么羽化边缘ps)
- python水仙花数的编程代码(水仙花数python代码条件语句)
- python tkinter布局(tkinter库入门详细教程)
- ps如何反选快捷键(ps反向选区快捷键是什么)
- HTML是指什么(html基本结构框架代码)
- 影楼ps磨皮美白步骤(ps人物磨皮教程步骤)
- 新手学ps2020还是ps2021(初学者ps用什么软件比较好)
- ps局部调亮具体步骤(ps怎么局部提亮和局部变暗)
- react和vue的未来趋势(vue和react的优缺点)
- mpeg4和mp4格式一样吗(mpeg格式怎么转换mp4)
- 清理谷歌浏览器缓存的方法(如何浏览器清理缓存)
- Linux挂载移动硬盘(linux下挂载u盘详解)
- linux创建多个目录的命令(创建文件和目录的命令)
- wifi代理ip怎么设置(苹果手机wifi代理怎么设置)
- python中一个*是什么意思(两个星号是什么意思python)
- linux和unix命令一样吗(linux和unix的关系是什么)
- python判断一个数是否为整数代码(python判断是否为整数)
- pythonif语句格式例子(python条件语句if简单例子)
- pycharm注释的快捷键(python快速注释快捷键)
- python中调用函数的方法(python中怎么调用函数)
- python爬虫可以用来干嘛(python普通人学有什么用)
- ps怎么羽化在哪里(ps羽化的快捷键是什么)
- ps如何填充前景色(如何在ps设置背景色)
- linux查看日志命令(实时查看日志命令)
- ps怎样把几个图层合并为一个图层(ps怎么合并图层不影响效果)
- Java中string是什么意思(java中string类的常用方法)
- win键是哪个键(什么是windows徽标键)
- centos7关闭防火墙命令(centos怎么关闭防火墙命令)
- 用来定义类的关键字是(python中第一类的关键字是)
- linux怎么创建文件夹(linux怎么创建txt文件)
- mysql limit分页慢优化(mysql limit原理)
- java三大特性的理解(java的三大特性是什么)
- 光盘驱动器是外部设备吗(光盘驱动器简称为什么)
- web标准的制定者是什么(Web标准的制定者是谁)
- C语言排序代码(c语言排序算法完整程序)
- centos关闭防火墙命令(centos如何关闭防火墙)
- ps中新建图层的快捷键是什么(ps怎么快捷键复制图层)
- 盖印快捷键PS(ps常用快捷键大全表格)
- linux网卡配置文件(centos7网卡配置文件)
- eclipse如何调整字体大小(eclipse代码字体大小设置)
- html是什么的英文缩写(Html全称是什么)
- ps怎样换证件照背景颜色(照片ps换底色最简单方法)
- 电脑pe是什么意思
- ps怎么保存下次继续做快捷键(ps保存可以下次再弄的格式)
- c语言常量的正确表示方法(c语言字符常量规则)
- 小程序后端开发流程详细(小程序开发成本预算)
- linux修改时间和日期的方法(Linux使用date修改当前日期)
- ps人像精修教程(ps人像修图基本步骤)
- linux上传文件夹命令(linux上传和下载命令)
- python代码写好了保存在文件后怎么运行(写完python代码如何运行)
- mysql查看表结构的sql语句(查询数据库表结构)
- c语言判断奇偶数代码(c语言判断一个数的奇偶性)
- mysql隔离级别解决的问题(简述事务的隔离级别)
- html表单制作代码(HTML简述创建表格的基本步骤)
- cmd查看mysql版本(windows下怎么查看mysql版本)
- 如何ping服务器端口通不通(怎么ping网络ip地址)
- 什么是root权限(手机root权限是什么)
- php服务器环境搭建及配置(常见的web服务器)
- php怎么和mysql数据库连接(php如何访问mysql)
- linux查看操作系统版本命令(linux服务器怎么看系统版本)
- 退出vi命令(vi编辑器保存退出命令)
- linux删除硬盘分区(linux系统格式化硬盘命令)
- linux vi命令的作用(vi安装命令详解)
- bcompare文件比较(bcompare按行对比)
- PHP环境搭建的主要步骤和方法(本地php环境搭建教程)
- python能做什么(python是学什么的)
- dev c++怎么用c语言(dev c++怎么调试)
- float 和 double 的区别是什么(c语言float和double的用法)
- 数据库索引是什么意思(索引的概念)
- tcp/ip协议介绍(计算机中TCP是什么意思)
- c/s架构和b/s架构(c/s和b/s)
- ps阴影效果怎么做平面图(ps怎么给局部加阴影)
- system占用磁盘高原因(system占用cpu怎么解决)
- python保留两位小数怎么表示(python精确到小数点后两位)
- devc++怎么调试运行(dev-c++使用教程)
- 什么是it行业(互联网it是什么工作)
- 数据库原理及应用(数据库原理与技术)
- javascript是干什么的(javascript基础知识总结)
- php开发有前途吗(php开发网站的优势)
- URL什么意思(url含义是什么意思)
- 如何p图教程(怎么样才能p图)
- c++是做什么的(c++能做什么)
- mysql(mysql教程)
- tcp协议工作在哪层(Tcp协议工作在以下的哪个层)
- ecs云服务器是什么(ecs系统是什么意思)
- HTML5是什么意思(h5是什么意思)
- scanner在java中的作用(scanner怎么使用)
- ps抠图换背景详细步骤(初学者ps抠图步骤图解)
- ssl状态是什么意思(ssl的概念)
- pscc是哪年的版本(ps哪个版本好用稳定)
- 初始化磁盘选mbr gpt(如何重新初始化硬盘)
- 钩子函数是什么意思(钩子函数的作用)
- python注释方法有几种(Python代码注释是啥)
- ps复制图层快捷键ctrl加什么(ps背景复制图层快捷键)
- java用什么软件编写最好(java软件有哪些)
- 关闭windows defender安全中心通知(怎么关闭Windows defender)
- 九九乘法表python代码详解(python乘法运算代码怎么写)
- .net是什么语言(NET是什么简称)
- mysql数据库基础知识(简要阐述mysql数据库的特点)
- mysql是干什么用的(mysql是什么类型数据库)
- 行内元素和行内块级元素有何区别(html的块级元素和行级元素)
- print在python中用法(python代码)
- mysql数据库建表的完整步骤(mysql创建一个空数据库)
- margin在html中什么意思(margin属性的作用是什么)
- jsp文件是什么(jsp文件是干嘛的)
- windows安装光盘怎么安装(系统损坏进不去怎么重装系统)
- vue框架和uniapp框架区别(uniapp和原生开发区别)
- ps闪退是什么原因win10(photoshop用几分钟自动关闭)
- win10 telnet服务怎么开启(如何打开telnet功能)
- python语言的特点有哪些(python主要应用领域)
- mybatis的一级缓存和二级缓存区别(mybatis工作原理)
- 电脑浏览器清除缓存怎么弄(浏览器清空缓存怎么清)
- ps标尺怎么调出来(ps标尺工具在哪里)
- jdbc连接数据库步骤(jdbc的概念和作用)
- .net开发工程师是做什么的(.net还有前景吗)
- 2021ps怎么安装字体(photoshop字体安装)
- func函数的功能Python(fun函数怎么计算)
- CMS是什么缩写(cms系统是干嘛的)
- linux常用命令返回上一级目录(linux基础命令表)
- 2021年php市场占有率(计算机语言排名最新)
- python内置函数大全表(python内置函数大全解释)
- decimal数据类型的用法(decimal数据类型的取值范围)
- vc++6.0怎么新建c语言文件(vc++2015怎么新建c语言文件)
- 创建表的sql语句主键(sql常用语句格式及例子说明)
- linux是哪个公司开发的(linux版权归哪国)
- react面试题及答案2022(react底层原理面试题)
- c++与python的区别(c++和python哪个好)
- ps怎么画矩形框填充颜色(ps里面怎么画矩形边框)
- ps局部透明度(ps透明底图怎么做)
- 初学者ps修图步骤图解(ps使用方法新手基础)
- ps怎么调整画布大小(ps怎么调整画布大小快捷键)
- linux压缩文件夹命令zip(linux压缩文件夹命令 tar)
- 查看端口的命令telnet(netstat查看端口状态详解)
- break在c语言中的用法(c语言break是什么意思及用法)
- js中charat函数(javacharat方法)
- win7文件夹只读属性去不掉(电脑文件夹只读模式取消不了)
- win10cmd关机命令(cmd重启电脑命令)
- restless是什么意思(restful接口特点)
- win10键盘重启(windows如何强制重启)
- linux查看端口占用情况(linux检测端口是否被占用)
- python的数据类型(python数据类型转换函数)
- 字符常量的正确表示方法(下列字符常量表示正确的是)
- python中append什么意思(python append()方法返回什么)
- 未来计算机的发展趋势是什么(未来计算机将是什么技术)
- ps的快捷键有哪些(ps所有快捷键大全总结)
- linux查看文件内容命令有哪些(grep命令查找文件内容)
- app和小程序的区别(微信小程序和app哪个更好)
- c语言double的意思(double x在c语言中是什么意思)
- static在c语言中是什么意思(x在c语言中等于什么意思)
- ps画笔颜色怎么改不了(ps画笔怎么画出颜色)
- php代码怎么讲(php简单程序代码)
- ps怎么调整图片像素大小不变形(照片大小怎么改到20k)
- css文字颜色透明(设置元素透明度的属性)
- c语言数组知识点总结(c语言如何定义字符串数组)
- ps快捷键大全常用(ps所有快捷键大全总结)
- linux查看文件内容命令有哪些(linux查看文件详细信息命令)
- ie内核的360浏览器是什么(ie内核浏览器有哪些)
- ps色板怎么改成色环(ps2019色环怎么调出来)
- c语言一元一次方程求根程序(c语言根号用什么函数)
- 数据完整性是指哪三个(数据库的完整性是指哪三个)
- pr和ps先学哪个(pr和ps哪个学起来简单)
- 浏览器缓存机制(浏览器缓存强缓存和协商缓存)
- sql server和mysql的语法区别(sql和mysql的语句一样吗)
- c语言中=与==的用法区别(C编程中=和==的区别)
- 电脑蓝屏7b怎么解决win7(win7开机蓝屏0x0000007b)
- ps里的文字怎么旋转位置(ps文字倾斜成自己要的角度)
- win10磁盘碎片清理在哪里(如何清理电脑c盘的空间)
- 电脑格式化的危害有哪些(c盘怎么清理到最干净)
- ps2022怎样换证件照背景(ps抠人像换背景证件照)
- overflow有哪些值(html的overflow属性)
- 怎么样p图换脸(如何p图把人p上去)
- ps快速制作网格图(ps怎么做网状效果图)
- java scanner输入字符串(java中scanner用法总结)
- linux复制文件到另一个文件夹(linux复制粘贴命令快捷键)
- win10台式睡眠按啥键唤醒(怎么唤醒电脑休眠状态)
- windows是应用软件吗(windows10是一种系统软件吗)
- win7硬盘分区表mbr还是guid(windows7旗舰版怎么分盘)
- ps怎么移动图层快捷键(ps怎么只移动当前图层)
- sql全称是什么(SQL的英文全称是什么)
- 数据库系统的特点是什么(数据库的特点包括什么)
前言
之前分析一个死锁问题,发现自己对数据库隔离级别理解还不够清楚,所以趁着这几天假期,整理一下MySQL事务的四大隔离级别相关知识,希望对大家有帮助~
事务
什么是事务?
事务,由一个有限的数据库操作序列构成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
假如A转账给B 100 元,先从A的账户里扣除 100 元,再在 B 的账户上加上 100 元。如果扣完A的100元后,还没来得及给B加上,银行系统异常了,最后导致A的余额减少了,B的余额却没有增加。所以就需要事务,将A的钱回滚回去,就是这么简单。
事务的四大特性
- 原子性: 事务作为一个整体被执行,包含在其中的对数据库的操作要么全部都执行,要么都不执行。
- 一致性: 指在事务开始之前和事务结束以后,数据不会被破坏,假如A账户给B账户转10块钱,不管成功与否,A和B的总金额是不变的。
- 隔离性: 多个事务并发访问时,事务之间是相互隔离的,一个事务不应该被其他事务干扰,多个并发事务之间要相互隔离。。
- 持久性: 表示事务完成提交后,该事务对数据库所作的操作更改,将持久地保存在数据库之中。
事务并发存在的问题
事务并发执行存在什么问题呢,换句话说就是,一个事务是怎么干扰到其他事务的呢?看例子吧~
假设现在有表:
CREATE TABLE `account` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`balance` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `un_name_idx` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码
表中有数据:
脏读(dirty read)
假设现在有两个事务A、B:
- 假设现在A的余额是100,事务A正在准备查询Jay的余额
- 这时候,事务B先扣减Jay的余额,扣了10
- 最后A 读到的是扣减后的余额
由上图可以发现,事务A、B交替执行,事务A被事务B干扰到了,因为事务A读取到事务B未提交的数据,这就是脏读。
不可重复读(unrepeatable read)
假设现在有两个事务A和B:
- 事务A先查询Jay的余额,查到结果是100
- 这时候事务B 对Jay的账户余额进行扣减,扣去10后,提交事务
- 事务A再去查询Jay的账户余额发现变成了90
事务A又被事务B干扰到了!在事务A范围内,两个相同的查询,读取同一条记录,却返回了不同的数据,这就是不可重复读。
幻读
假设现在有两个事务A、B:
- 事务A先查询id大于2的账户记录,得到记录id=2和id=3的两条记录
- 这时候,事务B开启,插入一条id=4的记录,并且提交了
- 事务A再去执行相同的查询,却得到了id=2,3,4的3条记录了。
事务A查询一个范围的结果集,另一个并发事务B往这个范围中插入/删除了数据,并静悄悄地提交,然后事务A再次查询相同的范围,两次读取得到的结果集不一样了,这就是幻读。
事务的四大隔离级别实践
既然并发事务存在脏读、不可重复、幻读等问题,InnoDB实现了哪几种事务的隔离级别应对呢?
- 读未提交(Read Uncommitted)
- 读已提交(Read Committed)
- 可重复读(Repeatable Read)
- 串行化(Serializable)
读未提交(Read Uncommitted)
想学习一个知识点,最好的方式就是实践之。好了,我们去数据库给它设置读未提交隔离级别,实践一下吧~
先把事务隔离级别设置为read uncommitted,开启事务A,查询id=1的数据
set session transaction isolation level read uncommitted;
begin;
select * from account where id =1;
复制代码
结果如下:
这时候,另开一个窗口打开mysql,也把当前事务隔离级别设置为read uncommitted,开启事务B,执行更新操作
set session transaction isolation level read uncommitted;
begin;
update account set balance=balance+20 where id =1;
复制代码
接着回事务A的窗口,再查account表id=1的数据,结果如下:
可以发现,在读未提交(Read Uncommitted) 隔离级别下,一个事务会读到其他事务未提交的数据的,即存在脏读问题。事务B都还没commit到数据库呢,事务A就读到了,感觉都乱套了。。。实际上,读未提交是隔离级别最低的一种。
已提交读(READ COMMITTED)
为了避免脏读,数据库有了比读未提交更高的隔离级别,即已提交读。
把当前事务隔离级别设置为已提交读(READ COMMITTED),开启事务A,查询account中id=1的数据
set session transaction isolation level read committed;
begin;
select * from account where id =1;
复制代码
另开一个窗口打开mysql,也把事务隔离级别设置为read committed,开启事务B,执行以下操作
set session transaction isolation level read committed;
begin;
update account set balance=balance+20 where id =1;
复制代码
接着回事务A的窗口,再查account数据,发现数据没变:
我们再去到事务B的窗口执行commit操作:
commit;
复制代码
最后回到事务A窗口查询,发现数据变了:
由此可以得出结论,隔离级别设置为已提交读(READ COMMITTED) 时,已经不会出现脏读问题了,当前事务只能读取到其他事务提交的数据。但是,你站在事务A的角度想想,存在其他问题吗?
提交读的隔离级别会有什么问题呢?
在同一个事务A里,相同的查询sql,读取同一条记录(id=1),读到的结果是不一样的,即不可重复读。所以,隔离级别设置为read committed的时候,还会存在不可重复读的并发问题。
可重复读(Repeatable Read)
如果你的老板要求,在同个事务中,查询结果必须是一致的,即老板要求你解决不可重复的并发问题,怎么办呢?老板,臣妾办不到?来实践一下可重复读(Repeatable Read) 这个隔离级别吧~
哈哈,步骤1、2、6的查询结果都是一样的,即repeatable read解决了不可重复读问题,是不是心里美滋滋的呢,终于解决老板的难题了~
RR级别是否解决了幻读问题呢?
再来看看网上的一个热点问题,有关于RR级别下,是否解决了幻读问题?我们来实践一下:
由图可得,步骤2和步骤6查询结果集没有变化,看起来RR级别是已经解决幻读问题了~ 但是呢,RR级别还是存在这种现象:
其实,上图如果事务A中,没有update account set balance=200 where id=5;这步操作,select * from account where id>2查询到的结果集确实是不变,这种情况没有幻读问题。但是,有了update这个骚操作,同一个事务,相同的sql,查出的结果集不同,这个是符合了幻读的定义~
这个问题,亲爱的朋友,你觉得它算幻读问题吗?
串行化(Serializable)
前面三种数据库隔离级别,都有一定的并发问题,现在放大招吧,实践SERIALIZABLE隔离级别。
把事务隔离级别设置为Serializable,开启事务A,查询account表数据
set session transaction isolation level serializable;
select @@tx_isolation;
begin;
select * from account;
复制代码
另开一个窗口打开mysql,也把事务隔离级别设置为Serializable,开启事务B,执行插入一条数据:
set session transaction isolation level serializable;
select @@tx_isolation;
begin;
insert into account(id,name,balance) value(6,'Li',100);
复制代码
执行结果如下:
由图可得,当数据库隔离级别设置为serializable的时候,事务B对表的写操作,在等事务A的读操作。其实,这是隔离级别中最严格的,读写都不允许并发。它保证了最好的安全性,性能却是个问题~
MySql隔离级别的实现原理
实现隔离机制的方法主要有两种:
- 读写锁
- 一致性快照读,即 MVCC
MySql使用不同的锁策略(Locking Strategy)/MVCC来实现四种不同的隔离级别。RR、RC的实现原理跟MVCC有关,RU和Serializable跟锁有关。
读未提交(Read Uncommitted)
官方说法:
SELECT statements are performed in a nonlocking fashion, but a possible earlier version of a row might be used. Thus, using this isolation level, such reads are not consistent.
读未提交,采取的是读不加锁原理。
- 事务读不加锁,不阻塞其他事务的读和写
- 事务写阻塞其他事务写,但不阻塞其他事务读;
串行化(Serializable)
官方的说法:
InnoDB implicitly converts all plain SELECT statements to SELECT ... FOR SHARE if autocommit is disabled. If autocommit is enabled, the SELECT is its own transaction. It therefore is known to be read only and can be serialized if performed as a consistent (nonlocking) read and need not block for other transactions. (To force a plain SELECT to block if other transactions have modified the selected rows, disable autocommit.)
- 所有SELECT语句会隐式转化为SELECT ... FOR SHARE,即加共享锁。
- 读加共享锁,写加排他锁,读写互斥。如果有未提交的事务正在修改某些行,所有select这些行的语句都会阻塞。
MVCC的实现原理
MVCC,中文叫多版本并发控制,它是通过读取历史版本的数据,来降低并发事务冲突,从而提高并发性能的一种机制。它的实现依赖于隐式字段、undo日志、快照读&当前读、Read View,因此,我们先来了解这几个知识点。
隐式字段
对于InnoDB存储引擎,每一行记录都有两个隐藏列DB_TRX_ID、DB_ROLL_PTR,如果表中没有主键和非NULL唯一键时,则还会有第三个隐藏的主键列DB_ROW_ID。
- DB_TRX_ID,记录每一行最近一次修改(修改/更新)它的事务ID,大小为6字节;
- DB_ROLL_PTR,这个隐藏列就相当于一个指针,指向回滚段的undo日志,大小为7字节;
- DB_ROW_ID,单调递增的行ID,大小为6字节;
undo日志
事务未提交的时候,修改数据的镜像(修改前的旧版本),存到undo日志里。以便事务回滚时,恢复旧版本数据,撤销未提交事务数据对数据库的影响。 undo日志是逻辑日志。可以这样认为,当delete一条记录时,undo log中会记录一条对应的insert记录,当update一条记录时,它记录一条对应相反的update记录。 存储undo日志的地方,就是回滚段。
多个事务并行操作某一行数据时,不同事务对该行数据的修改会产生多个版本,然后通过回滚指针(DB_ROLL_PTR)连一条Undo日志链。
我们通过例子来看一下~
mysql> select * from account ;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| 1 | Jay | 100 |
+----+------+---------+
1 row in set (0.00 sec)
复制代码
- 假设表accout现在只有一条记录,插入该该记录的事务Id为100
- 如果事务B(事务Id为200),对id=1的该行记录进行更新,把balance值修改为90
事务B修改后,形成的Undo Log链如下:
快照读&当前读
快照读:
读取的是记录数据的可见版本(有旧的版本),不加锁,普通的select语句都是快照读,如:
select * from account where id>2;
复制代码
当前读:
读取的是记录数据的最新版本,显示加锁的都是当前读
select * from account where id>2 lock in share mode;
select * from account where id>2 for update;
复制代码
Read View
- Read View就是事务执行快照读时,产生的读视图。
- 事务执行快照读时,会生成数据库系统当前的一个快照,记录当前系统中还有哪些活跃的读写事务,把它们放到一个列表里。
- Read View主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据~
为了下面方便讨论Read View可见性规则,先定义几个变量
m_ids:当前系统中那些活跃的读写事务ID,它数据结构为一个List。 min_limit_id:m_ids事务列表中,最小的事务ID max_limit_id:m_ids事务列表中,最大的事务ID
- 如果DB_TRX_ID < min_limit_id,表明生成该版本的事务在生成ReadView前已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问。
- 如果DB_TRX_ID > m_ids列表中最大的事务id,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问。
- 如果 min_limit_id =<DB_TRX_ID<= max_limit_id,需要判断m_ids.contains(DB_TRX_ID),如果在,则代表Read View生成时刻,这个事务还在活跃,还没有Commit,你修改的数据,当前事务也是看不见的;如果不在,则说明,你这个事务在Read View生成之前就已经Commit了,修改的结果,当前事务是能看见的。
注意啦!! RR跟RC隔离级别,最大的区别就是:RC每次读取数据前都生成一个ReadView,而RR只在第一次读取数据时生成一个ReadView。
已提交读(READ COMMITTED) 存在不可重复读问题的分析历程
我觉得理解一个新的知识点,最好的方法就是居于目前存在的问题/现象,去分析它的来龙去脉~ RC的实现也跟MVCC有关,RC是存在重复读并发问题的,所以我们来分析一波RC吧,先看一下执行流程
假设现在系统里有A,B两个事务在执行,事务ID分别为100、200,并且假设存在的老数据,插入事务ID是50哈~
事务A 先执行查询1的操作
# 事务A,Transaction ID 100
begin ;
查询1:select * from account WHERE id = 1;
复制代码
事务 B 执行更新操作,id =1记录的undo日志链如下
begin;
update account set balance =balance+20 where id =1;
复制代码
回到事务A,执行查询2的操作
begin ;
查询1:select * from account WHERE id = 1;
查询2:select * from account WHERE id = 1;
复制代码
查询2执行分析:
- 事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)在活跃,所以ReadView的m_ids列表内容就是[200]
- 由上图undo日志链可得,最新版本的balance为1000,它的事务ID为200,在活跃事务列表里,所以当前事务(事务A)不可见。
- 我们继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录200,所以这个版本可见,因此,查询2的结果,就是返回balance=100这个记录~~
我们回到事务B,执行提交操作,这时候undo日志链不变
begin;
update account set balance =balance+20 where id =1;
commit
复制代码
再次回到事务A,执行查询3的操作
begin ;
查询1:select * from account WHERE id = 1;
查询2:select * from account WHERE id = 1;
查询3:select * from account WHERE id = 1;
复制代码
查询3执行分析:
- 事务A在执行到SELECT语句时,重新生成一个ReadView,因为事务B(200)已经提交,不载活跃,所以ReadView的m_ids列表内容就是空的了。
- 所以事务A直接读取最新纪录,读取到balance =120这个版本的数据。
所以,这就是RC存在不可重复读问题的过程啦~有不理解的地方可以多读几遍哈~
可重复读(Repeatable Read)解决不可重复读问题的一次分析
我们再来分析一波,RR隔离级别是如何解决不可重复读并发问题的吧~
你可能会觉得两个并发事务的例子太简单了,好的!我们现在来点刺激的,开启三个事务~
假设现在系统里有A,B,C两个事务在执行,事务ID分别为100、200,300,存量数据插入的事务ID是50~
# 事务A,Transaction ID 100
begin ;
UPDATE account SET balance = 1000 WHERE id = 1;
复制代码
# 事务B,Transaction ID 200
begin ; //开个事务,占坑先
复制代码
这时候,account表中,id =1记录的undo日志链如下:
# 事务C,Transaction ID 300
begin ;
//查询1:select * from account WHERE id = 1;
复制代码
查询1执行过程分析:
- 事务C在执行SELECT语句时,会先生成一个ReadView。因为事务A(100)、B(200)在活跃,所以ReadView的m_ids列表内容就是[100, 200]。
- 由上图undo日志链可得,最新版本的balance为1000,它的事务ID为100,在活跃事务列表里,所以当前事务(事务C)不可见。
- 我们继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录100,所以这个版本可见,因此,查询1的结果,就是返回balance=100这个记录~~
接着,我们把事务A提交一下:
# 事务A,Transaction ID 100
begin ;
UPDATE account SET balance = 1000 WHERE id = 1;
commit;
复制代码
在事务B中,执行更新操作,把id=1的记录balance修改为2000,更新完后,undo 日志链如下:
# 事务B,Transaction ID 200
begin ; //开个事务,占坑先
UPDATE account SET balance = 2000 WHERE id = 1;
复制代码
回到事务C,执行查询2
# 事务C,Transaction ID 300
begin ;
//查询1:select * from account WHERE id = 1;
//查询2:select * from account WHERE id = 1;
复制代码
查询2:执行分析:
- 在RR 级别下,执行查询2的时候,因为前面ReadView已经生成过了,所以直接服用之前的ReadView,活跃事务列表为[100,200].
- 由上图undo日志链可得,最新版本的balance为2000,它的事务ID为200,在活跃事务列表里,所以当前事务(事务C)不可见。
- 我们继续找下一个版本,balance为1000这行记录,事务Id为100,也在活跃事务列表里,所以当前事务(事务C)不可见。
- 继续找下一个版本,balance为100这行记录,事务Id为50,小于活跃事务ID列表最小记录100,所以这个版本可见,因此,查询2的结果,也是返回balance=100这个记录~~
锁相关概念补充(附):
共享锁与排他锁
InnoDB 实现了标准的行级锁,包括两种:共享锁(简称 s 锁)、排它锁(简称 x 锁)。
- 共享锁(S锁):允许持锁事务读取一行。
- 排他锁(X锁):允许持锁事务更新或者删除一行。
如果事务 T1 持有行 r 的 s 锁,那么另一个事务 T2 请求 r 的锁时,会做如下处理:
- T2 请求 s 锁立即被允许,结果 T1 T2 都持有 r 行的 s 锁
- T2 请求 x 锁不能被立即允许
如果 T1 持有 r 的 x 锁,那么 T2 请求 r 的 x、s 锁都不能被立即允许,T2 必须等待T1释放 x 锁才可以,因为X锁与任何的锁都不兼容。
记录锁(Record Locks)
- 记录锁是最简单的行锁,仅仅锁住一行。如:SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE
- 记录锁永远都是加在索引上的,即使一个表没有索引,InnoDB也会隐式的创建一个索引,并使用这个索引实施记录锁。
- 会阻塞其他事务对其插入、更新、删除
记录锁的事务数据(关键词:lock_mode X locks rec but not gap),记录如下:
RECORD LOCKS space id 58 page no 3 n bits 72 index `PRIMARY` of table `test`.`t`
trx id 10078 lock_mode X locks rec but not gap
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 4; hex 8000000a; asc ;;
1: len 6; hex 00000000274f; asc 'O;;
2: len 7; hex b60000019d0110; asc ;;
复制代码
间隙锁(Gap Locks)
- 间隙锁是一种加在两个索引之间的锁,或者加在第一个索引之前,或最后一个索引之后的间隙。
- 使用间隙锁锁住的是一个区间,而不仅仅是这个区间中的每一条数据。
- 间隙锁只阻止其他事务插入到间隙中,他们不阻止其他事务在同一个间隙上获得间隙锁,所以 gap x lock 和 gap s lock 有相同的作用。
Next-Key Locks
- Next-key锁是记录锁和间隙锁的组合,它指的是加在某条记录以及这条记录前面间隙上的锁。
RC级别存在幻读分析
因为RC是存在幻读问题的,所以我们先切到RC隔离级别,分析一波~
假设account表有4条数据。
- 开启事务A,执行当前读,查询id>2的所有记录。
- 再开启事务B,插入id=5的一条数据。
- 事务B插入数据成功后,再修改id=3的记录
- 回到事务A,再次执行id>2的当前读查询
- 事务B可以插入id=5的数据,却更新不了id=3的数据,陷入阻塞。证明事务A在执行当前读的时候在id =3和id=4这两条记录上加了锁,但是并没有对 id > 2 这个范围加锁~
- 事务B陷入阻塞后,切回事务A执行当前读操作时,死锁出现。因为事务B在 insert 的时候,会在新纪录(id=5)上加锁,所以事务A再次执行当前读,想获取id> 3 的记录,就需要在 id=3,4,5 这3条记录上加锁,但是 id = 5这条记录已经被事务B 锁住了,于是事务A被事务B阻塞,同时事务B还在等待 事务A释放 id = 3上的锁,最终产生了死锁。
因此,我们可以发现,RC隔离级别下,加锁的select, update, delete等语句,使用的是记录锁,其他事务的插入依然可以执行,因此会存在幻读~
RR 级别解决幻读分析
因为RR是解决幻读问题的,怎么解决的呢,分析一波吧~
假设account表有4条数据,RR级别。
- 开启事务A,执行当前读,查询id>2的所有记录。
- 再开启事务B,插入id=5的一条数据。 可以发现,事务B执行插入操作时,阻塞了~因为事务A在执行select ... lock in share mode的时候,不仅在 id = 3,4 这2条记录上加了锁,而且在id > 2 这个范围上也加了间隙锁。
因此,我们可以发现,RR隔离级别下,加锁的select, update, delete等语句,会使用间隙锁+ 临键锁,锁住索引记录之间的范围,避免范围间插入记录,以避免产生幻影行记录。