【Flink读写外部系统】Flink自定义数据源函数_读取mysql

1 自定义的数据源函数_读取

1.1 应用场景:

  我将读取到的kafka的数据和mysql数据进行连接,此时就可以使用自定义的连接器;

1.2 自定义连接器实现

实现自定义的数据源函数读取,Flink为我们提供了两个方法:

  • SourceFunction通过实现RichSourceFunction来定义非并行的数据源连接器。
  • ParllelSourceFunction通过实现RichParalleSourceFunction来定义能并行的数据源连接器。

1.3 自定义连接器实现注意事项

在使用SourceFunction定义连接器的时候,在上述场景中是有个问题的。

  • 由于SourceFunction是非并行的数据连接器,使用kafka连接器如果是并行的话,会导致数据丢失。
  • 因为,假如Kafka数据源是3个并发程序,而SourceFunction数据源只有1个,那么它们在连接的时候比然会导致有2个线程中的数据是无法关联的,会导致数据丢失。

解决办法

  • 将SourceFunction变为ParllelSourceFunction连接器;
  • 同时定义一个全局的并行度: env.setParalllize()即可,又或者kafka连接器和ParllelSourceFunction都定义一个相同的并行度即可。

2 SourceFunction和ParallSourceFunction中定义了有两个方法

(分别是run()方法和cancel()方法)

2.1 Run()

  • Run只会被Flink调用一次,且Flink会专门为它而开放一个线程。该线程通常会不断的循环读取或接收数据,然后将他们发出。

2.2 Cancel()

  • Cancel会在应用被取消或关闭时调用。且为了关闭过程可以顺利完成,运行再单独线程内的run()方法需要在cancel()方法被调用会立即终止。

2.3 代码示例

class define_dataSource(number:Int) extends SourceFunction[Int]{
  var isRunning: Boolean = true
  override def run(ctx: SourceFunction.SourceContext[Int]): Unit = {
    var cnt = -1;
    while (isRunning && cnt < number){
      cnt +=1
      ctx.collect(cnt)
    }
  }
  override def cancel(): Unit = isRunning = false
}
object 自定义数据源函数  extends App {
  import org.apache.flink.streaming.api.scala.StreamExecutionEnvironment
  val streamLocal = StreamExecutionEnvironment.createLocalEnvironment(1)
  //获取集群的配置或提交客户端来指定默认并行度
  import org.apache.flink.api.scala._ //如果数据是有限的(静态数据集)可以引入这个包
  streamLocal.addSource(new define_dataSource(10)).map(x=>x).print()
  streamLocal.execute()
}

3 自定义函数读取Mysql数据源

  (注意在这这里实现的是RichSourceFunction而非SourceFunction,因为在RichSourceFunction中我们可以重写open方法)
Q:这里有个知识点,即为什么我们要实现open()方法?
A:因为open是富函数中的一个初始方法。它在每个任务首次调用转换方法(如map,flter等算子)前调用一次。open方法通常只用于那些只需要进行一次的设置工作

3.1 代码示例

class jdbc_reader extends RichSourceFunction[(String, Int)] {
  private var connect: Connection = _
  private var ps: PreparedStatement = _

  override def open(parameters: Configuration): Unit = {
    super.open(parameters)
    Class.forName("com.mysql.jdbc.Driver");
    connect = DriverManager.getConnection("jdbc:mysql://master:3306", "root", "msb_mk")
    ps = connect.prepareStatement("select * from friends.`ceshi`")
  }

  override def run(ctx: SourceFunction.SourceContext[(String, Int)]): Unit = {
    val result = ps.executeQuery()
    while (result.next()) {
      ctx.collect(result.getString("name"), result.getInt("age"))
    }
  }

  override def cancel(): Unit = {
    try {
      super.close()
      if (connect != null) connect.close()
      if (ps != null) ps.close()
    } catch {
      case e: Exception =>
        e.printStackTrace()
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值