mysql中不同事务隔离级别下数据的显示效果--转载

mysql中不同事务隔离级别下数据的显示效果--转载,第1张

概述事务是一组原子性的SQL查询语句,也可以被看做一个工作单元。如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都不会执行。也就是说,事务内的语句要么全部执行,要么一句也不执行。事务的特性:acid,也称为事务的四个测试(原子性,一致性,隔离性,持久性)automicity:原子性,事务所引起的数据库 *** 作,要么都完成,要么都不执行consisitency:一致性,事务执行前的总和和事务执行后的总和是不变的isolation:隔离性, 某个事务的结果只有在完成之后才对其他事务可见durability:持久性,一旦事务成功完成,系统必须保证任何故障都不会引起事务表现出不一致性事务的状态:活动部分提交失败中止提交事务在某一时刻,一定处于上边五种状态中的一种,事务各状态之间的转换如下所示:事务并发导致的问题脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了 *** 作,则后一个事务所读取的数据就会是不正确的。不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新了原有的数据。幻读(Phantom Read):在一个事务的两次查询中数据不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。并发控制多版本并发控制: Multiversion concurrency control,MVCC每个用户 *** 作数据时都是源数据的时间快照,当用户 *** 作完成后,依据各快照的时间点在合并到源数据中锁:要想实现并发控制,最简单的实现机制就是锁(MVCC采用的不是锁机制)。读锁:共享锁,由读表 *** 作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写写锁:独占锁,由写表 *** 作加上的锁,加锁后其他用户不能获取该表或行的任何锁锁粒度:从大到小,MySQL服务器仅支持表级锁,行锁需要存储引擎完成。表锁:锁定某个表页锁:锁定某个页行锁:锁定某行粒度越精细,并发性越好。即行锁的并发性最好,但需要存储引擎的支持。事务的四种隔离级别读未提交(read uncommitted): 允许脏读,也就是可能读取到其他会话中未提交事务修改的数据读提交(read committed): 只能读取到已经提交的数据。oracle等多数数据库默认都是该级别可重读(repeatable read): 在同一个事务内的查询都是事务开始时刻一致的,innodb的默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读可串行(serializable): 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞在MySQL中,在并发控制情况下,不同隔离级别分别有可能产生问题如下所示:上边之所以介绍那么多理论知识,是为了便于理解。在上边的表格中已经列出来了,在不同隔离级别下,数据的显示效果可能出现的问题,现在在linux上安装好mysql,通过我们的实验来一起看一下在不同隔离级别下数据的显示效果吧。实验环境:linux系统:RedHat 5.8linux内核:linux-2.6.18-308.el5mysql版本:mysql-5.6.10-linux-glibc2.5-i686本次实验的所有 *** 作均在虚拟机中完成,通过Xmanager连接虚拟机,然后打开两个会话连接,在两个会话中,同时更改隔离级别,然后查看数据的显示效果。本次实验中mysql采用源码编译安装的方式安装mysql,你也可以使用rpm包的方式直接安装mysql。具体源码安装的方式及过程,这里不再演示,在前面的博客中,我已经介绍了很多次。如果你采用源码编译安装的方式,不知道如何安装mysql,可参看我以前写的博客,里边都有介绍。采用源码编译安装的方式,在mysql的配置文件中,最好启用每表一个表空间。这里我们直接启用。因为是实验,这里没有对mysql设置密码,因此,我们直接使用命令进入mysql。命令及显示效果如下:50[root@mysql ~]# mysql -uroot -p #使用该命令进入mysql,因为没有设置密码,在要求输入密码时直接按回车键即可Enter password:Welcome to the MySQL monitor. Commands end with ; or g.Your MySQL connection id is 2Server version: 5.6.10 MySQL Community Server (GPL)Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.mysql> show variables like '%iso%'; #查看mysql默认的事务隔离级别,默认为可重读。也可以使用select @@tx_isolation命令查看+-----------------+------------------+| Variable_name | Value |+-----------------+------------------+| tx_isolation | REPEATABLE-READ |+-----------------+------------------+1 row in set (0.36 sec)mysql> show databases; #查看系统已经存在的数据库+---------------------+| Database |+---------------------+| information_schema || mysql || performance_schema || test |+---------------------+4 rows in set (0.00 sec)现在导入我们实验所使用的数据库。[root@mysql ~]# mysql < jiaowu.sql #导入实验所用的jiaowu数据库[root@mysql ~]# mysql -uroot -pEnter password:Welcome to the MySQL monitor. Commands end with ; or g.Your MySQL connection id is 7Server version: 5.6.10 MySQL Community Server (GPL)Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or itsaffiliates. Other names may be trademarks of their respectiveowners.Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.mysql> show databases; #查看导入的jiaowu数据库是否存在+----------------------+| Database |+----------------------+| information_schema || jiaowu || mysql || performance_schema || test |+----------------------+5 rows in set (0.01 sec)我们在mysql命令界面下,没有明确启用事务时,输入的每个命令都是直接提交的,因为mysql中有个变量的值,可实现自动提交。也就是说我们每输入一个语句,都会自动提交,这会产生大量的磁盘IO,降低系统的性能。在我们做实验时,因为我们要明确使用事务,所以,建议关闭自动提交的功能,如果不关闭也没有关系,但是如果你没有明确使用事务,想要做下边的实验,那就需要关闭此功能了。这里,我们明确使用事务,且关闭自动提交功能。假如你关闭了自动提交功能,需明确使用事务,否则你输入的所有语句会被当成一个事务进行处理。命令如下:16mysql> select @@autocommit; #查看该值,为1表示启动自动提交+--------------+| @@autocommit |+--------------+| 1 |+--------------+1 row in set (0.00 sec)mysql> set autocommit=0; #关闭自动提交功能Query OK, 0 rows affected (0.00 sec)mysql> select @@autocommit; #重新查看该值,为0表示关闭自动提交功能+--------------+| @@autocommit |+--------------+| 0 |+--------------+1 row in set (0.00 sec)现在打开两个会话,在这两个会话中分别进入mysql,首先记得要就修改两个回话中的autocommit变量,关闭自动提交功能,然后查看事务的隔离级别,默认为REPEATABLE-READ。在两个会话中都需要修改隔离级别。我们先从最低的隔离级别开始演示。30mysql> select @@tx_isolation;+-------------------+| @@tx_isolation |+-------------------+| REPEATABLE-READ |+-------------------+1 row in set (0.00 sec)mysql> set tx_isolation='read-uncommitted'; #修改隔离级别,将隔离级别可重读改为读未提交Query OK, 0 rows affected (0.00 sec)mysql> select @@tx_isolation;+-------------------+| @@tx_isolation |+-------------------+| READ-UNCOMMITTED |+-------------------+在两个回话中,修改完隔离级别后,使用导入的数据库,用tutors表来验证显示效果。mysql> use jiaowu; #使用jaiowu数据库Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -ADatabase changedmysql> show tables; #查看该数据库中都有那些表+-------------------+| Tables_in_jiaowu |+-------------------+| courses || scores || students || tutors |+-------------------+4 rows in se

