pymysql

pymysql 是在py3和py2上都可以使用的连接 MySQL 服务器的一个库。

事务

事务机制可以确保数据一致性。
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。

  • 原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
  • 一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
  • 隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(durability)。持续性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
    Python DB API 2.0 的事务提供了两个方法 commit 或 rollback。

安装

首先查看了conda库中是否有这个包conda search pymysql,发现是有的并且有py2.7版本,直接安装conda install pymysql

cursor游标

游标就像一辆货车,把指令带过去执行(execute),然后运回来值(fetch*)。

fetch

  • fetchone(): 该方法获取下一个查询结果集。结果集是一个对象
  • fetchall(): 接收全部的返回结果行.
  • rowcount: 这是一个只读属性,并返回执行execute()方法后影响的行数。

使用

## 建立数据库连接
conn = pymysql.Connect(host='127.0.0.1',
							user='root',
							passwd='123456',
							db='python_mysql',
							charset='utf8')
# 使用 cursor() 方法创建一个游标对象 cursor
# 每一个游标对象传送一条sql
cursor = conn.cursor()
# 使用 execute()  方法执行 SQL 查询 
cursor.execute("SELECT VERSION()")
# 使用 fetchone() 方法获取单条数据.两个单词tetch one
# fetchall() 所有
conn.commit()
data = cursor.fetchone()
print ("Database version : %s " % data)
# 关闭数据库连接
db.close()

代码

转账:

# -*- coding: UTF-8 -*-
import sys
import pymysql

class TransferMoney(object):
	def __init__(self, conn):
		self.conn = conn

	def check_acct_available(self, acctid):
		cursor = self.conn.cursor()
		try:
			sql = "select * from account where acctid=%s" % acctid
			cursor.execute(sql)
			print "check_acct_available: " + sql
			rs = cursor.fetchall()
			if len(rs) !=1:
				raise Exception("账号%s不存在" % acctid)
		finally:
		#关闭cursor
			cursor.close()
	
	def has_enough_money(self, acctid, money):
		cursor = self.conn.cursor()
		try:
			sql = "select money from account where acctid=%s and money >= %s " % (acctid, money)
			cursor.execute(sql)
			print "has_enough_money: " + sql
			rs = cursor.fetchall()
			if len(rs) != 1:
				raise Exception("账号%s金额不足,剩余金额为%s"%(acctid, money))
		finally:
			cursor.close()

	def reduce_money(self, acctid, money):
		cursor = self.conn.cursor()
		try:
			sql = "update account set money = money - %s where acctid=%s"%(money, acctid)
			cursor.execute(sql)
			print "reduce_money: " + sql

			if cursor.rowcount !=1 :
				raise Exception("账号%s减款失败"%(acctid))
		finally:
			cursor.close()

	def add_money(self, acctid, money):
		cursor = self.conn.cursor()
		try:
			sql = "update account set money = money + %s where acctid=%s"%(money, acctid)
			cursor.execute(sql)
			print "add_money: " + sql

			if cursor.rowcount !=1 : #判断被影响的行数:cursor.rowcount
				raise Exception("账号%s加款失败"%(acctid))
		finally:
			cursor.close()


	def transfer(self, source_acctid, target_acctid, money):
		try:
			self.check_acct_available(source_acctid)
			self.check_acct_available(target_acctid)
			self.has_enough_money(source_acctid, money)
			self.reduce_money(source_acctid, money)
			self.add_money(target_acctid, money)
			# 向数据库提交,不开启自动提交
			self.conn.commit()
		except Exception as e:
		# 发生错误时回滚
			self.conn.rollback()
			raise e



if __name__ == "__main__":
	source_acctid = sys.argv[1]
	target_acctid = sys.argv[2]
	money = sys.argv[3]

	conn = pymysql.Connect(host='127.0.0.1',
							user='root',
							passwd='123456',
							db='python_mysql',
							charset='utf8'
							)
	tr_money = TransferMoney(conn)

	try:
		tr_money.transfer(source_acctid, target_acctid, money)
	except Exception as e:
		print "出现问题:" + str(e)
	finally:
	# 关闭连接
		conn.close()

引用

1. http://www.runoob.com/python3/python3-mysql.html
2. PyMySQL’s documentation
3. https://github.com/PyMySQL/PyMySQL
4. https://www.python.org/dev/peps/pep-0249/