报错 :ClassNotFoundException: com.mysql.jdbc.Driver

需求描述:
hadoop需要动态加载个三方jar包(比如mysql JDBC 驱动包),是在MR结束后,使用hadoop 的filesystem系统读取HDFS文件,调用JDBC驱动类插入数据库,但是运行时报错找不到驱动类。
第一个方法:加到HADOOP_HOME/lib下不可行,集群需要重启(集群再用,队列有任务进行中)。
第二个方法:job2.addFileToClassPath(file)和DistributedCache.addFileToClassPath()
以及利用hadoop jar xx.jar -libjars $yourpath/mysql-connector-java-5.0.3-bin.jar <other args.....> 这种原理上是一样的,
这种方式加入了Mapreduce的classpath(最后是加载到了每个节点 map container 或reduce container的JVM的classpath中),MR结束后通过filesystem调用JDBC,是不可行的,我的代码在Diver类中调用,即客户端拿不到这个类。
第三个方法:所有依赖三方包和MR程序打包到一个jar中,打包完接近180MB。jar包太大了。
第四个方法:依赖的第三方jar打包到lib中,本次任务不需要的jar包可以全删掉 (这里注意:工程的jar和集群jar版本不一致可能导致冲突)。可以运行,导出的lib也小。
 
总结一下:
1.报错Diver类里缺少三方包,扔到lib下(不是鼠标拖进lib目录下,是打包打进去)
2.报错Map或Reduce缺少三方包,分发到集群即可;可以用上面第二个方法中的2个方法 (job.addFileToClassPath()这个方法好像只有hadoop 2.7版本以上才有)或者直接用-libjars $yourpath/your-jar.jar (一定要写在其他参数前面)把三方包分发到集群
 
other:
后来在网上搜了一下,发现可以直接使用hadoop的DBOutputFormat 和DBInputFormat类来直接对数据库进行操作。
Diver类中的设置项:
     conf.set(DBConfiguration.DRIVER_CLASS_PROPERTY,"com.mysql.jdbc.Driver");
conf.set(DBConfiguration.URL_PROPERTY,
"jdbc:mysql://x.x.x.x:3306/test");
conf.set(DBConfiguration.USERNAME_PROPERTY, "xxx");
conf.set(DBConfiguration.PASSWORD_PROPERTY, "xxxx"); //这三行代码是本机测试用的
// conf.set(DBConfiguration.URL_PROPERTY,
// "jdbc:mysql://localhost:3306/test");
// conf.set(DBConfiguration.PASSWORD_PROPERTY, "xxx");
Job job3 = Job.getInstance(conf,"step3:insertToMySqlDB");
job3.setJarByClass(ECMerchantMapReduceV2.class);
job3.setMapOutputKeyClass(DBOutputKey.class);
job3.setMapOutputValueClass(NullWritable.class);
job3.setMapperClass(ECMerchantThirdMap.class);
job3.setOutputFormatClass(DBOutputFormat.class);
job3.setNumReduceTasks(0);
job3.addFileToClassPath(new Path("/xxxx/mysql-connector-java-5.0.3-bin.jar"));
DBOutputFormat.setOutput(job3, "yourtablename", "column1","column2","column3","column4");
FileInputFormat.addInputPath(job3, new Path(otherArgs[3]));
if(!job3.waitForCompletion(true)) return ;
public static class DBOutputKey implements WritableComparable<DBOutputKey>,DBWritable {

