Python 数据库的Connection、Cursor两大对象

Python 数据库的Connection、Cursor两大对象

pymysql是Python中操做MySQL的模块,其使用方法和py2的MySQLdb几乎相同。html

Python 数据库图解流程python

   Connection、Cursor比喻mysql

 

 

 

Connection()的参数列表web

host,链接的数据库服务器主机名,默认为本地主机(localhost)。
user,链接数据库的用户名,默认为当前用户。
passwd,链接密码,没有默认值。
db,链接的数据库名,没有默认值。
conv,将文字映射到Python类型的字典。
MySQLdb.converters.conversions
cursorclass,cursor()使用的种类,默认值为MySQLdb.cursors.Cursor。
compress,启用协议压缩功能。
named_pipe,在windows中,与一个命名管道相链接。
init_command,一旦链接创建,就为数据库服务器指定一条语句来运行。
read_default_file,使用指定的MySQL配置文件。
read_default_group,读取的默认组。
unix_socket,在unix中,链接使用的套接字,默认使用TCP。
port,指定数据库服务器的链接端口,默认是3306。sql

 

 

 

链接对象的db.close()方法可关闭数据库链接,并释放相关资源。数据库

链接对象的db.cursor([cursorClass])方法返回一个指针对象,用于访问和操做数据库中的数据。
链接对象的db.begin()方法用于开始一个事务,若是数据库的AUTOCOMMIT已经开启就关闭它,直到事务调用commit()和rollback()结束。
链接对象的db.commit()和db.rollback()方法分别表示事务提交和回退。
指针对象的cursor.close()方法关闭指针并释放相关资源。
指针对象的cursor.execute(query[,parameters])方法执行数据库查询。
指针对象的cursor.fetchall()可取出指针结果集中的全部行,返回的结果集一个元组(tuples)。
指针对象的cursor.fetchmany([size=cursor.arraysize])从查询结果集中取出多行,咱们可利用可选的参数指定取出的行数。
指针对象的cursor.fetchone()从查询结果集中返回下一行。
指针对象的cursor.arraysize属性指定由cursor.fetchmany()方法返回行的数目,影响fetchall()的性能,默认值为1。
指针对象的cursor.rowcount属性指出上次查询或更新所发生行数。-1表示还没开始查询或没有查询到数据。segmentfault

 

 

 

Cursorwindows

经常使用方法:安全

close():关闭此游标对象
fetchone():获得结果集的下一行
fetchmany([size = cursor.arraysize]):获得结果集的下几行
fetchall():获得结果集中剩下的全部行
excute(sql[, args]):执行一个数据库查询或命令
excutemany(sql, args):执行多个数据库查询或命令ruby

 

 

 

 

 

 

 

 

 经常使用属性:

connection:建立此游标对象的数据库链接
arraysize:使用fetchmany()方法一次取出多少条记录,默认为1

事务

事务命令

事务指逻辑上的一组操做,组成这组操做的各个单元,要不所有成功,要不所有不成功。

数据库开启事务命令 

start transaction 开启事务
Rollback 回滚事务,即撤销指定的sql语句(只能回退insert delete update语句),回滚到上一次commit的位置
Commit 提交事务,提交未存储的事务
savepoint 保留点 ,事务处理中设置的临时占位符 你能够对它发布回退(与整个事务回退不一样)   

 转帐实例:

UPDATE account set balance=balance-5000 WHERE name=”yuan”;
UPDATE account set balance=balance+5000 WHERE name=”xialv”;
 
-- 建立表
create table test2(id int PRIMARY KEY auto_increment,name VARCHAR(20)) engine=innodb;

-- 插入数据
INSERT INTO test2(name) VALUE ("alvin"),
                              ("yuan"),
                              ("xialv");



start transaction; -- 开启事务
insert into test2 (name)values('silv');
select * from test2;
commit;   -- 提交事务


-- 保留点

start transaction;
insert into test2 (name)values('wu');
savepoint insert_wu; -- 给上面刚才insert的命令起了个名字叫insert_wu,并设置一个保留点,对重要的sql,要紧挨着设置保留点
select * from test2;



delete from test2 where id=4;
savepoint delete1;
select * from test2;


delete from test2 where id=1;
savepoint delete2;
select * from test2;

rollback to delete1;  -- 回滚到某个设置的节点


select * from test2;

savepoint
 

事务特性

<1> 原子性(Atomicity):原子性是指事务是一个不可分割的工做单位,事务中的操做要么都发生,要么都不发生。

