用spark在向关系型数据库写数据时,难免会遇到连接connection的问题。
如果把创建connection写到创建sparkcontext那里,这样是只会在driver端能用这个connection,在其他excutor是用不了的。
所以首先想到的是,RDD的操作是在每个excutor,那么就把创建connection放在RDD的操作里面,这样就能实现功能了。
但是如果用上面那个方法,就会担心,每来一批数据是不是都要创建一次连接,然后就会考虑用spark的广播变量,但是经过我的测试,广播变量无法广播connection,原因是connection无法被序列化,所以广播变量行不通,既然这个行不通,又不想每一批数据创建一个连接,这种情况怎么办呢。
最佳的一种方法就是在foreachpartition里面创建连接,这里创建的连接不会被重复创建,且可以一直使用。具体的原理是这样的,比如下方代码
a.foreachRDD(rdd => {
rdd.foreachPartition(x => {
val log: Logger = Logger.getLogger(this.getClass)
Class.forName(chDriver)
// val connection: Connection = DriverManager.getConnection(chUrl)
val connection: Connection = broadcast.value
println("=====================================================")
println(connection)
println("=====================================================")
x.foreach(data => {
..........
}
})
ps.executeBatch()
ps.close()
connection.close()
})
})
foreachpartition方法在每个机器就执行一次,所以可以在这里创建连接,再往里一层x.foreach才是对每一批可迭代数据的具体操作,循环执行