        private String city = "";
private String ec="";
private String account="";
private Date date2=null;    
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
public DBOutputKey() { } public DBOutputKey(String city, String ec, String account, Date date2) {
super();
this.city = city;
this.ec = ec;
this.account = account;
this.date2 = date2;
} public void set(String city, String ec, String account, Date date2) {
this.city = city;
this.ec = ec;
this.account = account;
this.date2 = date2;
} @Override
public void readFields(DataInput in) throws IOException {
this.city = in.readUTF();
this.ec = in.readUTF();
this.account = in.readUTF();
try {
this.date2 = new Date(format.parse(in.readUTF()).getTime());
} catch (ParseException e) {
e.printStackTrace();
}
} @Override
public void write(DataOutput out) throws IOException {
out.writeUTF(city);
out.writeUTF(ec);
out.writeUTF(account);
out.writeUTF(date2.toString());
} @Override
public int compareTo(DBOutputKey other) {
if (this.city.compareTo(other.city) != 0) {
return this.city.compareTo(other.city);
} else if (!this.ec .equals(other.ec) ) {
return ec .compareTo(other.ec);
} else if (!this.account.equals(other.account)) {
return account.compareTo(other.account);
}else {
return 0;
}
} @Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
//下面这2个方法是DBWritable接口的方法
@Override
public void write(PreparedStatement statement) throws SQLException {
statement.setString(1, city);
statement.setString(2, ec);
statement.setString(3, account);
statement.setDate(4, date2);
} @Override
public void readFields(ResultSet resultSet) throws SQLException {
this.city=resultSet.getString(1);
this.ec=resultSet.getString(2);
this.account=resultSet.getString(3);
this.date2=resultSet.getDate(4);
}
}
注意:
1.DBOutputFormat写入数据库,是按照key输出的,没有value,key要实现WritableComparable和DBWritable接口;
2.数据库表字段有个为Sql.date类型private Date date2=null,readFields(DataInput in)和write(DataOutput out)输入输出流不支持Sql.Date类型,通过文中红色代码部分转换格式,即可使Hadoop序列化的时候支持sql.Date数据类型。
  
    public static class ECMerchantThirdMap extends Mapper<LongWritable, Text, DBOutputKey, NullWritable> {
DBOutputKey dbKey=new DBOutputKey();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String date;
@Override
protected void setup(Mapper<LongWritable, Text, DBOutputKey, NullWritable>.Context context)
throws IOException, InterruptedException {
date=context.getConfiguration().get("eradiusDate");
}
public void map(LongWritable ikey, Text ivalue, Context context) throws IOException, InterruptedException {
String[] strs = ivalue.toString().split("\\s+");
if(strs.length!=3) return; Date date2=null;
try {
date2 = new Date(format.parse(date).getTime());
} catch (ParseException e) {
e.printStackTrace();
}
dbKey.set(strs[0], strs[1], strs[2], date2);
context.write(dbKey, NullWritable.get());
} }

Map类直接输出key就可以,不需要reduce类,可以设置reduce数量为0;

在Diver类中job3.addFileToClassPath(new Path("/xxxx/mysql-connector-java-5.0.3-bin.jar"));
测试后发现JDBC驱动包在ECMerchantThirdMap这个类写数据到Mysql数据库时是可以调用的,
而通过job3.addFileToClassPath()方法添加JDBC驱动包,在客户端是无法调用的。
所以该方法是添加jar包到运行Map或Reduce的节点的Classpath中。