<2> 一致性(Consistency):事务先后数据的完整性必须保持一致。在事务执行以前数据库是符合数据完整性约束的,不管事务是否执行成功,事务结束后的数据库中的数据也应该是符合完整性约束的。在某一时间点,若是数据库中的全部记录都能保证知足当前数据库中的全部约束,则能够说当前的数据库是符合数据完整性约束的。
好比删部门表前应该删掉关联员工(已经创建外键),若是数据库服务器发生错误,有一个员工没删掉,那么此时员工的部门表已经删除,那么就不符合完整性约束了,因此这样的数据库也就性能太差啦!

<3>隔离性(Isolation):事务的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务所干扰,多个并发事务之间数据要相互隔离。

<4>持久性(Durability):持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即便数据库发生故障也不该该对其有任何影响。

3、隔离性:
将数据库设计为串行化程的数据库,让一张表在同一时间内只能有一个线程来操做。若是将数据库设计为这样,那数据库的效率过低了。因此数据库的设计这没有直接将数据库设计为串行化,而是为数据库提供多个隔离级别选项,使数据库的使用者能够根据使用状况本身定义到底须要什么样的隔离级别。

不考虑隔离性可能出现的问题:

脏读

 
--一个事务读取到了另外一个事务未提交的数据,这是特别危险的,要尽力防止。
        a 1000
        b 1000
        a:
            start transaction;
            update set money=money+100 where name=b;
        b:
            start transaction;
            select * from account where name=b;--1100
            commit;
        a:
            rollback;
        b:  start transaction;
            select * from account where name=b;--1000
 

不可重复读

 
--在一个事务内读取表中的某一行数据,屡次读取结果不一样。(一个事务读取到了另外一个事务已经提交
-- 的数据--增长记录、删除记录、修改记录),在某写状况下并非问题,在另外一些状况下就是问题。

a:
start transaction;
select 活期帐户 from account where name=b;--1000    活期帐户:1000
select 按期帐户 from account where name=b;--1000   按期帐户:1000
select 固定资产 from account where name=b;--1000   固定资产:1000
------------------------------
b:
start transaction;
update set money=0 where name=b;(把某一个帐户的资金置为0)
commit;
------------------------------
select 活期+按期+固定 from account where name=b; --2000 总资产: 2000
 

虚读

 
是指在一个事务内读取到了别的事务插入的数据,致使先后读取不一致。
(一个事务读取到了另外一个事务已经提交的数据---增长记录、删除记录),在某写状况下并非问题,在另外一些状况下就是问题。 b 1000 c 2000 d 3000 a: start transaction select sum(money) from account;---3000 3000(b+c) ------------------- d:start transaction; insert into account values(d,3000); commit; ------------------- select count(*)from account;---3 3(算上插入的d总共三我的) 3000/3 = 1000 1000 (可是总金额仍是按照b和c两我的算的,因此平均金额不对)
 

四个隔离级别:
Serializable:可避免脏读、不可重复读、虚读状况的发生。(串行化)
Repeatable read:可避免脏读、不可重复读状况的发生。(可重复读)不能够避免虚读
Read committed:可避免脏读状况发生(读已提交)
Read uncommitted:最低级别,以上状况均没法保证。(读未提交)

安全性考虑:Serializable>Repeatable read>Read committed>Read uncommitted
数据库效率:Read uncommitted>Read committed>Repeatable read>Serializable

通常状况下,咱们会使用Repeatable read、Read committed mysql数据库默认的数据库隔离级别Repeatable read

mysql中设置数据库的隔离级别语句:

set [global/session] transaction isolation level xxxx;

若是使用global则修改的是数据库的默认隔离级别,全部新开的窗口的隔离级别继承自这个默认隔离级别若是使用session修改,则修改的是当前客户端的隔离级别,和数据库默认隔离级别无关。当前的客户端是什么隔离级别,就能防止什么隔离级别问题,和其余客户端是什么隔离级别无关。
mysql中设置数据库的隔离级别语句:

select @@tx_isolation;

事务

事务指逻辑上的一组操做,组成这组操做的各个单元,要不所有成功,要不所有不成功。

数据库开启事务命令     

-- start transaction 开启事务
-- Rollback 回滚事务,即撤销指定的sql语句(只能回退insert delete update语句),回滚到上一次commit的位置
-- Commit 提交事务,提交未存储的事务
--
-- savepoint 保留点 ,事务处理中设置的临时占位符 你能够对它发布回退(与整个事务回退不一样)
实例

--建立表
create table account(
id int primary key auto_increment,
name varchar (25),
balance double
);

