使用pymysql 中的游标cursor对象中的execute方法,将多条sql语句提交到缓冲区并一起commit,查和增得到的结果是否与提交顺序有关

问题描述:使用pymysql操作数据库时,先使用游标将多条sql语句添加到缓存中,然后一次性提交事务,那么同一次提交的事务中,查询的sql语句是否会查询到本次事务中增加的sql语句插入的记录呢?

首先声明:这里使用的表是innoDB存储引擎,对该引擎,支持事务操作,以及行级锁,外键等等。mysql数据中的知识

开始测试:

先来测试,创建表,和在该表中插入记录,如果是事务,那么是否遵守其约定?

import pymysql

config = {
    'host':'localhost'
    ,'user':'root'
    ,'password':'xxxxxx'
    ,'database':'dbx'
    ,'charset':'utf8'
    ,'port':3306   #注意端口为int 而不是str
}

db = pymysql.connect(**config)
cur = db.cursor()

try:
    c_sql = '''create table test1(
                    id int(3) zerofill primary key auto_increment,
                    name varchar(15) not null
                )engine=InnoDB,charset=utf8;
            '''
    cur.execute(c_sql)
    #插入一条记录
    i_sql ='insert into test1(name) values("chizer");'
    cur.execute(i_sql) 
    #统一提交
    db.commit()
except Exception as e:
    db.rollback()
    print('Failed:',e)

cur.close()
db.close()
    


这里是将创建表和在该表插入纪录统一提交,结果运行没有问题。那么交换一下顺序,先插入一个记录,前提是数据库中没有该表,再去创建,那么统一提交之后是否按照队列执行

import pymysql

config = {
    'host':'localhost'
    ,'user':'root'
    ,'password':'xxxxxx'
    ,'database':'dbx'
    ,'charset':'utf8'
    ,'port':3306   #注意端口为int 而不是str
}

db = pymysql.connect(**config)
cur = db.cursor()

try:
    c_sql = '''create table test1(
                    id int(3) zerofill primary key auto_increment,
                    name varchar(15) not null
                )engine=InnoDB,charset=utf8;
            '''
    
    #插入一条记录
    i_sql ='insert into test1(name) values("chizer");'
    
    cur.execute(i_sql) 
    cur.execute(c_sql) #此处先提交插入,后提交创建表
    #统一提交
    db.commit()
except Exception as e:
    db.rollback()
    print('Failed:',e)

cur.close()
db.close()

结果是报错,这可以想的明白,比如mysql中,表还没有创建就要插入?当然找不到表。这是一个sql错误。

Failed: (1146, "Table 'db5.test1' doesn't exist")
 

接下来回到正题,在该表中先插入在查询 和 先查询在插入 得到的查询结果 是否和 添加到缓存顺序有关?

import pymysql

config = {
    'host':'localhost'
    ,'user':'root'
    ,'password':'xxxxxx'
    ,'database':'dbx'
    ,'charset':'utf8'
    ,'port':3306   #注意端口为int 而不是str
}

db = pymysql.connect(**config)
cur = db.cursor()

try:
    c_sql = '''create table test1(
                    id int(3) zerofill primary key auto_increment,
                    name varchar(15) not null
                )engine=InnoDB,charset=utf8;
            '''

    i_sql ='insert into test1(name) values("chizer");'
    s_sql = 'select * from test1;'

    #先去查询,查询不需要提交到缓存,所以报错是没有表,因为创建表的事物还没有commit
    cur.execute(s_sql)
    cur.execute(c_sql) #加入创表
    cur.execute(i_sql) #加入插入记录
    db.commit()#统一提交
    # cur.execute(s_sql) #加入查询记录
    
    
    
    result = cur.fetchall() #得到查询结果
    print(result)

except Exception as e:
    db.rollback()
    print('Failed:',e)

cur.close()
db.close()
    


Failed: (1146, "Table 'db5.test1' doesn't exist") 同样的错误类似上面,没有创建表。

接下来:

import pymysql

config = {
    'host':'localhost'
    ,'user':'root'
    ,'password':'123456'
    ,'database':'db5'
    ,'charset':'utf8'
    ,'port':3306   #注意端口为int 而不是str
}

db = pymysql.connect(**config)
cur = db.cursor()

try:
    c_sql = '''create table test1(
                    id int(3) zerofill primary key auto_increment,
                    name varchar(15) not null
                )engine=InnoDB,charset=utf8;
            '''

    i_sql ='insert into test1(name) values("chizer");'
    s_sql = 'select * from test1;'

    #先去查询,查询不需要提交到缓存,所以报错是没有表,因为创建表的事物还没有commit
    # cur.execute(s_sql)
    cur.execute(c_sql) #加入创表
    cur.execute(i_sql) #加入插入记录
    db.commit()#统一提交

    #提交之后,再去查询,注意注意!!!该游标对象执行查询时往下并没有commit,
    #那么可以认为执行查询语句时,并不会添加到缓存,而是直接执行!
    cur.execute(s_sql) #执行查询记录
    
    
    
    result = cur.fetchall() #得到查询结果
    print(result)

