热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Hadoop实战学习(3)-读取数据库内容

要读取数据库中的数据,首先需要实现一个实体类,这个实体类部分映射数据库中要查询的表的字段。且该实体类需要实现Writable与DBWritable两个接口,DBWri

          要读取数据库中的数据,首先需要实现一个实体类,这个实体类部分映射数据库中要查询的表的字段。且该实体类需要实

现Writable与DBWritable两个接口,DBWritable的实现类负责查询与写入,Writable的实现类负责序列化输出(到Mapper)与写入。

          可以将两个接口的实现都写入到一个类。

开发环境:mysql-5.7,Hadoop-2.7.3集群,Idea(Linux版),ubuntu。

开发测试都是在Linux环境下执行的。

SQL语句及数据准备:

CREATE DATABASE BigData DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

use BigData;

CREATE TABLE author (
    id int primary key auto_increment not null ,    
    name varchar(20) null,
    sex  char(1) null,  
    remark varchar(255) null
) DEFAULT CHARSET=utf8;

insert into author(name,sex,remark) values ('李三','0','Hello 李三');
insert into author(name,sex,remark) values ('李芳','1','Hello 李芳');
insert into author(name,sex,remark) values ('张燕','1','Hello 张燕');
insert into author(name,sex,remark) values ('王5','0','Hello 王5');
insert into author(name,sex,remark) values ('李四','0','How are you 李四');
insert into author(name,sex,remark) values ('李7','0','Hello 李7');

代码:

Writable及DBWritable接口实现类。

package com.readdb;

import org.apache.hadoop.io.Writable;
import org.apache.hadoop.mapreduce.lib.db.DBWritable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 该类在Mapper前执行
 */
public class MyDBWriteable implements DBWritable,Writable {

    private String name,sex,remark;

    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    /**     
     * 序列化输出对象字段,将查询结果作为mapper的输入
     * 即将查询结果写入到Mapper的输入数据
     * @param dataOutput
     * @throws IOException
     */
    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeInt(id);
        dataOutput.writeUTF(sex);
        dataOutput.writeUTF(name);
        dataOutput.writeUTF(remark);
    }

    /**         
     * 读取向数据库写入输入字段,读取数据时可以不实现该方法
     * @param dataInput
     * @throws IOException
     */
    public void readFields(DataInput dataInput) throws IOException {
        //id=dataInput.readInt();
        //sex=dataInput.readUTF();
        //name=dataInput.readUTF();
        //remark=dataInput.readUTF();
    }

    /**     
     * 向数据库写入数据,只读数据的话该方法可以不写
     * @param statement
     * @throws SQLException
     */
    public void write(PreparedStatement statement) throws SQLException {
        //写入顺序要与列顺序一致
        //statement.setInt(1,id);
        //statement.setString(2,name);
        //statement.setString(3,sex);
        //statement.setString(4,remark);
    }

    /**     
     * 读取查询结果集
     * @param resultSet
     * @throws SQLException
     */

    public void readFields(ResultSet resultSet) throws SQLException {
        id=resultSet.getInt(1);
        name=resultSet.getString(2);
        sex=resultSet.getString(3);
        remark=resultSet.getString(4);
    }
}

Mapper:

package com.readdb;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;
import java.util.StringTokenizer;

public class WCMapper extends Mapper {
    @Override
    protected void map(LongWritable key, MyDBWriteable value, Context context) throws IOException, InterruptedException {
        StringTokenizer stringTokenizer=new StringTokenizer(value.getRemark());
        while (stringTokenizer.hasMoreTokens()){
            context.write(new Text(stringTokenizer.nextToken()),new IntWritable(1));
        }
    }
}

Reducer:

package com.readdb;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

public class WCReducer extends Reducer {

    @Override
    protected void reduce(Text key, Iterable values, Context context) throws IOException, InterruptedException {
        int count=0;
        for (IntWritable intWritable:values){
            count+=intWritable.get();
        }
        context.write(key,new IntWritable(count));
    }
}

作业执行:

package com.readdb;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;
import org.apache.hadoop.mapreduce.lib.db.DBInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

import java.io.IOException;

public class HDFSDemo {