insert into account values (1,'alex',8000),(2,'ego',8000);

-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 8000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+


start transaction ;--开始事务

update account set balance=balance-5000 where name='alex';
select * from account;
-- +----+------+---------+ --此时数据并无写入数据库,只是显示命令的结果,除非在操做下面写commit
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 3000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

savepoint update1; --设置保留点

update account set balance=balance+5000 where name='ego';
select * from account;

-- +----+------+---------+ --同样数据没有写入数据库
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 3000 |
-- | 2 | ego | 13000 |
-- +----+------+---------+

savepoint update2;

rollback to update1; --回滚至操做update1处,update1以上的操做任然存在,update1下的操做将全被取消
select * from account;

-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 3000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

rollback ; --直接回滚,则会回滚自前面的commit处,若是没有commit就一直回滚至开头
-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 8000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

commit ; --提交数据,此时数据才真正写入数据库
select * from account;

-- +----+------+---------+
-- | id | name | balance |
-- +----+------+---------+
-- | 1 | alex | 8000 |
-- | 2 | ego | 8000 |
-- +----+------+---------+

 

Python3 pymysql事务处理,执行多条sql语句后提交

# -*- coding: utf-8 -*-

import pymysql.cursors
# 链接数据库
connect = pymysql.Connect(
    host='localhost',
    port=3310,
    user='user',
    passwd='123',
    db='test',
    charset='utf8'
)
# 事务处理
sql_1 = "UPDATE staff SET saving = saving + 1000 WHERE user_id = '1001' "
sql_2 = "UPDATE staff SET expend = expend + 1000 WHERE user_id = '1001' "
sql_3 = "UPDATE staff SET income = income + 2000 WHERE user_id = '1001' "

try:
    cursor.execute(sql_1)  # 储蓄增长1000
    cursor.execute(sql_2)  # 支出增长1000
    cursor.execute(sql_3)  # 收入增长2000
except Exception as e:
    connect.rollback()  # 事务回滚
    print('事务处理失败', e)
else:
    connect.commit()  # 事务提交
    print('事务处理成功', cursor.rowcount)

# 关闭链接
cursor.close()
connect.close()

 

python pymysql cursor的问题

使用python操做mysql的时候通常都会使用以下语句:

官方示例
import pymysql.cursors # 链接到数据库后实际上TCP的链接状态是ESTABLISHED connection = pymysql.connect(host='localhost', user='user', password='passwd', db='db', charset='utf8mb4', cursorclass=pymysql.cursors.DictCursor) try: with connection.cursor() as cursor: sql = "INSERT INTO `users` (`email`, `password`) VALUES (%s, %s)" cursor.execute(sql, ('webmaster@python.org', 'very-secret')) #默认不自动提交事务,因此须要手动提交 connection.commit() with connection.cursor() as cursor: sql = "SELECT `id`, `password` FROM `users` WHERE `email`=%s" cursor.execute(sql, ('webmaster@python.org',)) result = cursor.fetchone() print(result) finally: connection.close() 

在这段代码里,有一个疑惑的点是,咱们如今建立了一个链接,可是实例化了多个cursor,咱们可不可使用同一个链接的同一个cursor来重复使用,代码以下

with connect.cursor() as cursor: cursor.execute("select * from person limit 1") print(id(cursor)) data = cursor.fetchone() print(data) print("=============") cursor.execute("select * from person limit 1") print(id(cursor)) data = cursor.fetchone() print(data) 

上面的代码,咱们执行完了以后发现查询操做是能够直接使用的,而且不会产生冲突,咱们经过打印cursor的地址发现是同一个cursor。

插入操做
with connect.cursor() as cursor: for id in range(1, 100, 2): cursor.execute("insert into test(id)values(%d)"%id) print(id) id += 1 cursor.execute("insert into test(id)values(%d)"%id) time.sleep(2) print(id) 

在单进程单线程环境下依然没有问题

删除
with connect.cursor() as cursor: for id in range(100): # cursor.execute("insert into test(id)values(%d)" % id) cursor.execute("delete from test where id=%s"%id) time.sleep(5) time.sleep(10) 

也没有问题

可是有博客说多进程环境下会出现问题,我一直想重现,可是没有成功,等之后重现了再来更新。

可是

  • 建立了一个 cursor 之后,建议完成一个事务就 commit 一下,不要一直用它,这样一直使用,并不会和数据库完成数据同步,若是操做太多,提交的时候会超时,形成部分数据更新,部分数据丢失,数据不一致且效率低。
    而且握着 cursor 期间,数据库端发生改变,也无法和客户端同步。