事务是一组原子性的SQL查询语句,也可以被看做一个工作单元。如果数据库引擎能够成功地对数据库应用所有的查询语句,它就会执行所有查询,如果任何一条查询语句因为崩溃或其他原因而无法执行,那么所有的语句就都不会执行。也就是说,事务内的语句要么全部执行,要么一句也不执行。

  事务的特性:acID,也称为事务的四个测试(原子性,一致性,隔离性,持久性)

  automicity:原子性,事务所引起的数据库 *** 作,要么都完成,要么都不执行

  consisitency:一致性,事务执行前的总和和事务执行后的总和是不变的

  isolation:隔离性, 某个事务的结果只有在完成之后才对其他事务可见

  durability:持久性,一旦事务成功完成,系统必须保证任何故障都不会引起事务表现出不一致性

  事务的状态:

  活动

  部分提交

  失败

  中止

  提交

  事务在某一时刻,一定处于上边五种状态中的一种,事务各状态之间的转换如下所示:

  事务并发导致的问题

  脏读(Drity Read):某个事务已更新一份数据,另一个事务在此时读取了同一份数据,由于某些原因,前一个RollBack了 *** 作,则后一个事务所读取的数据就会是不正确的。

  不可重复读(Non-repeatable read):在一个事务的两次查询之中数据不一致,这可能是两次查询过程中间插入了一个事务更新了原有的数据。

  幻读(Phantom Read):在一个事务的两次查询中数据不一致,例如有一个事务查询了几列(Row)数据,而另一个事务却在此时插入了新的几列数据,先前的事务在接下来的查询中,就会发现有几列数据是它先前所没有的。

  并发控制

  多版本并发控制: Multiversion concurrency control,MVCC

  每个用户 *** 作数据时都是源数据的时间快照,当用户 *** 作完成后,依据各快照的时间点在合并到源数据中

  锁:要想实现并发控制,最简单的实现机制就是锁(MVCC采用的不是锁机制)。

  读锁:共享锁,由读表 *** 作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写

  写锁:独占锁,由写表 *** 作加上的锁,加锁后其他用户不能获取该表或行的任何锁

  锁粒度:从大到小,MysqL服务器仅支持表级锁,行锁需要存储引擎完成。

  表锁:锁定某个表

  页锁:锁定某个页

  行锁:锁定某行

  粒度越精细,并发性越好。即行锁的并发性最好,但需要存储引擎的支持。

  事务的四种隔离级别

  读未提交(read uncommitted): 允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

  读提交(read committed): 只能读取到已经提交的数据。oracle等多数数据库默认都是该级别

  可重读(repeatable read): 在同一个事务内的查询都是事务开始时刻一致的,innodb的默认级别。在sql标准中,该隔离级别消除了不可重复读,但是还存在幻象读

  可串行(serializable): 完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞

  在MysqL中,在并发控制情况下,不同隔离级别分别有可能产生问题如下所示:

  上边之所以介绍那么多理论知识,是为了便于理解。在上边的表格中已经列出来了,在不同隔离级别下,数据的显示效果可能出现的问题,现在在linux上安装好MysqL,通过我们的实验来一起看一下在不同隔离级别下数据的显示效果吧。

  实验环境:

  linux系统:RedHat 5.8

  linux内核:linux-2.6.18-308.el5

  MysqL版本:mysql-5.6.10-linux-glibc2.5-i686

  本次实验的所有 *** 作均在虚拟机中完成,通过Xmanager连接虚拟机,然后打开两个会话连接,在两个会话中,同时更改隔离级别,然后查看数据的显示效果。

  本次实验中MysqL采用源码编译安装的方式安装MysqL,你也可以使用rpm包的方式直接安装MysqL。具体源码安装的方式及过程,这里不再演示,在前面的博客中,我已经介绍了很多次。如果你采用源码编译安装的方式,不知道如何安装MysqL,可参看我以前写的博客,里边都有介绍。采用源码编译安装的方式,在MysqL的配置文件中,最好启用每表一个表空间。这里我们直接启用。

  因为是实验,这里没有对MysqL设置密码,因此,我们直接使用命令进入MysqL。命令及显示效果如下:

  50[root@MysqL ~]# MysqL -uroot -p #使用该命令进入MysqL,因为没有设置密码,在要求输入密码时直接按回车键即可

  Enter password:

  Welcome to the MysqL monitor. Commands end with ; or \g.

  Your MysqL connection ID is 2

  Server version: 5.6.10 MysqL Community Server (GPL)

  copyright (c) 2000,2013,Oracle and/or its affiliates. All rights reserved.

  Oracle is a registered Trademark of Oracle Corporation and/or its

  affiliates. Other names may be Trademarks of their respective

  owners.

  Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

  MysqL> show variables like '%iso%'; #查看MysqL默认的事务隔离级别,默认为可重读。也可以使用select @@tx_isolation命令查看

  +-----------------+------------------+

  | Variable_name | Value |

  +-----------------+------------------+

  | tx_isolation | REPEAtable-READ |

  +-----------------+------------------+

  1 row in set (0.36 sec)

  MysqL> show databases; #查看系统已经存在的数据库

  +---------------------+

  | Database |

  +---------------------+

  | information_schema |

  | MysqL |

  | performance_schema |

  | test |

  +---------------------+

  4 rows in set (0.00 sec)

  现在导入我们实验所使用的数据库。

  [root@MysqL ~]# MysqL < jiaowu.sql #导入实验所用的jiaowu数据库

  [root@MysqL ~]# MysqL -uroot -p

  Enter password:

  Welcome to the MysqL monitor. Commands end with ; or \g.

  Your MysqL connection ID is 7

  Server version: 5.6.10 MysqL Community Server (GPL)

  copyright (c) 2000,Oracle and/or its affiliates. All rights reserved.

  Oracle is a registered Trademark of Oracle Corporation and/or its

  affiliates. Other names may be Trademarks of their respective

  owners.

  Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

  MysqL> show databases; #查看导入的jiaowu数据库是否存在

  +----------------------+

  | Database |

  +----------------------+

  | information_schema |

  | jiaowu |

  | MysqL |

  | performance_schema |

  | test |

  +----------------------+

  5 rows in set (0.01 sec)

  我们在MySQL命令界面下,没有明确启用事务时,输入的每个命令都是直接提交的,因为MysqL中有个变量的值,可实现自动提交。也就是说我们每输入一个语句,都会自动提交,这会产生大量的磁盘IO,降低系统的性能。在我们做实验时,因为我们要明确使用事务,所以,建议关闭自动提交的功能,如果不关闭也没有关系,但是如果你没有明确使用事务,想要做下边的实验,那就需要关闭此功能了。这里,我们明确使用事务,且关闭自动提交功能。假如你关闭了自动提交功能,需明确使用事务,否则你输入的所有语句会被当成一个事务进行处理。命令如下:

  16MysqL> select @@autocommit; #查看该值,为1表示启动自动提交

  +--------------+

  | @@autocommit |

  +--------------+

  | 1 |

  +--------------+

  1 row in set (0.00 sec)

  MysqL> set autocommit=0; #关闭自动提交功能

  query OK,0 rows affected (0.00 sec)

  MysqL> select @@autocommit; #重新查看该值,为0表示关闭自动提交功能

  +--------------+

  | @@autocommit |

  +--------------+

  | 0 |

  +--------------+

  1 row in set (0.00 sec)

  现在打开两个会话,在这两个会话中分别进入MysqL,首先记得要就修改两个回话中的autocommit变量,关闭自动提交功能,然后查看事务的隔离级别,默认为REPEAtable-READ。在两个会话中都需要修改隔离级别。我们先从最低的隔离级别开始演示。

  30MysqL> select @@tx_isolation;

  +-------------------+

  | @@tx_isolation |

  +-------------------+

  | REPEAtable-READ |

  +-------------------+

  1 row in set (0.00 sec)

  MysqL> set tx_isolation='read-uncommitted'; #修改隔离级别,将隔离级别可重读改为读未提交

  query OK,0 rows affected (0.00 sec)

  MysqL> select @@tx_isolation;

  +-------------------+

  | @@tx_isolation |

  +-------------------+

  | read-uncommitted |

  +-------------------+

  在两个回话中,修改完隔离级别后,使用导入的数据库,用tutors表来验证显示效果。

  MysqL> use jiaowu; #使用jaiowu数据库

  Reading table information for completion of table and column names

  You can turn off this feature to get a quicker startup with -A

  Database changed

  MysqL> show tables; #查看该数据库中都有那些表

  +-------------------+

  | tables_in_jiaowu |

  +-------------------+

  | courses |

  | scores |

  | students |

  | tutors |

  +-------------------+

  4 rows in set (0.00 sec)

  在会话1中,我们来修改tutors中的数据,在会话2中我们来查看数据,看会是什么情况。本打算使用tutors表来演示下边的实验,但修改完数据截图时比较麻烦,所以,自己就写了个脚本,比着tutors表的各字段创建了一个新表teachers。脚本写的有点拙劣,有兴趣可自己动手写个更好的脚本来实现创建及插入数据。创建表及插入数据的脚本如下:

  23#!/bin/bash

  #

  #Author: hulunbeIEr,http://lq2419.blog.51cto.com/

  #Description: creating table and inserting data

  #

  let B=0

  MysqL -e "use jiaowu;create table teachers like tutors;"

  read -p "input a number to create NUMBER data. You choice : " NUM #执行该脚本是,会让输入一个数字,因为是实验,所以我们这里进插入5行数据,读者可自行修改

  for I in `seq 1 $NUM`; do

  name=tech$I

  A=`echo $RANDOM/365 | bc`

  until [ $A -ge 40 ] && [ $A -le 100 ]; do

  A=`echo $RANDOM/365 | bc`

  done

  B=`echo $RANDOM%2 | bc`

  if [ $B = 0 ]; then

  GD=F

  else

  GD=M

  fi

  MysqL -e "insert into jiaowu.teachers (Tname,Gender,Age) values ('$name','$GD',$A);"

  echo "create tech$I success."

  done

  执行上边的脚本即可创建相应表及插入数据。查看下我们创建的新表是否成功,里边是否有数据。查询命令及显示结果如下所示:

  创建的新表已经存在,且插入数据也已成功,现在我们就用teachers表来演示以下各实验。演示实验从低隔离级别开始,到高隔离级别结束。

  read-uncommitted:读未提交

  首先,修改两个会话中的自动提交功能,将其关闭,然后修改系统默认的隔离级别,从低级别开始,将默认的可重读改为读未提交。

  以上修改在两个会话中完成后,我们明确启动事务,查询下表中的所有数据信息,显示TID为5的老师的年龄为61,然后在会话1中更新teachers表中TID为5的老师的年龄,将原来的61改为50,接着,在两个会话中在重新查询下所有的数据,看TID为5的老师的年龄是多少。命令及显示效果如下所示:

  当我们在会话1中使用rollback回滚之后,再在两个会话中查看数据,发现还是61。从上边两个会话的显示效果,可以看到,在隔离级别为读未提交时,当我们开启一个事务时,在该事务中修改了某个数据行的信息,且在该事务中,并未提交,但在另一个事务中,如果都是对同一个数据集的 *** 作,会发现我们前后两次查询的结果不一样了,在同一个事务中,两次查询得到的结果不一样,这种情况是不允许出现。此时就出现了脏读、不可重复读及幻读的现象。

  Read-committed:读提交

  首先在上边修改的基础上再次修改隔离级别,将读未提交改为读提交。然后,我们还去修改TID为5的老师的年龄,将61改为40。接着,在两个会话中再次查看显示效果。命令及显示效果如下所示:

  现在,在会话1中,我们使用commit命令提交事务,然后再会话2中,查看下显示效果,看又是怎么样的。结果会发现,在会话2中,TID为5的老师的年龄变成了40。从上边的显示效果,会发现,当隔离级别为read-committed(读提交)时,当我们在会话1中开启事务,并修改了某一行数据的信息时,在会话1中可以看到修改后的效果,但在会话2中并不会看到修改后的结果。当我们在会话1中提交事务后,在再会话2中查询,会发现,跟我们上次查询的不一样了,显示的是会话1修改后的结果。在该隔离级别下,虽然可以避免脏读的现象发生,但还是会出现不可重复读和幻读的现象。

  Repeatable-read:可重读

  首先修改隔离级别,将读提交改为可重读。然后,在会话1中,依然修改TID为5的老师的年龄,将其年龄改为60。最后,两个会话中再来查看结果。

  从上边的显示结果会发现,在该隔离级别下,当我们在会话1中修改了某个值时,会话1会立即显示修改后的结果,而会话2中不会显示。当我们在会话1中提交事务后,得到永久结果,在会话1中在查看,还是修改后的结果,但在会话2中,还是原来的结果。但当我们在会话2中提交事务后,再来查询,发现是会话1中修改后的结果,在会话2中,我们没做任何修改,我一提交事务,发现,数据竟然变了。起码,事务提交前和提交后看到的数据是不一样的。此时就出现了幻读的现象。

  Serializable:可串行

  首先,我们依然修改隔离级别,将可重读改为可串行。然后再会话1中,启动事务,并将TID为5的老师的年龄由60改为100,然后,在会话1和2中查看。在没有启动事务前,我们先来看下TID为5的老师年龄是多少。

  在上边的显示效果中,发现,在可串行隔离级别下,当我们启动两个事务时,如果在其中一个事务中,修改了某个数据行,在另一个事务中,我们是无法查询到该数据集的信息的,也就是说系统不会显示出任何信息,除非在修改的事务中,我们提交了,或者是执行了rollback命令。假如在修改的事务中,我们既没有执行commit命令提交,也没有执行rollback命令回滚,那么,在另一个事务中,当我们查询时,会一直卡着不动,直到锁时间超时,然后提示我们重新开启事务。在上图中,发现,在会话1中,当我们启动一个事务,并修改了一个数据后,在会话2中,我们是不能查询到任何信息的,当我们在会话1中执行了rollback命令后,会话2中才会显示查询结果,此时的查询所用时间会比以前查询所用时间长很多。因为在可串行级别下,是不允许通知开启多个事务的,或者说是不允许对同一个数据集执行任何 *** 作的。此时,既不会出现脏读、不可重复读,也不会出现幻读现象。但是此时的并发性会受影响。

  综上所述,在低隔离级别下,当有多个事务并发执行时,虽然会产生很多问题,如脏读、不可重复读、幻读等现象,但事务的并发性较好,可同时执行多个事务;在高隔离级别下,当有多个事务并发执行时,因在高隔离级别下,不支持多事务并发执行,虽然不会出现诸如脏读、不可重复读及幻读等现象,但并发性较低。InnoDB默认的隔离级别是repeatable-read(可重读),而在大多数的数据库中,oracle等多数数据库,一般默认的隔离级别是read-committed(读提交)。一般来说在实际应用中,除了在银行、股票等对数据安全要求较高的场景外,必须使用较高隔离级别外,其他对数据要求不高的场合,可采用低隔离级别,以提高并发性。然而,究竟哪种隔离级别更适合,那就需要看你对数据的安全性要求有多高了。

原文:http://www.haofanben.com/jiaocheng/MysqLshujuku/197015.HTML

总结

以上是内存溢出为你收集整理的mysql中不同事务隔离级别下数据的显示效果--转载全部内容,希望文章能够帮你解决mysql中不同事务隔离级别下数据的显示效果--转载所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/1169151.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-02
下一篇 2022-06-02

发表评论

登录后才能评论

评论列表(0条)

保存