如何通过Chapel向PostgreSQL批量插入数据?附CDO库报错案例
解决CDO库向PostgreSQL批量插入数据的问题
你已经搞定单条数据插入了,现在卡在批量插入是吧?我给你两种实用方案,都能解决这个问题:
方案一:使用executemany方法(推荐,安全高效)
大部分数据库驱动的游标都支持executemany方法,专门用来批量执行同一条SQL语句,处理多组参数。直接替换掉原来的循环就行,代码会简洁很多:
use Postgres, LinearAlgebra; const DB_HOST="localhost", DB_USER="buddha", DB_NAME="buddha", DB_PWD="buddha"; var q = "INSERT INTO r.condition_w (from_fid, to_fid, w) VALUES (%s, %s, %s);"; var con = PgConnectionFactory(host=DB_HOST, user=DB_USER, database=DB_NAME, passwd=DB_PWD); var cursor = con.cursor(); var e = ((1 ,4, 7.2), (3, 7, 22.8)); // 用executemany批量执行,无需手动循环 cursor.executemany(q, e); con.commit(); // 务必记得提交事务,否则数据不会真正写入数据库!
为什么优先选这个方案?
- 减少多次数据库交互的开销,性能比循环单条插入好很多
- 保留参数化查询的安全性,能有效避免SQL注入风险
- 代码更简洁,可读性更高
方案二:构造批量插入的SQL语句
如果因为某些限制没法用executemany,可以手动构造包含所有数据行的INSERT语句,一次性完成插入:
use Postgres, LinearAlgebra; const DB_HOST="localhost", DB_USER="buddha", DB_NAME="buddha", DB_PWD="buddha"; var con = PgConnectionFactory(host=DB_HOST, user=DB_USER, database=DB_NAME, passwd=DB_PWD); var cursor = con.cursor(); var e = ((1 ,4, 7.2), (3, 7, 22.8)); // 生成所有数据行的SQL片段,再拼接成完整语句 var value_clauses = [sprintf("(%s, %s, %s)", row[0], row[1], row[2]) for row in e]; var q = "INSERT INTO r.condition_w (from_fid, to_fid, w) VALUES " + join(", ", value_clauses); cursor.execute(q); con.commit();
注意事项
- 如果数据来自不可信来源,这种方法存在SQL注入风险,所以优先推荐方案一
- 当数据量极大时,要注意PostgreSQL对单条SQL语句长度的限制,避免超出阈值导致执行失败
关于你原有代码的小细节
你原来的循环代码执行失败,很大概率是因为没有提交事务!PostgreSQL默认开启事务,就算循环执行了INSERT,如果没调用con.commit(),所有操作都会在事务结束时回滚,数据库里根本看不到数据。哪怕是单条插入,没提交的话也只是在事务里临时存在,关闭连接后就消失了~
内容的提问来源于stack exchange,提问作者Brian Dolan
相关产品推荐
相关产品推荐

