1、其实使用Python连接Oracle数据库跟连接Mysql数据库差不多,整体流程以及方法都差不多。只是说在安装cx_Oracle过程中过程中可能会有点坑:特别是连接Oracle时,主要就是需要保证各个组件的版本一致:系统版本,python版本,oracle客户端的版本,cx_Oracle的版本
2、Python连接Oracle数据库依赖于第三方模块cx_Oracle:pip install cx_Oracle
简单的使用流程如下:
1、引用模块cx_Oracle
2、连接数据库
3、获取cursor
4、使用cursor进行各种操作
5、关闭cursor
6、关闭连接
使用Python连接到Oracle数据库共有三种方法:使用connect()函数连接到数据库,返回数据库的连接对象(连接对象的方法与pymysql连接对象的方法一致)
⑴用户名,密码和监听分开写:"用户名","密码","数据库IP:端口号/ServerName"。只需用到connect()方法
⑵用户名,密码和监听写在一起:用户名/密码@数据库IP:端口号/ServerName。只需用到connect()方法
⑶配置监听并连接:需要用到同时用到makedsn()和connect()方法,感觉不是经常用
例1:
import cx_Oracle #引用模块cx_Oracle
conn=cx_Oracle.connect('load/123456@localhost:8080/ora11g') #连接数据库
c=conn.cursor() #获取cursor
x=c.execute('select sysdate from dual') #使用cursor进行各种操作
x.fetchone()
c.close() #关闭cursor
conn.close() #关闭连接
注:
在连接过程中遇到的几个坑:
1、cx_Oracle.DatabaseError: DPI-1047: 64-bit Oracle Client library cannot be loaded....:这个问题的原因大概就是oracle客户端的驱动位数与python的位数不一致造成的
解决办法:
1、下载64位驱动地址:http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html
2、下载驱动压缩包后解压到任意文件夹下
3、将解压后的文件路径添加到环境变量:如path=C:\instantclient-basic-nt-11.2.0.2.0
4、然后设置Oracle的环境变量:Path:%ORACLE_HOME%\bin
5、把下载的文件解压,复制oci,oraocci11,oraociei11的3个DLL粘贴到你的PY目录的Libs/site-packages文件夹下面。
注:设置全部后,一定要重启Pycharm!!!不然会一直报错
2、查询数据中存在中文时,Python返回的中文显示为乱码
解决办法:在脚本前面增加以下代码
import os
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8' #或者
os.environ['NLS_LANG'] = 'AMERICAN_AMERICA.AL32UTF8'
1、目前在工作中用到的Oracle的场景是:使用Postman发送接口URL、Body等去请求数据库某个表中的数据,然后查看请求返回的数据是否与数据库中的数据一致。有时数据库中的字段少的话还好,手动对比就能对比完,但是特么有几个表中的字段有100多个,然后就没心思去对比了而且也容易对比错,所以自己就写了个脚本去对比
2、主要思路是:一方面将Postman的数据手动复制出来存到一个TXT或者Json文件中(Postman返回的是一个JSon型字符串)。另一方面通过脚本执行指定的SQL语句去查询数据库中的对应数据,然后将查询出来的数据以及其列名组成一个字典。把Postman返回的数据与查询出来的数据进行对比。对比方式为将返回数据中的键值拿出来,通过键名去找查询出来的数据的值,然后看两个值对不对
3、Postman返回的数据格式和数据库中的数据格式如下:通过下面数据对比,我们主要注意的是有几个地方需要我们去转化下
⑴返回数据的键名与数据库的列名不一致,通过对比可以发现:返回数据的键名就是数据列名中去掉"_"号,每个开头字母大写其余小写的
⑵数据库中的值一般有五种:数字、字符串、浮点数、日期、null(特别是null,这种数据类型在Python中什么都不是,既不是字符串也不是None,所以更需要单独转换)
#Postman返回的数据格式
{
"plegId": 11170260,
"ambFltid": "143564",
"plegFltno": "张三",
"plegShare": null,
"plegDate": "2019-12-25 09:39:21"
}
#数据库中的数据格式如下
{
"PLEG_ID" : 11170260,
"AMB_FLTID" : "143564",
"PLEG_FLTNO" : "张三",
"PLEG_SHARE" : null,
"PLEG_DATE" : "2019-12-25T01:39:21Z"
}
例2:
# -*- coding: utf-8 -*-
# @Time : 2019/11/26 0026 22:24
# @Author : 不怕猫的耗子A
import json
import datetime
import cx_Oracle
import os
def GetResonseData(filePath):
"""
作用:
1、根据指定路径获取存放Postman返回数据的文件并读取其中的数据
2、将返回数据中的键名进行处理:这里我想得办法是,把数据库的列名、返回数据的键名都转为小写,这样就好对比了
3、返回数据中的null我没有在脚本中处理,采用的是手动替换,实际也可以在脚本中处理
param filePath: 存放Postman返回数据的文件
return:返回处理了键名的字典
"""
responseDataDict = {}
with open(filePath, 'r', encoding='utf-8') as file:
responseData = json.loads(file.read())
for responseDataKey, responseDataValue in responseData.items():
responseDataDict[responseDataKey.lower()] = responseDataValue#将键名转为小写并重组为字典
return responseDataDict
def GetSelectData(sql):
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.AL32UTF8'
# 引用模块cx_Oracle
conn = cx_Oracle.connect('用户名/密码@数据库IP:端口号/ServerName') # 连接数据库
cursor = conn.cursor() # 创建游标
cursor.execute(sql) # 执行sql语句
selectData = cursor.fetchone() # 获取一条数据
#print(selectData)
# print(cursor.description)#获取列名
databaseColList = []
for i in cursor.description:
databaseColList.append("".join((i[0].split("_"))).lower())#对查询到的列名进行处理
# databaseColList = [i[0] for i in cursor.description]#这里注释了的用的列表生成式,作用跟上面一行才不多,感觉这样写好点
# databaseCol = []
# for n in databaseColList:
# databaseCol.append(("".join(n.split("_")).lower()))
cursor.close() # 关闭游标
conn.close() # 关闭数据库连接
selectDataList = []
for i in selectData:
if type(i) == str or type(i) == int or type(i) == float:
selectDataList.append(i)
# else:
# try:
# i = i.strftime("%Y-%m-%d %H:%M:%S")
# selectDataList.append(i)
# except AttributeError:
# #查询的数据中有null值,如果进行strftime()操作时会触发AttributeError异常,所以可以加一个异常处理来强制把null加到列表中
# selectDataList.append("null")
elif type(i) == datetime.datetime:#值类型为datetime.datetime对象的话
i = i.strftime("%Y-%m-%d %H:%M:%S")
selectDataList.append(i)
else:
selectDataList.append("null")
selectDataDict = dict(zip(databaseColList, selectDataList))
return selectDataDict
def ResToSelect(responseDataDict,selectDataDict):
resToSelectResultSame = []
resToSelectResultDiff = []
resToSelectResult = []
for responseEachData in responseDataDict: # 返回的数据去对比数据库查询的数据
if responseEachData in selectDataDict:
if responseDataDict[responseEachData] == selectDataDict[responseEachData]:
resToSelectResultSame.append(responseEachData)
else:
resToSelectResultDiff.append(responseEachData)
else:
resToSelectResult.append(responseEachData)
print("返回的数据去对比数据库查询的数据,比较通过的有:", resToSelectResultSame)
print("返回的数据去对比数据库查询的数据,键都存在但值不一样的有:", resToSelectResultDiff)
print("返回的数据去对比数据库查询的数据,返回数据中有但数据库中没有的有:", resToSelectResult)
def SelectToRes(responseDataDict,selectDataDict):
selectToResResultSame = []
selectToResResultDiff = []
selectToResResult = []
for selectEachData in selectDataDict: # 数据库查询的数据去对比返回的数据
if selectEachData in responseDataDict:
if selectDataDict[selectEachData] == responseDataDict[selectEachData]:
selectToResResultSame.append(selectEachData)
else:
selectToResResultDiff.append(selectEachData)
else:
selectToResResult.append(selectEachData)
print("数据库查询的数据去对比返回的数据,比较通过的有:", selectToResResultSame)
print("数据库查询的数据去对比返回的数据,键都存在但值不一样的有:", selectToResResultDiff)
print("数据库查询的数据去对比返回的数据,返回数据中有但数据库中没有的有:", selectToResResult)
if __name__ == "__main__":
sql = "SELECT * FROM TEE WHERE PLEG_ID = ' 11170260'"
responseDataDict = GetResonseData("D:\\responseData.json")
print("返回的数据为:",responseDataDict)
selectDataDict = GetSelectData(sql)
print("查询的数据为:",selectDataDict)
ResToSelect(responseDataDict, selectDataDict)
SelectToRes(responseDataDict, selectDataDict)
注:
1、上面代码估计是一个人都看不怎么懂,没办法个人水平在这里,如果有幸看到,请不要嫌弃
2、在写这个脚本过程中,感觉难点还是对返回数据和查询数据的键名进行处理以及对查询数据的值进行处理(日期格式的值和null值)
3、对于键名的处理刚开始自己想了很多该怎么从一个键名去找另一个字典中对应的键名,什么正则表达式呀等等都想过(因为返回数据中有大写有小写)不过写着写着就突然想到,要不就两个数据的键名都统一转为小写或大写就好了
上面例子中有几个知识点,感觉可以补充下
1、Python读取TXT、JSON文件:两个差不多可以当成一个东西来处理
⑴在读取文件时,我们可能需要一行一行的读取出来:这种就可以对文件对象进行for循环遍历或者使用对应方法,如readline、readlines
⑵同时我们也可能需要一下就将整个文件都读出来,并且需要保证其格式(不是数据类型):此时就可以使用read()方法,read()方法如果没有参数的话,就是将文件中全部的内容一次性读出来
例3:
import json
#
# import json
#
# 从文件中读取json并转化为python数据
#
# path = "C:\\Py_Demo\\test.json"
#
# with open(path, 'r', encoding="utf-8") as file: # 在代码当前目录生成一个data.json的文件
# json_data = json.load(file)#读取出来时为字符串类型,所以需要转换
# print(json_data)
import json
file = open('C:\\Py_Demo\\test.txt', 'r', encoding="utf-8")
js = file.read()#读取出来时为字符串类型,所以需要转换
dic = json.loads(js)
print(dic)
file.close()
例4:
import pymysql
def dbConnect():
dbMysql = pymysql.connect(user="root", password="123456", host="localhost", database="demo", port=3306)
dbCursor = dbMysql.cursor()
SQL = "SELECT roleId,LEVEL,userId,funcelUUid,roleName FROM roleinfo WHERE roleId=5529676068169717607"
execute = dbCursor.execute(SQL)#可以将其返回值赋值给一个变量,不过一般都没有这么做
print(execute)#返回执行SQL语句后影响的行数,一般这个感觉没啥用
data = dbCursor.fetchone()#数据
col = dbCursor.description#列名
dbCursor.close()
dbMysql.close()
return data,col
if __name__ == "__main__":
data,col = dbConnect()
print(data)
print(col)
colList = [i[0] for i in col]
#上面使用的时列表生成式,作用跟下面三行注释的语句一样
# colList = []
# for i in col:
# colList.append(i[0])
print(colList)
print(dict(zip(colList,data)))#Zip()函数:将任意两个序列组合成字典
"""
1
(5529676068169717607, 107, 5529676068164933051, 'b74f7a67f0e8a0d0ecf6265e9a7ebc68', 'Sam_林')
(('roleId', 8, None, 8, 8, 0, False), ('LEVEL', 3, None, 4, 4, 0, False), ('userId', 8, None, 8, 8, 0, False), ('funcelUUid', 253, None, 512, 512, 0, False), ('roleName', 253, None, 256, 256, 0, False))
['roleId', 'LEVEL', 'userId', 'funcelUUid', 'roleName']
{'funcelUUid': 'b74f7a67f0e8a0d0ecf6265e9a7ebc68', 'LEVEL': 107, 'roleId': 5529676068169717607, 'userId': 5529676068164933051, 'roleName': 'Sam_林'}
"""
例5:
item1 = ["lowman", "isbusy"]
item2 = "123"
item3= ",".join(item1) # 根据实际需要使用相应的分隔符连接列表元素,如 , : ; 或者空字符串
print(item3)
print(type(item3))
print(item2.join(item3))
string = 'PLEG_CDM_LINEPOINT'
colNameString = ''
for i in string.split("_"):#split()方法返回的是一个列表
colNameString += i.capitalize()
print(colNameString)
colNameList = []
for i in string.split("_"):
colNameList.append(i.capitalize())#capitalize()首字母大写,其余小写
colNameString_1 = ''.join(colNameList)
print(colNameString_1)
"""
lowman,isbusy
l123o123w123m123a123n123,123i123s123b123u123s123y
PlegCdmLinepoint
PlegCdmLinepoint
"""
注:
1、Python将一个列表里面的元素拼接成一个字符串,列表里面的元素必须全是字符串才可以使用.join()进行拼接
2、返回的是一个字符串
3、join()方法主要用于:用一个字符串将另一个字符串中各元素连接起来,只是用于连接的字符串可以是符号。另外就是该方法还用于将列表中的字符串元素连接起来
有时候需要单独更新字典的键或值,因此可以使用下面的方法
例6:
s = {
"PLEG_ID" : 11170260,
"AMB_FLTID" : "143564",
"PLEG_FLTNO" : "张三",
"PLEG_SHARE" : "null",
"PLEG_DATE" : "2019-12-25T01:39:21Z"
}
dicta = {}
for i in s:
dicta[i.lower()] = s[i]#更新字典的键
print(dicta)
dictb = {}
count = 1
for n in s:
dictb[n] = count#更新字典的键
count += 1
print(dictb)
#利用字典的更新特性来计数或去重
l = [1,2,3,4,2,1,1]
dic = {}
count = 1
for i in l:
if i in dic:
#dic[i] += 1
dic[i] = dic[i] + 1
else:
dic[i] = count
print(dic)
"""
{'pleg_id': 11170260, 'pleg_fltno': '张三', 'amb_fltid': '143564', 'pleg_share': 'null', 'pleg_date': '2019-12-25T01:39:21Z'}
{'PLEG_SHARE': 1, 'PLEG_ID': 4, 'AMB_FLTID': 3, 'PLEG_FLTNO': 2, 'PLEG_DATE': 5}
{1: 3, 2: 2, 3: 1, 4: 1}
"""