Spark Streaming实现词频计算将结果保存到Mysql数据库(scala)

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)
  }
}

猜你喜欢

转载自blog.csdn.net/adayan_2015/article/details/88420285
今日推荐