MapReduce 程序mysql JDBC驱动类找不到原因及学习hadoop写入数据到Mysql数据库的方法的更多相关文章

  1. MySQL JDBC驱动版本与MySQL数据库版本对应关系

    前言:前段时间发现在家使用和公司一样的mysql jdbc驱动版本发生了异常,原因:家里mysql数据库版本与公司不一致导致.查询了相关资料,发现mysql jdbc驱动版本与mysql数据库版本有一 ...

  2. mysql的驱动类com.mysql.jdbc.Driver过时了,需要用com.mysql.cj.jdbc.Driver代替

    springboot项目整合mybatis,配置文件如下: server: port: 8081 mybatis: config-location: classpath:mybatis/mybatis ...

  3. mysql——jdbc驱动下载&连接mysql例子

    mysql-connector-java-5.1.46.zip[解压后里面jar文件就是所需要的] https://dev.mysql.com/get/Downloads/Connector-J/my ...

  4. 一个MySQL JDBC驱动bug引起的血案

    1.1      问题背景 公司是做电商系统的,整个系统搭建在华为云上.系统设计的时候,考虑到后续的用户和订单数量比较大,需要使用一些大数据库的组件.关系型数据库这块,考虑到后续数据量的快速增长,不是 ...

  5. java web工程 数据库操作报驱动类找不到的错误

    这几天在进行数据库的操作,写好数据库操作类后,用测试类测试成功通过,但是部署到tomcat后,从页面访问就会报异常. 最后终于发现是tomcat使用了连接池的数据连接方式. 解决方法是把jdbc ja ...

  6. VMware 克隆linux后找不到eth0(学习hadoop,所以想快速搭建一个集群)

    发生情况:      由于在学习hadoop,所以想快速搭建一个集群出来.所以直接在windows操作系统上用VMware安装了CentOS操作系统,配置好hadoop开发环境后,采用克隆功能,直接克 ...

  7. mysql jdbc驱动与java 版本对应关系

    当使用某些密码套件时,Connector/J5.1需要JRE 1.8.x才能使用SSL/TLS连接到MySQL 5.6,5.7和8.0.

  8. MySQL JDBC驱动下载

    下载地址:https://pan.baidu.com/s/1VLNaV_rz2P1jMtYrjJydiQ

  9. windows各种程序中文显示乱码又找不到原因时

    我电脑上的各种程序,如xshell,Navicat for MySQL都不正常显示中文,该软件的编码,utf-8,gbk,gb2312来回切换好几回,没一次正常,最好解决办法如下       进入控制 ...

随机推荐

  1. Servlet的Listener介绍

    当Web应用在Web容器中运行时,Web应用内部会不断地发生各种事件:如Web应用被启动.Web应用被停止.用户session开始.用户session结束等.通常这些Web操作对开发者是透明的.但Se ...

  2. python 根据文件的编码格式读取文件

    因为各种文件的不同格式,导致导致文件打开失败,这时,我们可以先判断文件的编码吗格式,然后再根据文件的编码格式进行读取文件 举例:有一个data.txt文件,我们不知道它的编码格式,现在我们需要读取文件 ...

  3. Istio开启mtls请求503问题分析

    背景 为测试Istio流量管理,将两个服务sleep.flaskapp的两个版本v1.v2(部署文件见参考链接)部署到Istio环境中,通过sleep-v1向flaskapp发起调用http://fl ...

  4. 中文情感分析——snownlp类库 源码注释及使用

    最近发现了snownlp这个库,这个类库是专门针对中文文本进行文本挖掘的. 主要功能: 中文分词(Character-Based Generative Model) 词性标注(TnT 3-gram 隐 ...

  5. 【linux】查看linux系统自带的服务启动文件

    =============================================================== 1.查看所有启动文件 systemctl list-unit-files ...

  6. [转] Performance_js中计算网站性能监控利器

    1.Performance方法 Performance提供的方法可以灵活使用,获取到页面加载等标记的耗时情况. performance.now() //返回当前到页面打开时刻的耗时,精确到千分之一毫秒 ...

  7. kafka源码导入idea/eclipse

    先进入源码工程:执行gradle idea或者gradle eclipse 之后再导入idea/eclipse

  8. Asp.Net Core中使用NLog记录日志

    2019/10/28, Asp.Net Core 3.0, NLog 4.6.7, NLog.Web.AspNetCore 4.9.0 摘要:NLog在asp.net网站中的使用,NLog日志写入数据 ...

  9. 经典SQL语句使用方法大全(自留用)

    一.基础 1.说明:创建数据库CREATE DATABASE database-name2.说明:删除数据库drop database dbname3.说明:备份sql server--- 创建 备份 ...

  10. K8S CoreDNS部署失败,发现的一个问题

    K8S CoreDNS部署失败,查看错误日志,提示如下 root >> kubectl get all --all-namespaces -o wide root >> kub ...