except Exception as e:
    db.rollback()
    print('Failed:',e)

cur.close()
db.close()
    


得到的结果:((1, 'chizer'),)
那么再去试着在后面插入一条数据看看得到的查询结果>>

import pymysql

config = {
    'host':'localhost'
    ,'user':'root'
    ,'password':'123456'
    ,'database':'db5'
    ,'charset':'utf8'
    ,'port':3306   #注意端口为int 而不是str
}

db = pymysql.connect(**config)
cur = db.cursor()

try:
    c_sql = '''create table test1(
                    id int(3) zerofill primary key auto_increment,
                    name varchar(15) not null
                )engine=InnoDB,charset=utf8;
            '''

    i_sql ='insert into test1(name) values("chizer");'
    s_sql = 'select * from test1;'

     
    cur.execute(c_sql) #加入创表
    cur.execute(i_sql) #加入插入记录
    db.commit()#统一提交
    
    cur.execute(s_sql) #执行查询记录
    result = cur.fetchall() #得到查询结果
    print(result)
    
    i_sql ='insert into test1(name) values("chizer2");'
    cur.execute(i_sql)   
    db.commit() #提交第二条插入sql


except Exception as e:
    db.rollback()
    print('Failed:',e)

cur.close()
db.close()
    


返回结果:((1, 'chizer'),),符合预期猜测,插入一条记录之后去查询,得到一条,再去提交插入第二条时并不会查到。说明和查询的顺序以及提交的顺序有关。那么稍微改变一下代码,看一看结果,加第二次添加的cursor对象放到查询前面,同时将第二次提交的语句放在后面试试看>>

import pymysql

config = {
    'host':'localhost'
    ,'user':'root'
    ,'password':'123456'
    ,'database':'db5'
    ,'charset':'utf8'
    ,'port':3306   #注意端口为int 而不是str
}

db = pymysql.connect(**config)
cur = db.cursor()

try:
    c_sql = '''create table test1(
                    id int(3) zerofill primary key auto_increment,
                    name varchar(15) not null
                )engine=InnoDB,charset=utf8;
            '''

    i_sql ='insert into test1(name) values("chizer");'
    s_sql = 'select * from test1;'

     
    cur.execute(c_sql) #加入创表
    cur.execute(i_sql) #加入插入记录
    db.commit()#统一提交
    
    i_sql ='insert into test1(name) values("chizer2");'
    cur.execute(i_sql)  

    cur.execute(s_sql) #执行查询记录
    result = cur.fetchall() #得到查询结果
    print(result)
    
 
    db.commit() #提交第二条插入sql


except Exception as e:
    db.rollback()
    print('Failed:',e)

cur.close()
db.close()
    


得到结果:((1, 'chizer'), (2, 'chizer2'))

这个结果很意外,不是由commit执行提交第二次插入记录吗?查询只管去查询啊,怎么会得到两条记录?在运行代码时我发现得到打印结果之前,稍微的停顿了一下,说明在插入语句和提交之间的查询cur去执行查询时,会发生阻塞!这个结果让我感到很意外。当然,把查询cur总是放在最后,保证所有的commit都在前面执行完毕,一定会得到最后更新出来的那张表,去执行查到结果。这是没有问题的。

 

到这里应该明白,查询,是不需要commit,它是直接去数据库中查对应的表,如果没有这个表,就报错。如果查询写在添加和提交中间,会发生阻塞,等所有执行完才会去查询。

总结:创建,增,删,改 都需要用数据库连接的对象去提交事务,而查询并不用去提交,代码执行到查询处,游标对象会直接去查询,将得到的结果保存在自己的内部,使用fetch*方法可以获取。所以前面所说的问题根本不存在什么时候添加到缓存,与顺序是否有关,因为查询是不需要commit,它会直接去数据库中对应的表去查询。

那么和什么有关呢,查询的到的结果和commit的先后顺序有关,如果先提交了插入的记录,再去查询,那么ok,select * 会包括该记录,如果先去select * 再去将添加的记录commit ,那么查询得到的结果一定不包含该记录。

所以也不存在一开始的顾虑,即是否和存储引擎有关。其实问题很简单,我想的有点复杂化,关键在于查询不需要commit。

思考:pymysql为什么没有将查询加入到事务中,或者可以理解为查询不需要修改数据库连接的虚拟对象?所以不要提交它?

这些问题还需要进一步去探索,以上是我的一些个人看法,有什么问题希望大家指出,多多交流!

 

 

 

 

 

 

 

 

 

  • 19
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值