StructuredStreaming自定义落地到JDBC

1.使用场景:

收集业务系统数据–>数据处理–>放入 OLTP 数据–>外部通过 ECharts 获取并处理数据

2.StructuredStreaming的落地问题:

在 Structured Streaming 中, 并未提供完整的 MySQL/JDBC 整合工具
不止 MySQL 和 JDBC, 可能会有其它的目标端需要写入
很多时候 Structured Streaming 需要对接一些第三方的系统, 例如阿里云的云存储, 亚马逊云的云存储等, 但是 Spark 无法对所有第三方都提供支持, 有时候需要自己编写

3.解决方式: foreach模式

既然无法满足所有的整合需求, StructuredStreaming 提供了 Foreach, 可以拿到每一个批次的数据
通过 Foreach 拿到数据后, 可以通过自定义写入方式, 从而将数据落地到其它的系统

4.代码实现

步骤:
创建类实现foreachWriter,实现三个方法
在writeStream中指定foreach(自定义类)

object foreach {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder().appName("hdfs").master("local[4]").getOrCreate()
    import spark.implicits._
    spark.sparkContext.setLogLevel("warn")

    //1.从kafka中读取数据
    val ds: Dataset[String] = spark.readStream
      .format("kafka")
      .option("kafka.bootstrap.servers", "node01:9092,node02:9092,node03:9092")
      .option("subscribe", "streaming_test_01")
      .load()
      .selectExpr("cast(value as String) as value")
      .as[String]

    //2.处理数据
    //数据格式: 1::叶凡::中洲
    val df: DataFrame = ds.map(item => {
      val arr = item.split("::")
      (arr(0).toInt, arr(1).toString, arr(2).toString)
    }).as[(Int, String, String)].toDF("id", "name", "address")

    **//3.自定义落地位置foreach--落地到MySQL中
    //3.1 自定义ForeachWriter
    class MySQLWriter extends ForeachWriter[Row]{
      var connection:Connection = _
      var statement: PreparedStatement = _
      val username = "root"
      val password = "123"
      //启动时调用的方法获取连接
      override def open(partitionId: Long, version: Long): Boolean = {
        Class.forName("com.jdbc.mysql.Driver")
        connection = DriverManager.getConnection("jdbc:mysql://node03:3306/test",username,password)
         //这里最好不要使用createStatement,如果原始数据中有单引号 ' ,在sql语句运行的时候会报错
        statement = connection.prepareStatement("insert into test01 values(?,?,?)")
        //返回true触发下面的方法执行
        true
      }
      //当open()返回true的时候调用
      override def process(value: Row): Unit = {
        val id: Int = value.getAs[String]("id").toInt
          val name = value.getAs[String]("name")
          val catogry = value.getAs[String]("catogry")
          statement.setInt(1,id)
          statement.setString(2,name)
          statement.setString(3,catogry)
          statement.execute()

      }
      //关闭的时候调用
      override def close(errorOrNull: Throwable): Unit = {
        statement.close()
        connection.close()
      }
    }**

    //启动写入
    df.writeStream
        .foreach(new MySQLWriter)
          .start()
            .awaitTermination()

  }
}

注意:
foreachWriter处理的数据是ROW类型,效率比较低
2.4版本的foreachBatch按批处理是一种更高效的模式

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值