参考连接:
Python 数据库的Connection、Cursor两大对象
PyMySQL 0.9.2
python - 在 python MySQLdb模块中,是否应该重用游标

你看一下MySQLdb下面的cursors模块,DictCursor的这个功能是继承于CursorDictRowsMixIn,这个MixIn提供了3个额外的方法: fetchoneDict、fetchmanyDict、fetchallDict。

>>> import MySQLdb >>> c = MySQLdb.connect('127.0.0.1', 'root', 'password', 'test') >>> x = c.cursor(MySQLdb.cursors.DictCursor) >>> x.execute('select * from user') 2L >>> x.fetchoneDict() {'age': 26L, 'id': 1L, 'name': 'test'}


2、execute()之sql注入

这里只截图演示三种SQL注入示例截图

1

2

3

 

 

解决方法: 

# 原来是咱们对sql进行字符串拼接 # sql="select * from userinfo where name='%s' and password='%s'" %(username,pwd) # print(sql) # result=cursor.execute(sql) #改写为(execute帮咱们作字符串拼接,咱们无需且必定不能再为%s加引号了) sql="select * from userinfo where name=%s and password=%s" #!!!注意%s须要去掉引号,由于pymysql会自动为咱们加上 result=cursor.execute(sql,[user,pwd]) #pymysql模块自动帮咱们解决sql注入的问题,只要咱们按照pymysql的规矩来。
 

pymysql .cursor属性方法(tcy)

cursor.excutemany(query, args)#执行多个数据库查询或命令参数:query - 要在服务器上执行的查询args - 序列或映射的序列。它用做参数。返回:受影响的行数(若是有)说明:提升多行INSERT和REPLACE的性能。不然它等同于使用execute()循环遍历argsexecutemany()生成的最大语句大小为max_allowed_pa​​cket - packet_header_sizecursor.max_stmt_length #1024000con.max_allowed_packet#16777216实例:str_insert = "INSERT INTO Cu_table (id) VALUES (%s)"cursor.executemany(str_insert,['A','B','C','D']) #一次插入A B C D 四个值方法:调用函数cursor.callproc(procname, args=())  # 调用数据库中的存储过程参数:procname表示数据库中存储过程的名字,args表示为存储过程传入的参数。返回:返回原始args调用的结果做为输入序列的修改副本返回。该过程还能够提供结果集做为输出。而后必须经过标准.fetch * ()方法使其可用调用无参数存储过程:cursor.callproc('p2')  # 等价cursor.execute("call p2()")调用有参数存储过程:cursor.callproc('p1', args=(1, 22, 3, 4))class pymysql.cursors.Cursor(connection)  # 游标结果做为元祖的元祖返回说明:这是您用于与数据库交互的对象。不要本身建立Cursor实例。调用connections.Connection.cursor()class pymysql.cursors.SSCursor(connection)  # 无缓冲游标结果做为元祖的元祖返回,用途:用于返回大量数据查询,或慢速网络链接到远程服务器不将每行数据复制到缓冲区,根据须要获取行。客户端内存使用少在慢速网络上或结果集很是大时行返回速度快限制:MySQL协议不支持返回总行数,判断有多少行惟一方法是迭代返回的每一行。目前没法向后滚动,由于只有当前行保存在内存中。class pymysql.cursors.DictCursor(connection)  # 将结果做为字典返回游标class pymysql.cursors.SSDictCursor(connection)  # 无缓冲游标结果做为字典返回游标属性:cursor.max_stmt_length  # 1024000cursor.rownumber  # 5 #当前结果集中游标所在行的索引(起始行号为 0)cursor.arraysize  # 1 #此读/写属性指定用.fetchmany()一次获取的行数。# 默认1表示一次获取一行;也能够用于执行.executemany()cursor.lastrowid  # None #只读属性提供上次修改行的rowid# DB仅在执行单个INSERT 操做时返回rowid 。# 如未设rowid或DB不支持rowid应将此属性设置为None# 如最后执行语句修改了多行,例如用INSERT和.executemany()时lastrowid语义是未定义cursor.rowcount  # 5 #最近一次 execute() 建立或影响的行数# 如无cursor.execute()或接口没法肯定最后一个操做的rowcount则该属性为-1# 该行数属性能够在动态更新其值的方式来编码。# 这对于仅在第一次调用.fetch()方法后返回可用rowcount值的 数据库很是有用。commit()方法:在数据库里增,删,改的时候。必需要进行提交,不然插入的时候数据不生效
相关文章
相关标签/搜索