100%让你在10分钟内学会如何用Python将数据批量的插入到数据库

开发 后端 大数据
本文基于python, 使用pandas, pymysql等三方库实现了向数据库中高效批量插入数据,一方面提供被网上很多瞎转载的答案给坑蒙了的人(因为我也是),一方面自己也做个笔记,以后方便查阅

我是一名挣扎在编程链底端的pythoner,工作中既要和数据打交道,也要保持和erp系统,web网站友好的"沟通"···,我会时不时的分享下工作中遇到那点事,包括个人觉得值得记录的编程小技巧,还有就是遇到的问题以及解决方案,还有源码的阅读等等,可能也有编程中的生活感悟,不说了,我要去重构我的程序了

 

100%让你在10分钟内学会如何用python将数据批量的插入到数据库

本文基于python, 使用pandas, pymysql等三方库实现了向数据库中高效批量插入数据,一方面提供被网上很多瞎转载的答案给坑蒙了的人(因为我也是),一方面自己也做个笔记,以后方便查阅

需求原因

最近在处理一个需求,有关批量往数据库插入数据的,描述如下

  • 原来的程序是基于sql的存储过程进行数据的更新修改操作,由于数据量较大,导致对数据库压力太大,于是需要将程序重构为用python读取文件的方式将数据做计算处理,减少这部分的压力,最后仅仅将计算的结果调用aws的lambda服务重新更新到数据库中就可以了,减少了极大的压力,也降低了成本。涉及数据库主要是插入及更新操作

版本库信息

  • 基于linux系统写的
  • 三方库 >>> pandas 1.0.5, pymysql 0.9.3
  • python版本 >>> 3.7
  • 标准库 >> os

逻辑梳理

实际上,最后一步,要写入数据库的文件数据是存储在内存中的。因为读取文件后进行的计算都是在内存中进行的,那么计算的结果也没必要再写到本地,再去读取,再写入数据库,这是会影响程序的效率的。逻辑如下

  • 读取文件
  • 文件的拼接及计算,生成新的df
  • 初始化数据库的连接
  • 将df所需数据转换为元组数据(取决于数据库的三方库的接口是如何支持批量操作的)
  • 将数据写入数据库
  • 检查数据库内容即可

分步实现及分析

读取文件

