mysql事务

事务的四大特性(ACID)

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

原子性:事务内执行的sql操做看成一个总体,要么同时成功,要么同时失败回滚 一致性:强调的是数据的状态,指的是数据库从一个一致性状态到另一个一致性状态,打个比方,A有200,B有100,A转100给B,那么最后的一致性状态是A有100,B有200,若是状态是A有100,B仍是原来的100,那这就不符合数据的一致性 隔离性:一个事务所作的修改在最终提交之前,对其余事务是不可见的,也就是说,A有200,B有100,A转100,B加100,尚未提交的时候,又开启了一个事物,此时看到的是A有200,B有100,也就是第一个事物没有commit以前的状态;还有一点就是说事物对某 行的某个字段进行加操做,那么在没有提交以前,其余事物是不能修改这一行的这个字段的,由于mysql此时的行锁被第一个事物拿到,commit以后才会释放 持久性:事物一旦进行了提交,那么数据落盘,所作的修改会永久保存到数据库mysql

事务的隔离级别

事务的隔离级别是为了解决mysql并发问题的几种控制手段。sql

事务的并发问题

一、脏读:事务A读取了事务B更新的数据,而后B回滚操做,那么A读取到的数据是脏数据 二、不可重复读:事务 A 屡次读取同一数据,事务 B 在事务A屡次读取的过程当中,对数据做了更新并提交,致使事务A屡次读取同一数据时,结果 不一致。 三、幻读:系统管理员A将数据库中全部学生的成绩从具体分数改成ABCDE等级,可是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉同样,这就叫幻读。 小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住知足条件的行,解决幻读须要锁表 <font color='red'>单条</font>修改数据的命令会自动的触发事务,包括insert、update、delete。 而在SQL语句中有手动开启事务的缘由是:能够进行屡次数据的修改,若是成功一块儿成功,不然一块儿会滚到以前的数据.数据库

4种隔离级别

Read Uncommitted(读取未提交内容)

在该隔离级别,全部事务均可以看到其余未提交事务的执行结果。本隔离级别不多用于实际应用,由于它的性能也不比其余级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。session

Read Committed(读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它知足了隔离的简单定义:一个事务只能看见已经提交事务所作的改变。,由于同一事务的其余实例在该实例处理其间可能会有新的commit,因此同一select可能返回不一样结果,这就是不可重复读并发

Repeatable Read(可重读)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到一样的数据行。不过理论上,这会致使另外一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另外一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎经过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。性能

Serializable(可串行化)

这是最高的隔离级别,它经过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每一个读的数据行上加上共享锁。在这个级别,可能致使大量的超时现象和锁竞争。测试

在测试的时候,把mysql事务级别设置成 Repeatable Read,一个事务往里插数据,另外一个事务是看不到其余事务插入的数据的,即读的不是最新数据,咱们把这种现象也看做是幻读fetch

查看和设置隔离级别

SELECT @@tx_isolation 设置mysql的隔离级别:set session transaction isolation level 设置事务隔离级别spa

pymysql

对于pymysql有几个点须要注意线程

默认支持事务

pymysql默认开启事务,从每次执行执行增删改都须要最终commit就能知道。 经过pymysql增长数据但未提交时候,发现表的AUTO_INCREMENT是一直递增的(说明数据库已经收到插入指令了,就等着拍板呢),这是为了解决并发的考量,而且若是回滚AUTO_INCREMENT并不会减小,而是一直递增下去,这样才不会出错。

cursor对象存放查询的数据

import pymysql
conn = pymysql.connect(host='localhost', user='root', password="123456",database='test', port=3306, charset='utf8')
cur = conn.cursor()
cur.execute('select * from department')
Out[5]: 4
cur.fetchone()
Out[6]: (200, '技术')
cur.execute('select * from employee')
Out[7]: 18
cur.fetchone()
Out[8]: 
(1,
 'egon',
 'male',
 18,
 datetime.date(2017, 3, 1),
 '办事处外交大使',
 None,
 7300.33,
 401,
 1)

经过上面咱们能够发现,当咱们查询的时候,取数据没有取完就执行另外一条查询语句,那么先前的查询结果会被覆盖。也就是说执行了一条查询语句,那么就应该当即取出结果,不然拿着这个cursor去执行任何增删改查操做,原来存储的查询数据都会被清掉

pymysql模块的threadsafety = 1

若是在多个线程中的cursor共用一个conn链接,那么就会报相似pymysql.err.InternalError: Packet sequence number wrong - got 45 expected 0的错误

  1. 每一个线程拥有本身的链接
  2. 全部线程共用一个链接池,须要考虑线程总数和链接池链接数上限的问题

pymysql遇到的幻读

以前我开了两个线程,一个线程取数据,一个线程往表插入数据,最终的结果是每次取得的数据都是同样的,可是数据表确确实实是在不停地增长数据。这是由于数据库的隔离级别形成的.解决办法有两个:

  1. 修改隔离级别
  2. 创建conn的时候加上autocommit=True参数
相关文章
相关标签/搜索