Flink实现往mysql中存储数据

扶醉桌前 提交于 2020-01-19 12:50:41

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主程序

  1. 主程序其实很简单,无非就是首先获取执行环境,和数据流,本次实验是从本地的8888端口输入数据,如果不会操作的话下载一个netcat,上网搜一下怎么安装,打开端口命令 nc -l -p 8888
  2. 之后写一个map方法,将每条数据都转成一个student对象
  3. 最后调用addSink()方法,传入的参数是我们自定义的dataSink对象SinkToMysql(),将数据传入mysql

3.2 SinkToMysql详解

  1. 首先我们要知道自定义的dataSink是继承了RichSinkFunction<>类,这是一个泛型类,可以设定我们传入的数据类型,但是我们可以看到这个类其实实现的接口还是SinkFunction接口,对于这些接口的实现,我其实不是很懂,大家有兴趣可以去查一查
@Public
public abstract class RichSinkFunction<IN> extends AbstractRichFunction implements SinkFunction<IN> {

	private static final long serialVersionUID = 1L;
}
  1. 之后在这个类中,我们要实现的方法一共有三个open,invoke,close。open方法其实就是做一些初始化的配置,invoke就是每次插入数据都执行一次,close是最后释放资源的方法
  2. getConnection()方法:这个方法其实最终就是返回我们的一个数据库连接信息,Class.forName方法就是获取数据库驱动自动加载到DriverManager中去,最后conn中存储的是我们要连接数据库所要的信息!
  3. open方法中首先调用super.open方法这个其实我不太明白,我推测应该是父类也有一些配置首先要进行!之后我们获取数据库连接,定义sql语句,用prepareStatement(sql)方法去对sql语句进行预编译处理,其实对于prepareStatement我也不是很清楚,有需求的话可以看下面这篇博客,讲的应该是挺清楚的!
    https://www.cnblogs.com/diegodu/p/8072387.html
  4. 之后实现的是invoke方法,这个方法就是每次插入都执行一次,我们可以看到传入的参数就是Student类型的value,后面的Context就是执行的上下文。我们可以看到我们之前写的sql语句是有三个问号的,也就是三个参数,所以后面的三个set就行进行三个参数的设置!最后调用pstmt.executeUpdate();执行sql语句。
  5. close方法其实就是释放资源的方法
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!