数据在HDFS和关系型数据库之间的迁移,主要有以下两种方式

1、按照数据库要求的文件格式生成文件,然后由数据库提供的导入工具进行导入

2、采用JDBC的方式进行导入

MapReduce默认提供了DBInputFormat和DBOutputFormat,分别用于数据库的读取和数据库的写入

1、需求

下面使用DBOutputFormat,将MapReduce处理后的学生信息导入到mysql中

2、数据集

张明明    45
  李成友    78
  张辉灿    56
  王露      56
  陈东明    67
  陈果      31
  李华明    32
  张明东    12
  李明国    34
  陈道亮    35
  陈家勇    78     
  陈旻昊    13
  陈潘      78
  陈学澄    18

3、实现

package com.buaa;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException; import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.Writable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;
import org.apache.hadoop.mapreduce.lib.db.DBOutputFormat;
import org.apache.hadoop.mapreduce.lib.db.DBWritable;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner; /**
* @ProjectName DBOutputormatDemo
* @PackageName com.buaa
* @ClassName MysqlDBOutputormatDemo
* @Description TODO
* @Author 刘吉超
* @Date 2016-05-06 09:15:57
*/
@SuppressWarnings({ "unused", "deprecation" })
public class MysqlDBOutputormatDemo extends Configured implements Tool {
/**
* 实现DBWritable
*
* TblsWritable需要向mysql中写入数据
*/
public static class TblsWritable implements Writable, DBWritable {
String tbl_name;
int tbl_age; public TblsWritable() {
} public TblsWritable(String name, int age) {
this.tbl_name = name;
this.tbl_age = age;
} @Override
public void write(PreparedStatement statement) throws SQLException {
statement.setString(1, this.tbl_name);
statement.setInt(2, this.tbl_age);
} @Override
public void readFields(ResultSet resultSet) throws SQLException {
this.tbl_name = resultSet.getString(1);
this.tbl_age = resultSet.getInt(2);
} @Override
public void write(DataOutput out) throws IOException {
out.writeUTF(this.tbl_name);
out.writeInt(this.tbl_age);
} @Override
public void readFields(DataInput in) throws IOException {
this.tbl_name = in.readUTF();
this.tbl_age = in.readInt();
} public String toString() {
return new String(this.tbl_name + " " + this.tbl_age);
}
} public static class StudentMapper extends Mapper<LongWritable, Text, LongWritable, Text>{
@Override
protected void map(LongWritable key, Text value,Context context) throws IOException, InterruptedException {
context.write(key, value);
}
} public static class StudentReducer extends Reducer<LongWritable, Text, TblsWritable, TblsWritable> {
@Override
protected void reduce(LongWritable key, Iterable<Text> values,Context context) throws IOException, InterruptedException {
// values只有一个值,因为key没有相同的
StringBuilder value = new StringBuilder();
for(Text text : values){
value.append(text);
} String[] studentArr = value.toString().split("\t"); if(StringUtils.isNotBlank(studentArr[0])){
/*
* 姓名 年龄(中间以tab分割)
* 张明明 45
*/
String name = studentArr[0].trim(); int age = 0;
try{
age = Integer.parseInt(studentArr[1].trim());
}catch(NumberFormatException e){
} context.write(new TblsWritable(name, age), null);
}
}
} public static void main(String[] args) throws Exception {
// 数据输入路径和输出路径
String[] args0 = {
"hdfs://ljc:9000/buaa/student/student.txt"
};
int ec = ToolRunner.run(new Configuration(), new MysqlDBOutputormatDemo(), args0);
System.exit(ec);
} @Override
public int run(String[] arg0) throws Exception {
// 读取配置文件
Configuration conf = new Configuration(); DBConfiguration.configureDB(conf, "com.mysql.jdbc.Driver",
"jdbc:mysql://172.26.168.2:3306/test", "hadoop", "123"); // 新建一个任务
Job job = new Job(conf, "DBOutputormatDemo");
// 设置主类
job.setJarByClass(MysqlDBOutputormatDemo.class); // 输入路径
FileInputFormat.addInputPath(job, new Path(arg0[0])); // Mapper
job.setMapperClass(StudentMapper.class);
// Reducer
job.setReducerClass(StudentReducer.class); // mapper输出格式
job.setOutputKeyClass(LongWritable.class);
job.setOutputValueClass(Text.class); // 输入格式,默认就是TextInputFormat
// job.setInputFormatClass(TextInputFormat.class);
// 输出格式
job.setOutputFormatClass(DBOutputFormat.class); // 输出到哪些表、字段
DBOutputFormat.setOutput(job, "student", "name", "age"); // 添加mysql数据库jar
// job.addArchiveToClassPath(new Path("hdfs://ljc:9000/lib/mysql/mysql-connector-java-5.1.31.jar"));
// DistributedCache.addFileToClassPath(new Path("hdfs://ljc:9000/lib/mysql/mysql-connector-java-5.1.31.jar"), conf);
//提交任务
return job.waitForCompletion(true)?0:1;
}
}

