Spark Streaming实现词频计算将结果保存到Mysql数据库(scala)实例。
1)建立Mysql连接池(MysqlPool.scala)
package com.fyy.spark.streaming
import java.sql.{Connection, DriverManager}
import java.util
/**
* @Title: MysqlPool
* @ProjectName SparkStreamingProject
* @Description: 创建MySQL连接池
* @author fanyanyan
*/
object MysqlPool {
private val max = 8 //连接池的连接总数
private val connectionNum = 10 //每次产生的连接数
private var conNum = 0 //当前连接池已经产生的连接数
private val pool = new util.LinkedList[Connection]() //连接池
{
Class.forName("com.mysql.jdbc.Driver")
}
/**
* 释放连接
* @param conn
*/
def closeConnect(conn: Connection) = {
pool.push(conn)
}
/**
* 获取连接
*/
def getConnect(): Connection = {
//同步代码块
AnyRef.synchronized({
if(pool.isEmpty){
for(i <- 1 to connectionNum){
val conn = DriverManager.getConnection("jdbc:mysql://01.server.bd:3306/streaming","root","123456")
pool.push(conn)
conNum + 1
}
}
pool.poll()
})
}
}
2)进行词频统计(ForeachRDDApp.scala)
package com.fyy.spark.streaming
import java.sql.DriverManager
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
/**
* @Title: ForeachRDDApp
* @ProjectName SparkStreamingProject
* @Description: 使用Spark Streaming完成词频统计,并将结果写入到MySQL数据库中
* @author fanyanyan
*/
/**
* 使用Spark Streaming完成词频统计,并将结果写入到MySQL数据库中
*/
object ForeachRDDApp {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setAppName("ForeachRDDApp").setMaster("local[*]")
val ssc = new StreamingContext(sparkConf, Seconds(5))
// 如果使用了stateful的算子,必须要设置checkpoint,建议存放到hdfs的某个文件中
ssc.checkpoint("hdfs://01.server.bd:9000/user/hdfs/checkpoint/")
// 接收
val lines = ssc.socketTextStream("01.server.bd", 6666)
// 利用redeceByKey()按批次进行统计
val result = lines.flatMap(_.split(" ")).map((_,1))
val state = result.updateStateByKey[Int](updateFunction _)
/**
* 方法一:将结果写入到MySQL数据库中
*/
// state.foreachRDD(rdd => {
// rdd.foreachPartition(partitionOfRecords => {
// // 获取数据库连接
// val connection = createConnection()
// // 进行插入数据库操作
// partitionOfRecords.foreach(x => {
// // 如果存在历史记录,则删除历史记录然后插入,否则直接插入
// val sql = "replace into words(word, num) value (" +x._1 + "," + x._2 + ")"
// connection.createStatement().execute(sql)
// })
// })
// })
/**
* 方法二:将结果写入到MySQL数据库中(通过mysql连接池)
*/
state.foreachRDD(rdd => {
rdd.foreachPartition(partitionOfRecords => {
// 获取数据库持久化连接
val conn = MysqlPool.getConnect()
val statement = conn.createStatement()
// 处理好的数据进行入库(库名:streaming)操作
partitionOfRecords.foreach(x => {
// 如果存在历史记录,则删除历史记录然后插入,否则直接插入
val sql = "replace into streaming.words(word, num) value (" +x._1 + "," + x._2 + ")"
statement.execute(sql)
})
MysqlPool.closeConnect(conn)
})
})
ssc.start()
ssc.awaitTermination()
}
/**
* 创建mysql数据库连接(用于方法一)
* @return
*/
def createConnection() = {
Class.forName("com.mysql.jdbc.Driver")
DriverManager.getConnection("jdbc:mysql://01.server.bd:3306/streaming", "root", "123456")
}
/**
* 把当前的数据和历史数据进行累加
* @param currentValues 当前的值
* @param preValues 历史值
* @return
*/
def updateFunction(currentValues: Seq[Int], preValues: Option[Int]): Option[Int] = {
val current = currentValues.sum
val pre = preValues.getOrElse(0)
Some(current + pre)
}
}