I code it

Code and Life

Cx_oracle的一些使用技巧

工作中的数据库采用oracle。访问oracle数据库一般都采用cx_oracle包来完成,API很清晰,操作效率也比较高,而且oracle官方好像对cx_oracle也非常支持,提供了丰富的文档。这里讨论一些使用技巧,作为记录,可能对你也有用。

我最近用python写了一个小工具,这个工具根据客户端的请求查询数据库,并将结果集以json的方式返回。请求的格式如下:

   1: {
   2:     fields : [
   3:         {name : "project_id", type : "string"},
   4:         {name : "project_name", type : "string"}
   5:     ],
   6:     
   7:     sql : "select t.project_id, t.project_name from dp_project t"
   8: }

即,客户端描述自己想要的元数据信息(字段名称,字段类型),以及SQL语句,服务器端根据此信息查询数据库,并将返回组织成客户端在fields中描述的那样。

cx_oracle默认从cursor中fetch出来的数据是一个元组,按照SQL中的顺序组织,但是我希望返回的是一个字典结构,这个可以通过设置cursor的rowfactory属性来实现,定义一个rowfactory的回调函数

   1: def makedict(self, cursor):
   2:     cols = [d[0] for d in cursor.description]
   3:  
   4:     def createrow(*args):
   5:         return dict(zip(cols, args))
   6:  
   7:     return createrow

这个函数返回一个函数:createrow。可能有点绕口,仔细想想就清晰了。cursor中带有足够的信息来生成这个字典,如cursor的description的值为:

   1: [
   2: ('PROJECT_ID', <;type 'cx_Oracle.STRING'>, 40, 40, 0, 0, 0), 
   3: ('PROJECT_NAME', <;type 'cx_Oracle.STRING'>, 50, 50, 0, 0, 1)
   4: ]

我们需要的是cursor.description的第一列,zip函数将cols和默认的那个元组合成为一个新的元组,再用dict转换为一个新的字典对象返回。

然后将这个返回函数的函数注册给cursor的rowfactory即可:

   1: cursor.rowfactory = self.makedict(cursor)

这样,我们使用cursor.fetchall/fetchone的时候,取出来的就成为一个字典对象,很方便将其序列化为json格式返回。

另一个技巧是关于将查询到的结果中,字符串类型的字段转换为unicode,数值类型的不做处理:

   1: def outtypehandler(self, cursor, name, dtype, size, p, s):
   2:     if dtype in (oracle.STRING, oracle.FIXED_CHAR):
   3:         return cursor.var(unicode, size, cursor.arraysize)

将connection对象的outputtypehandler注册为此函数即可:

   1: connection = oracle.connect(self.constr)
   2: connection.outputtypehandler = self.outtypehandler

通用查询的这个小工具还在开发中,等完成了再整理一下。

Comments