mr程序很简单,只是读取文件内容,在这里我们主要关注的是怎么将mr处理后的结果集导入mysql中的

数据库中表是student,为student表编写对应的bean类TblsWritable,该类需要实现Writable接口和DBWritable接口。

1、Writable接口

@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(this.tbl_name);
out.writeInt(this.tbl_age);
} @Override
public void readFields(DataInput in) throws IOException {
this.tbl_name = in.readUTF();
this.tbl_age = in.readInt();
}

上面两个方法对应着Writable接口,用对象序列化,这里不再多说,前面文章有介绍

2、DBWritable接口

@Override
public void write(PreparedStatement statement) throws SQLException {
statement.setString(1, this.tbl_name);
statement.setInt(2, this.tbl_age);
} @Override
public void readFields(ResultSet resultSet) throws SQLException {
this.tbl_name = resultSet.getString(1);
this.tbl_age = resultSet.getInt(2);
}

上面两个方法对应着DBWriteable接口。readFields方法负责从结果集中读取数据库数据(注意ResultSet的下标是从1开始的),一次读取查询SQL中筛选的某一列。Write方法负责将数据写入到数据库,将每一行的每一列依次写入。

最后进行Job的一些配置,具体如下面代码所示

DBConfiguration.configureDB(conf, "com.mysql.jdbc.Driver", "jdbc:mysql://172.26.168.2:3306/test", "hadoop", "123")

上面的配置主要包括以下几项:

1、数据库驱动的名称:com.mysql.jdbc.Driver

2、数据库URL:jdbc:mysql://172.26.168.2:3306/test

3、用户名:hadoop

4、密码:123

还有以下几项需要配置

1、数据库表以及每列的名称:DBOutputFormat.setOutput(job, "student", "name", "age");

2、输出格式改为:job.setOutputFormatClass(DBOutputFormat.class);

需要提醒的是DBOutputFormat以MapReduce的方式运行,会并行的连接数据库。在这里需要合适的设置map、reduce的个数,以便将并行连接的数量控制在合理的范围之内

4、运行效果

5、注意事项

运行项目可能会报如下错误

解决方法:

共有3种解决方法,但我喜欢第三种

1、在每个节点下的${HADOOP_HOME}/lib下添加该包。重启集群,一般是比较原始的方法。

2、把jar包传到集群上,命令如下

hadoop fs -put mysql-connector-java-5.1.31.jar /lib/mysql

在mr程序提交job前,添加如下两个语句中一个就行