给文件路径,然后去读文件就行了,强调一下需要注意的点

  • 绝对路径: 这种最简单,直接给路径字符串就行了,但是一旦文件夹目录结构变化,就需要频繁的改
  • 相对路径: 我一般喜欢先在脚本中定位当前脚本的位置,然后通过相对路径去找,这样只要你整个包内部的目录结构不变化,都不用改,就算部署上线也是直接根据包的位置来,很方便
  • pandas默认会将所有数字读取为float类型,所以对于那种看起来是数字,但实际上是需要当作字符串使用的字段进行类型的转换
  1. import pandas as pd  
  2. import numpy as np 
  3.  
  4. # 当前脚本的位置 
  5. current_folder_path = os.path.dirname(__file__) 
  6.  
  7. # 你的文件的位置 
  8. your_file_path1 = os.path.join(current_folder_path, "文件的名字1"
  9. your_file_path2 = os.path.join(current_folder_path, "文件的名字2"
  10.  
  11. # 我这里是以读取csv文件为例, delimiter为我们内部约定的列之间的分割符 
  12. df1 = pd.read_csv(your_file_path1, dtype={"column1": str, "column2": str}, delimiter="/t"
  13. df2 = pd.read_csv(your_file_path2, dtype={"column1": str, "column2": str}, delimiter="/t"

文件的拼接及计算

文件的拼接主要就是merge和concat两个语法的使用,强调一下小知识点

  • merge语法主要是对应于sql语言的内连接,外连接,左连接和右连接等
  • concat主要是用来将相同结构的df单纯的拼接起来(也就是列表的总行数增加)
  1. # 这里以左连接举例, 假设只有两个文件拼接 
  2. ret_df = pd.merge(df1, df2, left_on=["column_name"], right_on=["column_name"], how="left"

初始化连接

导入三方库pymysql,初始化连接

  1. # pymysql的接口获取链接 
  2. def mysql_conn(host, userpassword, db, port=3306, charset="utf8"): 
  3.   # 传参版本 
  4.   conn = pymysql.connect(host=host, user=userpassword=passworddatabase=db, port=port, charset=charset) 
  5.   return conn 

对应接口转换数据

  1. 数据插入要考虑写入一个事务,因为失败的话,要保证对数据库没有影响
  2. 构造符合对应接口的数据格式,通过查询,pymysql有两种可以执行语句的接口
  • execute(单条插入语句)
  • 执行单条语句的接口
  1. 类似这种: Insert into table_name (column) values (value);
  2. executemany(批量插入语句)
  • 执行多条语句的接口
  • 类似这种: Insert into table_name (column1, column2, column3) values (value1, value2, value3);

具体实现如下

  1. # 先创建cursor负责操作conn接口 
  2. conn = mysql_conn("your db host""your username""your password""db name"
  3. cursor = conn.cursor() 
  4. # 开启事务 
  5. conn.begin() 
  6.  
  7. #############      构造批量数据的过程            ############# 
  8.  
  9. # 先构造需要的或是和数据库相匹配的列 
  10. columns = list(df.columns) 
  11. # 可以删除不要的列或者数据库没有的列名 
  12. columns.remove("列名"
  13. # 重新构造df,用上面的columns,到这里你要保证你所有列都要准备往数据库写入了 
  14. new_df = df[columns].copy() 
  15.  
  16. # 构造符合sql语句的列,因为sql语句是带有逗号分隔的,(这个对应上面的sql语句的(column1, column2, column3)) 
  17. columns = ','.join(list(new_df.columns)) 
  18.  
  19. # 构造每个列对应的数据,对应于上面的((value1, value2, value3)) 
  20. data_list = [tuple(i) for i in gdsord_df.values] # 每个元组都是一条数据,根据df行数生成多少元组数据 
  21.  
  22. # 计算一行有多少value值需要用字符串占位 
  23. s_count = len(data_list[0]) * "%s," 
  24.  
  25. # 构造sql语句 
  26. insert_sql = "insert into " + "数据库表名" + " (" + columns + ") values (" + s_count[:-1] + ")" 

将数据写入数据库

这个简单,直接上代码

  1. cursor.executemany(insert_sql, data_list) 
  2. conn.commit() 
  3. cursor.close() 
  4. conn.close() 

检查数据库是否插入成功

如果没问题的话,就可以同时进行多个文件读写,计算,最后启用多线程同时向数据库中写入数据了,非常高效!

完整代码

  1. import pandas as pd  
  2. import numpy as np 
  3.  
  4.  
  5. # pymysql接口 
  6. def mysql_conn(host, userpassword, db, port=3306, charset="utf8"): 
  7.   conn = pymysql.connect(host=host, user=userpassword=passworddatabase=db, port=port, charset=charset) 
  8.   return conn 
  9.  
  10.  
  11. # 当前脚本的位置 
  12. current_folder_path = os.path.dirname(__file__) 
  13.  
  14. # 你的文件的位置 
  15. your_file_path1 = os.path.join(current_folder_path, "文件的名字1"
  16. your_file_path2 = os.path.join(current_folder_path, "文件的名字2"
  17.  
  18. # 我这里是以读取csv文件为例, delimiter为我们内部约定的列之间的分割符 
  19. df1 = pd.read_csv(your_file_path1, dtype={"column1": str, "column2": str}, delimiter="/t"
  20. df2 = pd.read_csv(your_file_path2, dtype={"column1": str, "column2": str}, delimiter="/t"
  21. # 合并 
  22. ret_df = pd.merge(df1, df2, left_on=["column_name"], right_on=["column_name"], how="left"
  23.  
  24. # 先创建cursor负责操作conn接口 
  25. conn = mysql_conn("your db host""your username""your password""db name"
  26. cursor = conn.cursor() 
  27. # 开启事务 
  28. conn.begin() 
  29.  
  30. # 先构造需要的或是和数据库相匹配的列 
  31. columns = list(df.columns) 
  32. # 可以删除不要的列或者数据库没有的列名 
  33. columns.remove("列名"
  34. # 重新构造df,用上面的columns,到这里你要保证你所有列都要准备往数据库写入了 
  35. new_df = df[columns].copy() 
  36.  
  37. # 构造符合sql语句的列,因为sql语句是带有逗号分隔的,(这个对应上面的sql语句的(column1, column2, column3)) 
  38. columns = ','.join(list(new_df.columns)) 
  39.  
  40. # 构造每个列对应的数据,对应于上面的((value1, value2, value3)) 
  41. data_list = [tuple(i) for i in gdsord_df.values] # 每个元组都是一条数据,根据df行数生成多少元组数据 
  42.  
  43. # 计算一行有多少value值需要用字符串占位 
  44. s_count = len(data_list[0]) * "%s," 
  45.  
  46. # 构造sql语句 
  47. insert_sql = "insert into " + "数据库表名" + " (" + columns + ") values (" + s_count[:-1] + ")" 
  48. try: 
  49.   cursor.executemany(insert_sql, data_list) 
  50.   conn.commit() 
  51.   cursor.close() 
  52.   conn.close() 
  53. except Exception as e: 
  54.   # 万一失败了,要进行回滚操作 
  55.   conn.rollback() 
  56.   cursor.close() 
  57.   conn.close() 

 

责任编辑:未丽燕 来源: 今日头条
相关推荐

2009-11-20 17:06:49

Oracle数据库字符

2019-11-20 10:38:59

MySQLSQL数据库

2021-07-15 06:43:11

Bash调试脚本

2018-11-28 11:20:53

Python函数式编程编程语言

2011-08-04 18:00:47

SQLite数据库批量数据

2019-07-18 16:32:06

Python函数数据

2018-02-01 14:15:00

Python函数

2009-11-03 17:15:07

VB.NET开发Exc

2009-11-20 18:08:37

Oracle数据库

2020-05-22 10:20:27

Shiro架构字符串

2018-06-26 09:37:07

时序数据库FacebookNoSQL

2009-11-02 18:07:58

Oracle数据库

2020-05-26 10:42:31

数据库读写分离数据库架构

2023-04-15 20:33:35

图形数据库数据库

2020-07-21 07:42:29

数据库信息技术

2016-12-21 15:08:14

数据库垂直拆分

2024-12-04 16:12:31

2023-12-22 09:37:13

二分查找数组数据库

2021-07-19 15:33:27

编程Rust开发

2022-05-30 08:34:49

PythonSQL
点赞
收藏

51CTO技术栈公众号