因为医院的管理系统老旧落后,需要实现一些新功能,作为新上任的信息科工程师,正好拿来练练手。 新功能需要从数据库中读取数据,一开始我选择python。
连接数据库
从百度,到第一次连上数据库,我花了整整两天,可算找到一点门道。 其中走了一条很大的弯路
网上说连接数据库需要版本配合,这里的版本不需要考虑数据库服务端的版本。起码,新的cx_Oracle和最新的instantclient能够连接10g版本 起初为了考虑兼容10g服务端,我要用老版的cx_Oracle,老板的Python,老版的instantclient,一趟折腾下来,还总是异常。 我气的差点砸键盘,冷静半天后,我决定用其他的语言试试,于是挑了扔下很久的C#。结果…… 微软爸爸太牛逼了😭 只需要引用一个nuget包,直接搞定!!!包名貌似是:
Oracle.ManagedDataAccess.Client.Core
这个时候,我才意识到,根本不用执着于服务端的数据库版本。 因为种种原因,我最后回到了Python,因为动态语言就是香……
读取中文数据乱码
好不容易连上数据库,能够正常查询了,又遇到一个棘手的问题:中文乱码 起初,我以为是配置问题,python连接时不能设置解码器,于是尝试了C#和JS连接,都不能解决问题。 又是一番百度,我找到了数据库的语言设置,终于发现数据库建立时,用UTF
作为nvchar
的编码格式,但是实际保存的字节是用gbk
编码的,所以不管怎么设置NLS_LANG,要么连接错误,要么读取的中文都是乱码。 我一边骂当初的设计者傻X,一边打算投降了。😒
解决乱码
在B站上浪了一天,中二之力充满,我觉得自己又行了,灵机一动,想到一个办法:重新解码中文
实现这个目的,需要两步:
读取原始的字节序列
这点可以通过Oracle函数rawtohex(column_name)
实现
重新编码
这一步也不难,只需Python一行代码 bytes.fromhex(byte_str).decode('gbk')
最后,把两步合起来,组成一个对使用者透明的api
def query(query_table,query_fields:Union[list[str],str],decode_fields:list[str]=None,filters:str=None):
sql='select '
sql+='T.'+query_fields if isinstance(query_fields,str) else ','.join(query_fields)
for field in decode_fields:
sql+=f',rawtohex({field})'
sql+=f' from {query_table} T'
if filters:
sql+=' '+filters
print('Query:',sql)
with cx_Oracle.connect('user','pwd','ip/orcl') as connection:
with connection.cursor() as cursor:
cursor.execute(sql)
col_names=[col[0] for col in cursor.description]
rows=format_rows(col_names,cursor.fetchall())
if decode_fields:
for i in range(len(rows)):
row=rows[i]
keys=list(row.keys())
for key in keys:
if key.lower().startswith('raw'):
decode_str=decodegbk(row[key])
for field in decode_fields:
if field.lower() in key.lower():
row[field.upper()]=decode_str
del row[key]
break
return rows
今天的文章记Python连接Oracle数据库的各种问题分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/19754.html