(1)DistributedCache.addFileToClassPath(new Path(“hdfs://ljc:9000/lib/mysql/mysql-connector-java-5.1.31.jar”), conf);

这条语句不推荐使用了,建议使用下面这条语句

(2)job.addArchiveToClassPath(new Path("hdfs://ljc:9000/lib/mysql/mysql-connector-java-5.1.31.jar"));

注意:用这种方式,在本地运行,依然报“java.io.IOException: com.mysql.jdbc.Driver”,但放到hadoop运行环境就可以啦

3、把依赖的jar打到项目中,然后配置MANIFEST.MF文件中Class-Path选项

具体配置,请参考“通过指定manifest.mf文件的打包

如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【刘超★ljc】。

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

实现代码及数据:下载

使用DBOutputFormat把MapReduce产生的结果集导入到mysql中的更多相关文章

  1. [MapReduce_add_1] Windows 下开发 MapReduce 程序部署到集群

    0. 说明  Windows 下开发 MapReduce 程序部署到集群 1. 前提 在本地开发的时候保证 resource 中包含以下配置文件,从集群的配置文件中拷贝 在 resource 中新建  ...

  2. 【原创】MapReduce程序如何在集群上执行

    首先了解下资源调度管理框架Yarn. Yarn的结构(如图): Resource Manager (rm)负责调度管理整个集群上的资源,而每一个计算节点上都会有一个Node Manager(nm)来负 ...

  3. mysql集群之MYSQL CLUSTER

    1. 参考文档 http://xuwensong.elastos.org/2014/01/13/ubuntu-%E4%B8%8Bmysql-cluster%E5%AE%89%E8%A3%85%E5%9 ...

  4. Oracle存储过程实现返回多个结果集 在构造函数方法中使用 dataset

    原文 Oracle存储过程实现返回多个结果集 在构造函数方法中使用 dataset DataSet相当你用的数据库: DataTable相当于你的表.一个 DataSet 可以包含多个 DataTab ...

  5. Hadoop集群搭建过程中ssh免密码登录(二)

    一.为什么设置ssh免密码登录 在集群中,Hadoop控制脚本依赖SSH来执行针对整个集群的操作.例如,某个脚本能够终止并重启集群中的所有守护进程.所以,需要安装SSH,但是,SSH远程登陆的时候,需 ...

  6. Spring整合Quartz定时任务 在集群、分布式系统中的应用(Mysql数据库环境)

    Spring整合Quartz定时任务 在集群.分布式系统中的应用(Mysql数据库环境)   转载:http://www.cnblogs.com/jiafuwei/p/6145280.html 单个Q ...

  7. hadoop集群搭建过程中遇到的问题

    在安装配置Hadoop集群的过程中遇到了很多问题,有些是配置导致的,有些是linux系统本身的问题造成的,现在总结如下. 1. hdfs namenode -format出现错误:hdfs namen ...

  8. Mysql中各种与字符编码集(character_set)有关的变量含义

    mysql涉及到各种字符集,在此做一个总结. 字符集的设置是通过环境变量来设置的,环境变量和linux中的环境变量是一个意思.mysql的环境变量分为两种:session和global.session ...

  9. 服网LNMP集群 w/ MySQL PaaS-1.0

    平台: arm 类型: ARM 模板 软件包: haproxy linux mysql nginx application server arm basic software fuwang infra ...

随机推荐

  1. PYTHON开发--面向对象基础入门

    面向对象 一:面向对象初级 1.思考:首先在python中,以前我们以前用到的几乎都是函数式编程,但是有时候函数式编程其中代码重复利用率太高,我们往往会把这些重复代码写进一个函数日后去调用,所以呢,今 ...

  2. android调试bug集锦 onActivityResult立即返回,并且被CANCEL

    症状: 在使用startActivityForResult调用照相机或者选择图片的时候,总是onActivityResult立马返回,resultCode=0 CANCEL. startActivit ...

  3. [译]36 Days of Web Testing(二)

    Day 7: Http 和 Https Why? 当在网络上传输一些私人,敏感信息时,应该采用加密的手段来保证这些信息在传输的过程中不被侦测到.Https协议正是这种实现机制. Https是一种广泛使 ...

  4. 我是如何学习NodeJs

    实际上在开始的时候我已经对NodeJS有了一定的了解. 比如我知道它是居于Javascript语言的服务器端web Server,比如我知道它的优势在于它的性能,而造成性能优异的原因在于高效的V8引擎 ...

  5. 2016 年开发者应该掌握的十个 Postgres 技巧

    [编者按]作为一款开源的对象-关系数据库,Postgres 一直得到许多开发者喜爱.近日,Postgres 正式发布了9.5版本,该版本进行了大量的修复和功能改进.而本文将分享10个 Postgres ...

  6. 能分析压缩的日志,且基于文件输入的PYTHON代码实现

    确实感觉长见识了. 希望能坚持,并有多的时间用来分析这些思路和模式. #!/usr/bin/python import sys import gzip import bz2 from optparse ...

  7. SqlTransaction的解析

    SqlTransaction的解析 2011-10-10 19:48 2757人阅读 评论(1) 收藏 举报 exceptionsql serverinsertcommandobjectstring ...

  8. Storm on Yarn 安装配置

    1.背景知识 在不修改Storm任何源代码的情况下,让Storm运行在YARN上,最简单的实现方法是将Storm的各个服务组件(包括Nimbus和Supervisor),作为单独的任务运行在YARN上 ...

  9. IEEE 802

    IEEE 802又称为LMSC(LAN /MAN Standards Committee, 局域网/城域网标准委员会), 致力于研究局域网和城域网的物理层和MAC层中定义的服务和协议, 对应OSI网络 ...

  10. bzoj1014

    动态询问LCP,所以我们不好用后缀数组考虑使用维护序列问题的splay+hash求LCP这里mark一下,hash求LCP常用mo=9875321自然溢出的话交上去莫名其妙WA了这里树上某节点hash ...