    public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException {
        Configuration cOnfiguration=new Configuration();
        //配置作业
        Job job=Job.getInstance(configuration,"readdb");
        String[] otherArgs = new GenericOptionsParser(configuration, args).getRemainingArgs();
        if (otherArgs.length != 1) {
            System.err.println("Usage: wordcount ");
            System.exit(2);
        }else {
            FileSystem.get(configuration).delete(new Path(otherArgs[0]));
        }
        //配置数据库信息
        String driverClass="com.mysql.jdbc.Driver";
        String url="jdbc:mysql://127.0.0.1:3306/BigData?useUnicode=true&characterEncoding=utf8&useSSL=false";
        String userName="root";
        String password="123456";
        String querySelect="select * from author";
        String queryCount="select count(*) from author";
        //配置数据库
        DBConfiguration.configureDB(job.getConfiguration(),driverClass,url,userName,password);
        //配置Mapper数据输入
        DBInputFormat.setInput(job,MyDBWriteable.class,querySelect,queryCount);
        //设置搜索类
        job.setJarByClass(HDFSDemo.class);
        //设置输入格式,TextInputFormat是默认输入格式,不能设置成FileInputFormat.Class,该惨数在当前情况下可以不设置
        job.setInputFormatClass(DBInputFormat.class);
        //设置Mapper类
        job.setMapperClass(WCMapper.class);
        //设置Reducer类
        job.setReducerClass(WCReducer.class);
        //设置Reducer个数
        //job.setNumReduceTasks(1);
        //设置maper端单词输出格式
        job.setMapOutputKeyClass(Text.class);
        //设置mapper端单词输出个数格式
        job.setMapOutputValueClass(IntWritable.class);
        //设置Reducer端单词输出格式
        job.setOutputKeyClass(Text.class);
        //设置Reducer单词输出个数格式
        job.setOutputValueClass(IntWritable.class);
        //设置job的输入路径,多次add可以设置多个输入路径
        //FileInputFormat.addInputPath(job,new Path(otherArgs[0]));
        //设置输出路径
        FileOutputFormat.setOutputPath(job,new Path(otherArgs[0]));
        System.exit(job.waitForCompletion(true) ? 0 : 1);
    }

}

然后点击Idea菜单栏的Run->Edit Configurations配置参数。

这里只需要配置输出目录。


然后编译运行。如果编译通过了,会在用户主目录下产生一个out目录。


然后执行命令:cat ~/out/* 查看输出结果。


可以看到,hadoop作业输出结果与mysql数据表中的数据完全符合。然后将代码打成jar包,在集群上运行。

打包之前,记得修改代码中的ip地址,我这里配置的是本机地址。改成内网ip后打包。


可以看到已经打成jar包了。然后将jar包移动到用户主目录下。


如果Idea所在的主机就是NameNode,当然也可以直接在IDea中执行jar包。

如果不是,还需要将jar包复制到NameNode上面。

允许jar包之前,还需要拷贝mysql的驱动(mysql-connector-java-5.1.38.jar)到各个节点的${HADOOP_HOME}/share/hadoop/common/lib目录下。也可以拷贝到${HADOOP_HOME}/share/hadoop/hdfs/lib目录下。

然后执行:hadoop jar readdb-core-1.0-SNAPSHOT.jar com.readdb.HDFSDemo /user/zhang/hadoop/out


然后查看输出结果:


可以看到输出结果和mysql表中的 数据一致。

常见问题解决:

1.提示驱动类找不到是因为没有加载mysql驱动jar包。

2.提示数据库找不到是因为ip地址配置错误,在执行jar包的时候,ip地址不能使用127.0.0.1;

3.无法连接到数据库,数据库访问被拒绝可以点此查看ubuntu无法访问mysql数据库

4.如果重复出现以下情况:


配置historyserver,执行:mr-jobhistory-daemon.sh start historyserver即可解决。

点此下载源代码

源代码下载完成后,先执行SQL语句,然后以导入maven工程的方式导入root目录下的pom.xml,只需要导入这一关pom.xml即可。



推荐阅读
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文讨论了在数据库打开和关闭状态下,重新命名或移动数据文件和日志文件的情况。针对性能和维护原因,需要将数据库文件移动到不同的磁盘上或重新分配到新的磁盘上的情况,以及在操作系统级别移动或重命名数据文件但未在数据库层进行重命名导致报错的情况。通过三个方面进行讨论。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • Linuxchmod目录权限命令图文详解在Linux文件系统模型中,每个文件都有一组9个权限位用来控制谁能够读写和执行该文件的内容。对于目录来说,执行位的作用是控制能否进入或者通过 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
  • 本文主要复习了数据库的一些知识点,包括环境变量设置、表之间的引用关系等。同时介绍了一些常用的数据库命令及其使用方法,如创建数据库、查看已存在的数据库、切换数据库、创建表等操作。通过本文的学习,可以加深对数据库的理解和应用能力。 ... [详细]
author-avatar
浪之音_544
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有