flink sink 2 mysql demo
我们先看一个自定义sink 的demo,将 nc 的数据写入到mysql 中。
import myflink.learn.model.Student;
import myflink.learn.sink.SinkToMySQL;
import org.apache.flink.streaming.api.TimeCharacteristic;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author wtx
* @Date 2019/1/23
*/
public class Flink2MysqlDemo {
public static void main(String[] args) throws Exception {
AtomicInteger atomicInteger = new AtomicInteger(0);
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
env.setParallelism(1);
// 设置数据源
DataStream<String> text = env.socketTextStream("localhost", 9000, "\n");
// DataStream<Student> studentDataStream = text.map(new MapFunction<String, Student>() {
// @Override
// public Student map(String s) throws Exception {
// Student student = new Student();
// student.setName(s);
// student.setId(atomicInteger.addAndGet(1));
// return student;
// }
// });
DataStream<Student> studentDataStream = text.map((str) -> {
Student student = new Student();
student.setName(str);
student.setId(atomicInteger.addAndGet(1));
return student;
});
studentDataStream.addSink(new SinkToMySQL());
env.execute();
}
}
@Slf4j
public class SinkToMySQL extends RichSinkFunction<Student> {
PreparedStatement ps;
private Connection connection;
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
connection = getConnection();
String sql = "insert into student(id, name) values(?, ?);";
ps = this.connection.prepareStatement(sql);
}
@Override
public void close() throws Exception {
super.close();
//关闭连接和释放资源
if (connection != null) {
connection.close();
}
if (ps != null) {
ps.close();
}
}
@Override
public void invoke(Student value, Context context) throws Exception {
//组装数据,执行插入操作
ps.setInt(1, value.getId());
ps.setString(2, value.getName());
ps.executeUpdate();
}
private static Connection getConnection() {
Connection con = null;
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8", "root", "");
} catch (Exception e) {
log.error("exception e:", e);
}
return con;
}
}
RichSinkFunction 的类结构
可以看到自定义的sink 继承自RichSinkFunction. 来看 RichSinkFunction 的类结构
/**
* The base interface for all user-defined functions.
*
* <p>This interface is empty in order to allow extending interfaces to
* be SAM (single abstract method) interfaces that can be implemented via Java 8 lambdas.</p>
*/
@Public
public interface Function extends java.io.Serializable {
}
public interface SinkFunction<IN> extends Function, Serializable{
default void invoke(IN value, Context context) throws Exception {
invoke(value);
}
@Public
interface Context<T> {
long currentProcessingTime();
long currentWatermark();
Long timestamp();
}
}
在上面的 SinkFunction 接口中实际只有一个方法,invoke(),将类型为IN 的value 写入到sink 中。Context: 写入value 时的上下文
@Public
public abstract class AbstractRichFunction implements RichFunction, Serializable {
private transient RuntimeContext runtimeContext;
@Override
public void open(Configuration parameters) throws Exception {}
@Override
public void close() throws Exception {}
}
而在AbstractRichFunction 只有默认的生命周期方法 open() 和 close() 的空实现。 留给我们自己的比如上面的 SinkToMySQL那样 实现 对于mysql 的 open() close() 另外可以类似的实现对于redis 的sink 类。查看flink-connector-redis 发现已经有了RedisSink 类。
我们先来看看简单的使用:只需要将 new SinkToMySQL() -> new RedisSink
studentDataStream.addSink(new SinkToMySQL());
==>
FlinkJedisPoolConfig conf = new FlinkJedisPoolConfig.Builder().setHost("127.0.0.1").build();
studentDataStream.addSink(new RedisSink<Tuple2<String, Integer&g