我尝试使用如下代码将Spark SQL Row值插入数据库:
final Broadcast<String> jdbcUrl = sc.broadcast(config.jdbcUrl());
df.foreachPartition((final Iterator<Row> it) -> {
final Sql2o sql2o = new Sql2o(jdbcUrl.value(), null, null, new NoQuirks());
try (final Connection conn = sql2o.beginTransaction()) {
final String sql = "INSERT INTO Table (Id, Value) VALUES (:id, :value)";
final Query query = conn.createQuery(sql, false);
int batchSize = 0;
while (it.hasNext()) {
final Row row = it.next();
query.addParameter("id", row.getLong(0))
.addParameter("value", row.get(1));
.addToBatch();
if (++batchSize == 1000) {
query.executeBatch();
conn.commit();
batchSize = 0;
}
}
query.executeBatch();
conn.commit();
}
});
我收到了主要密钥违规错误:
java.sql.BatchUpdateException:违反PRIMARY KEY约束 &#39; PK_Table&#39 ;.无法在对象&#39;表&#39;中插入重复键。该 重复键值为42。
我添加了一些调试日志代码,并且我验证了两个不同的执行程序试图插入相同的行(具有相同的id和值)。
在Spark SQL开始插入Row值之前,表是空的。另外,我在调用DataFrame上的distinct()
之前尝试拨打persist()
和foreachPartition()
,我仍然遇到了问题。
同一DataFrame的不同分区是否应该有单独的数据?不要分区的人总是保证吗?
修改
我在DataFrame上运行df.groupBy(df.col("id")).count().filter(col("count").gt(1)).show();
,并且没有ID分组到多个行的ID:
+--+-----+
|id|count|
+--+-----+
+--+-----+
从我可以看出,看起来在不同的执行器中同时迭代同一个分区。怎么样?
答案 0 :(得分:0)
也许,列索引是错误的; “id”不在0列中。更好:
userow.getAs[Long]("id")
而不是row.getLong(0)