1.代码与含义解释
1.1 思路
Flink 获取数据流后,需要做数据过滤那么首先就要有一下几个步骤:
构建运行环境 接入数据流 链接数据库,写入数据
1.2 直接上代码
public static void main(String[] args) throws Exception {
// 构建执行环境
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(5);
env.enableCheckpointing(2000, CheckpointingMode.EXACTLY_ONCE);
// 读取文本数据 DataStreamSource 是数据源
DataStreamSource<String> visitinfos = env.readTextFile("TheFilePaths");
// Mysql JDBC 连接器
JdbcConnectionOptions jdbcConnectionOptions = new JdbcConnectionOptions.JdbcConnectionOptionsBuilder()
.withUrl("jdbc:mysql://localhost:3306/xxx")
.withDriverName("com.mysql.cj.jdbc.Driver")
.withUsername("username")
.withPassword("passwd")
.build();
SingleOutputStreamOperator<List<String>> results = visitinfos.flatMap(new FlatMapFunction<String, List<String>>() {
@Override
public void flatMap(String value, Collector<List<String>> out) throws Exception {
JSONObject jsonObject = JSON.parseObject(value);
List<String> result = new ArrayList<>();
for (String valuekey : jsonObject.keySet()) {
result.add((String) jsonObject.get(valuekey));
}
out.collect(result);
}
});
// 插入Mysql数据库
// results 是来自于那个数据流 本阶段采用的是SingleOutputStreamOperator<List<String>> results 的 list 也可以使用DataStream<String> visitinfos 但需要 解析visitinfos
results.addSink(
JdbcSink.sink(
"insert into visit_info " +
"(Column_name)\n" +
"values(values)",
new JdbcStatementBuilder<List<String>>() {
@Override
public void accept(PreparedStatement preparedStatement, List<String> strings) throws SQLException {
for (int i = 0; i < strings.size(); i++) {
preparedStatement.setString(i + 1, strings.get(i));
}
}
},
jdbcConnectionOptions
)
);
env.execute();
}
}
1.3 代码注释
1.首先还是构建 Flink 运行环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
2.获取数据源
DataStreamSource visit_info = env.readTextFile(" ThePath"); 此数据源可以是文本文档也可以是其他例如 端口或 Kafka 数据流,此处可以理解为数据流输入端
3.处理数据
SingleOutputStreamOperator<List> results = visitinfos.flatMap(new FlatMapFunction<String, List>() { @Override public void flatMap(String value, Collector<List> out) throws Exception { JSONObject jsonObject = JSON.parseObject(value); List result = new ArrayList<>(); for (String valuekey : jsonObject.keySet()) { result.add((String) jsonObject.get(valuekey)); } out.collect(result); } }); 4.创建JDBC 链接
JdbcConnectionOptions jdbcConnectionOptions = new JdbcConnectionOptions.JdbcConnectionOptionsBuilder() .withUrl("jdbc:mysql://localhost:3306/xxx") .withDriverName("com.mysql.cj.jdbc.Driver") .withUsername("username") .withPassword("password") .build(); 5.数据写入
results.addSink( JdbcSink.sink( "insert into visit_info " + "(column_names)\n" + "values(values)", new JdbcStatementBuilder<List>() { @Override public void accept(PreparedStatement preparedStatement, List strings) throws SQLException { for (int i = 0; i < strings.size(); i++) { preparedStatement.setString(i + 1, strings.get(i)); } } }, jdbcConnectionOptions ) ); 核心代码说明:
它使用了JdbcSink,一个通常与流式数据处理框架(如Apache Flink)中的数据库输出操作相关的组件。下面是对这段代码的逐行解释:
results.addSink( ... );
这一行是在一个叫做results的对象上调用addSink方法。这通常意味着你想为这个数据流添加一个输出(或“接收器”)以将数据发送到某个目的地,这里是一个数据库。 JdbcSink.sink( ... )
这是创建JdbcSink对象的方法调用。JdbcSink是一个能够将数据写入数据库的接收器。 "insert into visit_info " + "(column_names)\n" + "values(values)"
这是一个SQL插入语句的字符串,它将被用于向数据库中的visit_info表插入数据。这里column_names和values应该是占位符,实际使用时应该被实际的列名和值替换。 new JdbcStatementBuilder<List>() { ... }
这里创建了一个新的JdbcStatementBuilder对象。这个对象用于构建数据库操作语句,并将数据绑定到这些语句中。 @Override public void accept(PreparedStatement preparedStatement, List strings) throws SQLException { ... }
这是JdbcStatementBuilder接口的accept方法的实现。这个方法将接收一个PreparedStatement对象和一个字符串列表作为参数。 for (int i = 0; i < strings.size(); i++) { ... }
这是一个for循环,用于遍历传入的字符串列表。 preparedStatement.setString(i + 1, strings.get(i));
在循环内部,这一行代码将列表中的每个字符串值设置到PreparedStatement的对应参数位置。i + 1是因为PreparedStatement的参数索引是从1开始的。 }, jdbcConnectionOptions )
这部分代码关闭了JdbcStatementBuilder的匿名内部类定义,并传递jdbcConnectionOptions作为参数来配置JdbcSink的数据库连接选项。
2.思考
1.写入数据时数据表结构设计(数据模型)与数据流 如何动态匹配?
2.写入 Kafka 的话代码如何写?