MySQLdb
MySQLdb是一款较为底层的,python连接mysql用的模块。和更加高级的,提供ORM的模块不同,MySQLdb主要还是聚焦于如何和数据库进行连接和进行基本的操作,操作的体现形式主要还是进行SQL语句的执行。
■ 安装
在Linux下
pip install MySQL-python
如果安装之后仍不能正常运行,尝试用yum install MySQL-python,因为这个模块需要一些第三方程序来运行的。
如果是在windows环境下安装的话那么可以直接下载一个安装程序来安装已经编译好的模块。比如去【http://www.codegood.com/downloads】下载。
■ 基本使用
MySQLdb提供了connect方法来建立一个与数据库的连接,调用这个对象的close方法来关闭一个连接。通过这个连接可以创建出一个游标对象,通过游标对象来进行数据的增删查改。
import MySQLdb db = MySQLdb.connect(host='localhost',user='weiyz',passwd='123456',db='test_DB',charset='utf-8') cursor = db.cursor() #创建一个游标对象 cursor.excute("use test_table;show tables;") #执行SQL语句,注意这里不返回结果,只是执行而已 res = cursor.fetchall() #fetchall方法返回所有匹配的元组,给出一个大元组(每个元素还是一个元组) ####或者也可以这样#### res = cursor.fetchone() while res: print res res = cursor.fetchone() #fetchone只给出一条数据,然后游标后移。游标移动过最后一行数据后再fetch就得到None
db.close()
另外关于db这个连接对象,除了可以实例化一个游标对象之外,还可以进行commit(),rollback()等操作。
■ 游标对象的执行和返回数据
就像上面例子中提到的那样,cursor可以调用execute来执行一定的SQL语句,也可以fetchone或者fetchall来得到返回的数据。接下来详细看一下cursor的各个方法:
callproc(procname[,args]) 调用一个叫做procname的存储过程
close() 游标也有关闭方法,游标被关闭之后就不能再移动,更不能被fetch
execute(query[,args]) query是一个SQL串,args是一个序列或者映射,将依次为query中的变量赋值。关于query串中的变量设置下面会细讲。这个方法返回的值是影响的行数(比如查询SQL就返回查询到了多少行,增删SQL就返回增删了多少行)
executemany(query[,args]) 这个方法和execute是类似的,只不过它是重复好几次执行execute,args也是一个“相同长度序列的序列”,每一次执行都把一个序列中的项对应到query的变量中去。据说executemany在效率上比execute高出很多, 在批量插入、批量更新时可以考虑使用。需要注意的是,这个方法是一个整体,如果想要进行多次查询操作用这个方法的话往往只能得到最后一个参数约束到SQL中得到的结果集。
fetchone/fetchall() 获得一行/所有行结果
fetchmany([size]) size指出了我到底要获取多少行的数据,如果能够返回的行数小于要求的行数的话,就以少的为准。
nextset() 放弃所有结果集中结果直接跳到下个结果集(如果有的话)。如果没有更多结果集就返回None,否则返回True,接下来的fetch操作将会从新结果集返回数据了。所谓结果集,就是比如连着执行两条SQL语句的话,如果不调用nextset,那么fetch来fetch去总是只能得到第一个语句的结果内容,调用了这个之后就可以看到下一个语句执行结果的内容了。
rowcount 这个属性代表了上一次execute*方法得到结果的结果行数,如果是-1则代表了上一次返回结果没有结果集且行数无法确定。
● query字符串中的变量设置
query中可以设置变量来动态地生成一些SQL语句,从而使得操作更加灵活多变。query中的变量大多数时候用在查询操作里面,因为没有统一的格式规定,设定变量的方法有很多种形式。比如可以用?,格式化字符串,数字等等。下面统一用格式化字符串的形式来表示。
比如"select Sno,Sname from Student where Sno=%s"
“select * from Client where level > %d and gid = %s"
这些变量可以和execute*方法的args参数进行配合以具体化。对于execute方法而言,因为只执行一次SQL,所有它的args只需要一个元组(序列),元组各元素和SQL串中的变量一一对应。而对于executemany方法,args是一系列上面那样的元组组成的一个元组(序列),相当于以一个循环依次把大元组中的各个小元组约束进SQL执行。实例:
SQL = """ select * from Client where level > %d and gid = %s """ cursor.execute(SQL,(2,'10001')) #需要注意的是,如果只有一个变量,args不要写类似('10001')这样,因为这判是<type 'str'>而不是tuple,应该写('10001',) print cursor.fetchone() ##如果同样的SQL,用executemany来查询多个结果集的话 cursor.executemany(SQL,( (2,'10001'), (2,'10002'), (1,'10003'), ) ) #如此就相当于依次把2,10001;2,10002和1,10003约束给SQL在执行,但是从查询数据的角度来看,只能得到10003的数据,
#因为executemany是一口气执行完的,fetch只能fetch到最后一个数字。所以executemany比较适合用于写而不是读操作。
■ 事务操作
因为MySQLdb是比较底层的模块,对数据库的操作都基于最基本的SQL语句,所以也就无所谓细讲如何增删查改了(反正到头来都是调用SQL),不过对于事务,还是有必要提及。
事务是通过接口对于数据库做出操作的最基本操作单位,可以看成是一系列操作的集合。一个事务具有以下特性:
原子性,事务中的所有操作要么都做要么都不做。
一致性,事务可以把数据库从一个一致性状态转变成另一个一致性状态
永久性,事务对数据库做出的改变是永久的。
隔离性,事务不应该被其他并行运行的事务所影响,事务间彼此应该是独立的
基于以上对于事务的理解,可以如此利用事务的commit和rollback方法:
SQL = "DELETE FROM Client WHERE level < %d" db = MySQLdb.connect(xxxxx) cursor = db.cursor() try: cursor.execute(SQL,(2,)) db.commit() except Exception,e: db.rollback() finally: cursor.close() db.close()
对于支持事务的数据库, 在Python数据库编程中,当游标建立之时,就自动开始了一个隐形的数据库事务。commit()方法游标的所有更新操作,rollback()方法回滚当前游标的所有操作。
■ 积累
● 关于使用MySQLdb获取到的数据的类型不符合预期的问题
今天碰到了一个问题。从数据库中通过MySQLdb获取到了一些数据是诸如这样的((u'01',8L,Decimal(900.00)),)。可以看到MySQLdb取数据的时候对于相应的MySQL中的数据类型会被转换成类似的Python中的类型。但是有时候我们不想要那么repr地表示,比如这一行数据我就只想让它是'01',8,900.0这些比较基本的Python中的类型而不是unicode,long,float这些。
一种办法是在取得数据之后进行一些数据的清洗。找到的另一种办法是将建立连接时的convertor改变。
MySQLdb在建立和MySQL之间的连接的时候,会声明好数据库数据类型和Python数据类型的对应关系。这部分信息被维护在了MySQLdb.convertors.conversions这个字典里。重点关注这个字典的中间部分有一些类似于FIELD_TYPE.XXX: xxx的键值对。键值其实是一个常量,后者是Python中的一个类型。这个字典就是会在MySQLdb.connect方法被执行时作为一个参数传递进来,并凭借里面的信息来对应类型的。
所以如果我们想把默认从数据库中取出来的Decimal换成float,8L换成int的8,就可以这么高:
from MySQLdb import convertors conv = convertors.conversions.copy() conv[246] = float # 246对应FIELD_TYPE.NEWDECIMAL,在convertors.py的代码中,如果from decimal import Decimal没有出错那么这个类型的数据最终返回Decimal,现在改成了float conv[3] = int conv[4] = int # 3和4分别对应Long和LongLong数据,都改成int了 conn = MySQLdb.connect(host='xxxx',user='xxx',passwd='xxx',db='xxx',charset='xxx',conv=conv) # 将参数conv设置为我们修改过的字典,之后再进行常规操作即可