pymysql的使用方法
什么是 PyMySQL?
PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。
PyMySQL 遵循 Python 数据库 API v2.0 规范,并包含了 pure-Python MySQL 客户端库。
PyMySQL 安装
在使用 PyMySQL 之前,我们需要确保 PyMySQL 已安装。
PyMySQL 下载地址:https://github.com/PyMySQL/PyMySQL。
如果还未安装,我们可以使用以下命令安装最新版的 PyMySQL:
$ pip3 install PyMySQL
如果你的系统不支持 pip 命令,可以使用以下方式安装:
1、使用 git 命令下载安装包安装(你也可以手动下载):
$ git clone https://github.com/PyMySQL/PyMySQL
$ cd PyMySQL/
$ python3 setup.py install
2、如果需要制定版本号,可以使用 curl 命令来安装:
$ # X.X 为 PyMySQL 的版本号
$ curl -L https://github.com/PyMySQL/PyMySQL/tarball/pymysql-X.X | tar xz
$ cd PyMySQL*
$ python3 setup.py install
$ # 现在你可以删除 PyMySQL* 目录
**注意:**请确保您有root权限来安装上述模块。
安装的过程中可能会出现"ImportError: No module named setuptools"的错误提示,意思是你没有安装setuptools,你可以访问https://pypi.python.org/pypi/setuptools 找到各个系统的安装方法。
Linux 系统安装实例:
$ wget https://bootstrap.pypa.io/ez_setup.py
$ python3 ez_setup.py
pymysql基础操作
数据库创建操作
import pymysql
# 打开数据库连接
db = pymysql.connect("localhost","master","123456","TESTDB")
# 使用 cursor() 方法创建一个游标对象
cursorcursor = db.cursor()
# 使用 execute() 方法执行 SQL,如果表存在则删除
cursor.execute("DROP TABLE IF EXISTS EMPLOYEE")
# 使用预处理语句创建表
sql = """CREATE TABLE EMPLOYEE (
FIRST_NAME CHAR(20) NOT NULL,
LAST_NAME CHAR(20),
AGE INT,
SEX CHAR(1),
INCOME FLOAT )"""
cursor.execute(sql)
# 关闭数据库连接
db.close()
数据库插入操作
import pymysql
# 打开数据库连接
db = pymysql.connect("localhost","user","123","TESTDB")
# 使用cursor()方法获取操作游标
cursor = db.cursor()
# SQL 插入语句
sql = """INSERT INTO EMPLOYEE(FIRST_NAME,
LAST_NAME, AGE, SEX, INCOME)
VALUES ('Mac', 'Mohan', 20, 'M', 2000)"""
try:
# 执行sql语句
cursor.execute(sql)
# 提交到数据库执行
db.commit()
except:
# 如果发生错误则回滚
db.rollback()
# 关闭数据库连接
db.close()
数据库查询操作
Python查询Mysql使用 fetchone() 方法获取单条数据, 使用fetchall() 方法获取多条数据。
-
fetchone(): 该方法获取下一个查询结果集。结果集是一个对象
-
fetchall(): 接收全部的返回结果行.
-
rowcount: 这是一个只读属性,并返回执行execute()方法后影响的行数
import pymysql # 打开数据库连接 db = pymysql.connect("localhost","user","123","TESTDB") # 使用cursor()方法获取操作游标 cursor = db.cursor() # SQL 查询语句 sql = "SELECT * FROM EMPLOYEE \ WHERE INCOME > %s" % (1000) try: # 执行SQL语句 cursor.execute(sql) # 获取所有记录列表 results = cursor.fetchall() for row in results: fname = row[0] lname = row[1] age = row[2] sex = row[3] income = row[4] # 打印结果 print("fname=%s,lname=%s,age=%s,sex=%s,income=%s" % \ (fname, lname, age, sex, income)) except: print("Error: unable to fetch data") # 关闭数据库连接 db.close()
数据库更新操作
import pymysql
# 打开数据库连接
db = pymysql.connect("localhost","user","123","TESTDB")
# 使用cursor()方法获取操作游标
cursor = db.cursor()
# SQL 更新语句
sql = "UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = '%c'" % ('M')
try:
# 执行SQL语句
cursor.execute(sql)
# 提交到数据库执行
db.commit()
except:
# 发生错误时回滚
db.rollback()
# 关闭数据库连接
db.close()
数据库删除操作
import pymysql
# 打开数据库连接
db = pymysql.connect("localhost","user","123","TESTDB")
# 使用cursor()方法获取操作游标
cursor = db.cursor()
# SQL 删除语句
sql = "DELETE FROM EMPLOYEE WHERE AGE > %s" % (20)
try:
# 执行SQL语句
cursor.execute(sql)
# 提交修改db.commit()
except:
# 发生错误时回滚
db.rollback()
# 关闭连接
db.close()
实例:
import pymysql
# 创建连接
# 需要传入一些参数:
# host mysql所在的主机名或者是域名或者是ip地址
# port mysql运行的端口号
# ps -aux | grep mysql 找到MySQL运行的进程号
# netstat -tnlp | grep mysql的进程号 找到MySQL的端口
# user 用户名
# passwd 密码
# db 指定要操作的数据库
conn = pymysql.connect(host='master', port=3306, user='root', passwd='123456',db='stu_test')
# 创建游标cursor
cur = conn.cursor()
# cur.execute("use stu_test") # 切换数据库
# 准备SQL语句
sql_str1 = '''
SELECT t1.sid
,t1.sname
,t2.score
from (
SELECT sid
,sname
from Student
where sid in (
select t1.sid
from (
SELECT sid
,score
from SC
where cid = '01'
) t1 left join (
SELECT sid
,score
from SC
where cid = '02'
) t2 on t1.sid = t2.sid
where t1.score > ifnull(t2.score,0)
)
) t1 left join SC t2 on t1.sid = t2.sid
'''
# 执行SQL语句
cur.execute(sql_str1)
# 如果有返回值 可以通过cursor进行获取
print(cur.fetchone()) # 获取一条数据
print('#' * 50)
print(cur.fetchall()) # 获取所有数据
print('#' * 50)
print(cur.fetchmany(10)) # 获取指定大小的数据数据
# 如果没有返回值,看后续自己处理
事务
1.事务的基本介绍
如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
-
操作:
1.开启事务:start transaction;
2.回滚:rollback;
3.提交:commit;
-
例子:
--建表 CREATE TABLE account( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(10), balance DOUBLE ); --插入数据 INSERT INTO account(NAME,balance) VALUES ('zhangsan',1000),('lisi',1000); SELECT * FROM account; -- 张三给李四转账500元 -- 0.开启事务 START TRANSACTION; -- 1.张三账户 -500 UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan'; -- 2.李四账户 + 500 UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi'; -- 出错了/没出错... -- 发现没有问题了,提交事务 COMMIT; -- 发现出问题了,回滚事务 ROLLBACK;
-
MySQL数据库中事务默认自动提交,事务提交的两种方式:
-
自动提交:
mysql就是自动提交的
例如:一条DML(增删改)语句会自动提交一次事务。
-
手动提交:
需要先开启事务,再提交
Oracle数据库默认是手动提交事务
-
-
修改事务的默认提交方式:
--查看事务的默认提交方式: SELECT @@autocommit; -- 1 代表自动提交 0 代表手动提交 --修改默认提交方式: SET @@autocommit = 0;
2.事务的四大特征ACID
-
原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
-
一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
-
隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
-
持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。
3.事务的隔离级别(了解)
多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
隔离级别:
-
Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
-
Repeatable read (可重复读)(默认):可避免脏读、不可重复读的发生。
-
Read committed (读已提交):可避免脏读的发生。
-
Read uncommitted (读未提交):最低级别,任何情况都无法保证。
注意:隔离级别从低到高到安全性越来越高,但是效率越来越低
查询数据库隔离级别:
select @@tx_isolation;
数据库设置隔离级别:
set global transaction isolation level 级别字符串;
存在问题:
-
1.脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下
update account set money=money + 100 where name=’B’; (此时A通知B) update account set money=money - 100 where name=’A’;
当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。
-
2.不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发生了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……
-
3.虚读(幻读)
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
executemany()方法批量插入数据
使用execute()插入
# 方法一
import pymysql
# 创建一个链接对象
conn = pymysql.connect(host='master',user='root',password='123456',port=3306,db='stu')
# 创建游标
cur = conn.cursor()
# insert sql
insert_sql = "nsert into student() values(1500001,'张三',22)"
cur.excute(insert_sql)
# 提交事务
conn.commit()
cur.close()
conn.close()
# 方法二
import pymysql
# 创建一个链接对象
conn = pymysql.connect(host='master',user='root',password='123456',port=3306,db='stu')
# 创建游标
cur = conn.cursor()
# 数据
id = 15222
age = 22
name = '李四'
insert_sql=f"insert into student() values({id},'{name}',{age})" ## 注意一定要有引号,此处引用时被自动省略了
cur.excute(insert_sql)
# 提交事务
conn.commit()
cur.close()
conn.close()
# 方法三
import pymysql
# 创建一个链接对象
conn = pymysql.connect(host='master',user='root',password='123456',port=3306,db='stu')
# 创建游标
cur = conn.cursor()
# 数据
id = 15222
age = 22
name = '李四'
insert_sql=f"insert into student() values(%d,'%s',%d)" % (id,name,age)## 注意一定要有引号,此处引用时被自动省略了
cur.excute(insert_sql)
# 提交事务
conn.commit()
cur.close()
conn.close()
使用executemany()批量插入
executemany()用法
在数据库连接后,使用cursor.excutemany(sql, list)执行批量插入,其中sql为数据库SQL语句,其中的变量可以写为%s;list为要插入数据库的元组列表,其中的元组元素依次与SQL语句中的%s对应。
注意: List中数据类型必须为Tuple元组 eg.[(0, 3132), (1, 1298), (2, 6543), (3, 4553) ……]
import pymysql
# 创建一个链接对象
conn = pymysql.connect(host='master', user='root', password='123456', port=3306, db='demo1')
# 创建游标
cur = conn.cursor()
# 数据
with open('./student.txt', 'r', encoding='utf-8') as fp:
line_list = fp.readlines()
print(line_list)
new_list = []
for info in line_list:
splits = info.split(",")
new_list.append((splits[0], splits[1], splits[2], splits[3])) ## 存到元组,在一个一个加入列表
insert_many = "insert into Student() values(%s,%s,%s,%s)"
cur.executemany(insert_many, new_list)
# 提交事务
conn.commit()
cur.close()
conn.close()