1.需求
任务需求:
- 从socket中获取数据,数据的每条类型为int,String,int,对应着每一位学生的id,姓名和年龄
- 将每条数据转成一个Student对象
- 自定义数据输出,输出到mysql中
2.代码实现
代码一共分为两部分:
- 第一部分是主程序,主要的作用是接受数据,将数据流转成student对象
- 第二部分是自定义DataSink,也就是最后调用的new SinkToMysql()
2.1 Student对象
public class Student {
private int id;
private String name;
private int age;
}
2.2 主程序
/**
* 从socket中获取数据 以对象的形式传入mysql
*/
public class JavaCustomDataSinkToMsql {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStreamSource<String> source = env.socketTextStream("localhost", 8888);
//数据处理 转为student对象
SingleOutputStreamOperator<Student> studentSource = source.map(new MapFunction<String, Student>() {
@Override
public Student map(String value) throws Exception {
String[] splits = value.split(",");
Student stu = new Student();
stu.setId(Integer.parseInt(splits[0]));
stu.setName(splits[1]);
stu.setAge(Integer.parseInt(splits[2]));
return stu;
}
});
//写入Mysql
studentSource.addSink(new SinkToMysql());
env.execute("JavaCustomDataSinkToMsql");
}
}
2.3 DataSink
/**
* 自定义dataSink 将数据存储在mysql中
* 继承RichSinkFunction 这个抽象类实现了RichFunction接口
*/
public class SinkToMysql extends RichSinkFunction<Student> {
Connection connection;
//PreparedStatement 是执行sql语句的API 具体看博客https://www.cnblogs.com/diegodu/p/8072387.html
PreparedStatement pstmt;
//获取数据库连接信息
private Connection getConnection(){
Connection conn = null;
try{
Class.forName("com.mysql.jdbc.Driver");//将mysql驱动注册到DriverManager中去
String url = "jdbc:mysql://localhost:3306/imooc_flink";//数据库路径
conn = DriverManager.getConnection(url,"root","123456");//数据库连接信息
}catch (Exception e){
e.printStackTrace();
}
return conn;
}
/**
* 在open方法中建立connection
* @param parameters
* @throws Exception
*/
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
connection = getConnection();
String sql = "insert into student(id,name,age) value(?,?,?)";
pstmt = connection.prepareStatement(sql);
}
//每条记录插入时调用一次
@Override
public void invoke(Student value, Context context) throws Exception {
//为前面的占位符赋值
pstmt.setInt(1,value.getId());
pstmt.setString(2,value.getName());
pstmt.setInt(3,value.getAge());
pstmt.executeUpdate();
}
/**
* 在close方法中要释放资源
* @throws Exception
*/
@Override
public void close() throws Exception {
super.close();
if(pstmt != null){
pstmt.close();
}
if (connection != null){
connection.close();
}
}
}
3. 代码讲解
3.1主程序
- 主程序其实很简单,无非就是首先获取执行环境,和数据流,本次实验是从本地的8888端口输入数据,如果不会操作的话下载一个netcat,上网搜一下怎么安装,打开端口命令 nc -l -p 8888
- 之后写一个map方法,将每条数据都转成一个student对象
- 最后调用addSink()方法,传入的参数是我们自定义的dataSink对象SinkToMysql(),将数据传入mysql
3.2 SinkToMysql详解
- 首先我们要知道自定义的dataSink是继承了RichSinkFunction<>类,这是一个泛型类,可以设定我们传入的数据类型,但是我们可以看到这个类其实实现的接口还是SinkFunction接口,对于这些接口的实现,我其实不是很懂,大家有兴趣可以去查一查
@Public
public abstract class RichSinkFunction<IN> extends AbstractRichFunction implements SinkFunction<IN> {
private static final long serialVersionUID = 1L;
}
- 之后在这个类中,我们要实现的方法一共有三个open,invoke,close。open方法其实就是做一些初始化的配置,invoke就是每次插入数据都执行一次,close是最后释放资源的方法
- getConnection()方法:这个方法其实最终就是返回我们的一个数据库连接信息,Class.forName方法就是获取数据库驱动自动加载到DriverManager中去,最后conn中存储的是我们要连接数据库所要的信息!
- open方法中首先调用super.open方法这个其实我不太明白,我推测应该是父类也有一些配置首先要进行!之后我们获取数据库连接,定义sql语句,用prepareStatement(sql)方法去对sql语句进行预编译处理,其实对于prepareStatement我也不是很清楚,有需求的话可以看下面这篇博客,讲的应该是挺清楚的!
https://www.cnblogs.com/diegodu/p/8072387.html - 之后实现的是invoke方法,这个方法就是每次插入都执行一次,我们可以看到传入的参数就是Student类型的value,后面的Context就是执行的上下文。我们可以看到我们之前写的sql语句是有三个问号的,也就是三个参数,所以后面的三个set就行进行三个参数的设置!最后调用pstmt.executeUpdate();执行sql语句。
- close方法其实就是释放资源的方法
来源:CSDN
作者:我是方小磊
链接:https://blog.csdn.net/weixin_44844089/article/details/104037534