Hive&HBase JDBC之抽象工厂模式

10 篇文章 0 订阅

抽象工厂模式的Hive和HBase连接

设计目的:通过将配置文件和Hive、HBase的执行代码全部写在xml文件内,然后直接一次性加载读取xml完成代码的执行

一、dwdom工程

1、新建dom4j工程

1.1 新建接口Dom
  • 定义初始化dom的init方法
  • 定义根据xpath获取元素信息的get方法
package cn.kgc.datawarehouse.dom.util;

public interface Dom {
    //接收外部xml文件路径,完成初始化
    void init(String path) throws Exception;//出异常就是失败,所以不需要返回值
    //键:字符串 //NodeName,拿到多个是list,拿到一个是Node,所以用泛型
    <T> T get(String key,String...subs);
}
1.2 新建类DomFactory
1.2.1 重写init方法
  • 文件读取check
  • 初始化reader、doc、root
1.2.2 重写get方法
  • 判断节点是否有attribute属性值,因为文件会根据属性值使用不同的方法执行其中的text命令
  • 重写get方法:把传入的参数拼接为xpath路径;根据xpath获取元素列表,分为【元素唯一无子节点、元素唯一有子节点、元素不唯一】三种情况
package cn.kgc.datawarehouse.dom.util;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

public abstract class DomFactory {
    //不给初始化
    public static Dom get() {
        return new Dom() {
            private SAXReader reader;
            private Document doc;
            private Element root;

            private File checkPath(String path) throws Exception {
                if (null == path) {
                    throw new NullPointerException(" dom xml null error");
                }
                File xml = new File(path);
                if (!xml.exists()) {
                    throw new FileNotFoundException(path + " not exist error");
                }
                if (!xml.isFile()) {
                    throw new Exception(path + " not file error");
                }
                if (!xml.getName().endsWith(".xml")) {
                    throw new Exception(path + " mot xml error");
                }
                if (!xml.canRead()) {
                    throw new Exception(path + " unreadable error");
                }
                return xml;
            }

            @Override
            public void init(String path) throws Exception {
                File xml = checkPath(path);
                reader = new SAXReader();
                doc = reader.read(xml);
                root = doc.getRootElement();
            }

            @Override
            public <T> T get(String key, String... subs) {
                StringBuilder builder = new StringBuilder("//");
                builder.append(key);
                for (String sub : subs) {
                    builder.append("/");
                    builder.append(sub);
                }
                //拼出来之后,检索元素集合
                List<Element> list = doc.selectNodes(builder.toString());
                if (null != list && list.size() > 0) {
                    int subSize = 0;
                    //如果只有一个元素
                    if (list.size() == 1) {
                        //如果检索元素唯一
                        Element el = list.get(0);
                        //获取唯一元素的子元素集合
                        list = el.elements();
                        if ((subSize = list.size()) == 0) {
                            //叶节点,没有子节点,提取文本
                            return ((T) el.getText());
                        }
                    }
                    //检索元素集合超过1,或检索元素唯一但存在子元素
                    if (list.size() > 1 || subSize > 0) {
                        List<String> lst = new ArrayList<>(list.size());
                        for (Element element : list) {
                            lst.add((element).getText());
                        }
                        return ((T) lst);
                    }
                }
                return null;
            }
        };
    }
}

2、打成jar包

MavenProject->Lifecycle->install的方式

二、dwjob工程

1、导入pom依赖

1.1 自定义的Dom依赖

除了常规的Hive、HBase、Hadoop、Log4j、集群管理repositories依赖之外,导入自定义的Dom依赖,如下:

    <!--myself - dom-->
    <dependency>
      <groupId>cn.kgc.datawarehouse.dom</groupId>
      <artifactId>dwdom</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
1.2 hadoop相关依赖

再打入其他hadoop相关jar包

<properties>
        <hadoop.version>2.6.0</hadoop.version>
        <hbase.version>1.2.0-cdh5.14.2</hbase.version>
        <hive.version>1.1.0</hive.version>
    </properties>
  <repositories>
    <repository>
      <id>cloudera</id>
      <url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
    </repository>
  </repositories>
	<dependencies>
<!-- hive-jdbc -->
        <dependency>
            <groupId>org.apache.hive</groupId>
            <artifactId>hive-jdbc</artifactId>
            <version>${hive.version}</version>
        </dependency>
        <!--hbase-->
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-client</artifactId>
            <version>${hbase.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-common</artifactId>
            <version>${hbase.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hbase</groupId>
            <artifactId>hbase-server</artifactId>
            <version>${hbase.version}</version>
        </dependency>
        <!-- hadoop-client,auth,common,hdfs,mapreduce -->
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-auth</artifactId>
            <version>${hadoop.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>jdk.tools</artifactId>
                    <groupId>jdk.tools</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>${hadoop.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>jdk.tools</artifactId>
                    <groupId>jdk.tools</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>${hadoop.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>jdk.tools</artifactId>
                    <groupId>jdk.tools</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>jdk.tools</artifactId>
                    <groupId>jdk.tools</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-mapreduce-client-core</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
    </dependencies>

2、Hive JDBC

2.1 新建接口Hive

定义执行方法execute,重载

  • 重载1:根据参数执行一条语句
  • 重载2:多条sql同时执行
package cn.kgc.dw.com.hive;

import cn.kgc.dw.com.DW;
import java.util.List;

public interface Hive extends DW {
    boolean execute(String sql,Object...params);
    boolean execute(List<String> sql);
}
2.2 新建类HiveFactory

设计思路:通过读取xml文件,返回接口Hive类型接口对象,然后重写并调用其中的方法。全程con只连接关闭一次

直接放代码,原理就是简单的JDBC

package cn.kgc.dw.com.hive;

import cn.kgc.datawarehouse.dom.util.Dom;
import org.apache.log4j.Logger;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

public class HiveFactory {
    public static Hive get(Dom dom) throws Exception {
        String driver = dom.get("driver");
        Class.forName(driver);
        String url = dom.get("url");
        String username = dom.get("username");
        String password = dom.get("password");
        return new Hive() {
            //引入log4j4j记录hive sql执行异常,导入日志
            private Logger logger = Logger.getLogger(Hive.class);

            private Connection getCon() throws SQLException {
                return DriverManager.getConnection(url,username,password);
            }
            private PreparedStatement getPst(Connection con ,String sql,Object...params) throws SQLException {
                PreparedStatement pst = con.prepareStatement(sql);
                for (int i = 0; i < params.length; i++) {
                    pst.setObject(i+1,params[i]);
                }
                return pst;
            }

            private boolean exe(Connection con,String sql, Object... params) {
                PreparedStatement pst = null;
                try {
                    pst = getPst(con,sql,params);
                    pst.execute();
                    //成功了也写进日志里
                    if (params.length>0){
                        sql +="PARAMS:"+ Arrays.toString(params);
                    }
                    logger.info("execute "+sql+" successfully");
                    return true;
                    //写一个接口进行资源释放
                } catch (SQLException e) {
//                    e.printStackTrace();
                    //把异常写到日志里,增加log4j
                    logger.error(e.getMessage());
                }finally {
                    close(pst);
                }
                return false;
            }

            @Override
            public boolean execute(String sql, Object... params) {
                Connection con = null;
                try {
                    con = getCon();
                    //成功了也写进日志里
                    return exe(con,sql,params);
                    //写一个接口进行资源释放
                } catch (SQLException e) {
//                    e.printStackTrace();
                    //把异常写到日志里,增加log4j
                    logger.error(e.getMessage());
                }finally {
                    close(con);
                }
                return false;
            }

            @Override
            public boolean execute(List<String> sql) {
                Connection con =null;
                try {
                    con = getCon();
                    for (String s : sql) {
                        if (!exe(con,s)){
                            return false;
                        }
                    }
                    return true;
                } catch (SQLException e) {
                    logger.error(e.getMessage());
                }finally {
                    close(con);
                }
                return false;
            }
        };
    }
}

3、HBase JDBC

3.1 新建HBase接口

一般来说,因为命令语句的不方便,在HBase中很少操作增删改查。因此本例接口中只写了建NS和Table的操作

package cn.kgc.dw.com.hbase;

import cn.kgc.dw.com.DW;
import java.util.List;

public interface HBase extends DW {
    boolean createNameSpace(List<String> names);
    boolean createTable(List<String> tables);
}
3.2 新建类HBaseFactory
  • HBase的设计思路和Hive的基本一样,只是HBase的配置信息需要传入一对的值,Hive只需要传入Value即可
  • 需要注意xml文件里的前后空格,可以通过trim方法消除

代码如下:

package cn.kgc.dw.com.hbase;

import cn.kgc.datawarehouse.dom.util.Dom;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.log4j.Logger;
import java.io.IOException;
import java.util.List;

public abstract class HBaseFactory {
    public static HBase get(Dom dom) {
        List<String> cnf = dom.get("hbase");//相当于 xpath="//hbase"
        Configuration config = new Configuration();
        for (String s : cnf) {
            String[] split = s.split("->");
            config.set(split[0], split[1]);
        }

        return new HBase() {
            private Logger logger = Logger.getLogger(HBase.class);

            private Connection getCon() throws IOException {
                return ConnectionFactory.createConnection(config);
            }

            @Override
            public boolean createNameSpace(List<String> names) {
                Connection con = null;
                Admin admin = null;
                try {
                    con = getCon();
                    admin = con.getAdmin();
                    for (String name : names) {
                        name = name.trim();
                        admin.createNamespace(NamespaceDescriptor.create(name).build());
                        logger.info("create namespace " + name + " succeed");
                    }
                    return true;
                } catch (IOException e) {
                    logger.error(e.getMessage());
                } finally {
                    close(admin, con);
                }
                return false;
            }

            @Override
            public boolean createTable(List<String> tables) {
                Connection con = null;
                Admin admin = null;
                try {
                    con = getCon();
                    admin = con.getAdmin();
                    for (String table : tables) {
                        table=table.trim();
                        String[] ps = table.split(",");
                        TableName tn = TableName.valueOf(ps[0]);
                        HTableDescriptor tbl = new HTableDescriptor(tn);
                        for (int i = 1; i < ps.length; i++) {
                            tbl.addFamily(new HColumnDescriptor(ps[i]));
                        }
                        admin.createTable(tbl);
                        logger.info("create tabe "+table+" succeed");
                    }
                    return true;
                } catch (IOException e) {
                    logger.error(e.getMessage());
                } finally {
                    close(admin, con);
                }
                return false;
            }
        };
    }
}

4、通用常量配置

4.1 新建接口DW

  • 添加常用字符串配置信息
  • Hive和HBase的关闭方法封装
package cn.kgc.dw.com;

public interface DW {
    String DW_LOG_DIR = "dw.log.dir";
    String LAYER = "layers";
    String TYPE_HQL="hql";
    String TYPE_HBASE_CREATE_NS="hbase->create->namespace";
    String TYPE_HBASE_CREATE_TABLE="hbase->create->table";

    default void close(AutoCloseable...closeables){
        for (AutoCloseable closeable : closeables) {
            if (null!=closeable) {
                try {
                    closeable.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

5、Job类

5.1 新建类DWJob
5.2 初始化
  • 初始化日志输出
  • 定义Hive、HBase、Dom对象
  • 初始化Hive、HBase、Dom对象、日志输出路径
5.3 对不同类型的执行语句进行区分
  • 定义一个键值存储的类Sqls,每个对象存储Type和该类型的所有sql语句
  • 定义一个方法parse循环读取一批叶子节点下的Hive、HBase命令,根据属性判断区分Hive、HBase。先new一个list;若第一个是Hive,则new一个Sqls对象并装进去;若第二个仍是Hive,add进去(Sqls类中封装了List的add方法);若第二个是HBase,把前一个Sqls对象add到list中,重新new一个Sqls对象;以此类推,直到这一批次所有命令都被add到list中,返回list
5.4 执行语句的方法
  • 先根据xpath获取所有批次(节点)
  • 对于每个批次(节点),获取其中的所有子节点,获取其中的内容(sql语句)并区分
  • 再次循环,使用switch case分类执行其中的语句
5.5 start启动方法
  • 初始化
  • 执行
  • 最后别忘了日志输出,防止出了问题无从检查

代码如下:

package cn.kgc.dw.com;

import cn.kgc.dw.com.hbase.HBase;
import cn.kgc.dw.com.hbase.HBaseFactory;
import cn.kgc.dw.com.hive.Hive;
import cn.kgc.dw.com.hive.HiveFactory;
import cn.kgc.datawarehouse.dom.util.Dom;
import cn.kgc.datawarehouse.dom.util.DomFactory;
import org.apache.log4j.Logger;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class DWJob {
    private static Logger logger = Logger.getLogger(DWJob.class);
    private Dom dom;
    private Hive hive;
    private HBase hBase;

    private void init(String xmlPath) throws Exception {
        dom = DomFactory.get();
        dom.init(xmlPath);
        System.setProperty(DW.DW_LOG_DIR, new File(xmlPath).getParentFile().getAbsolutePath());//拿到他上一级目录的绝对路径
        hive = HiveFactory.get(dom);
        hBase = HBaseFactory.get(dom);
    }

    class Sql {
        private String type;
        private List<String> sqls;

        Sql(String type) {
            this.type = type;
            sqls = new ArrayList<>();
        }

        public void add(String sql) {
            sqls.add(sql);
        }

        public String getType() {
            return type;
        }

        public List<String> getSqls() {
            return sqls;
        }
    }

    private String format(String sql){
        return sql.trim();
    }

    private List<Sql> parse(List<String> sqls){
        List<Sql> list = new ArrayList<>();
        Sql _sql = null;
        for (String sql : sqls) {
            String[] ps = sql.split(";");
            if (null == _sql) {
                _sql = new Sql(ps[0]);
                _sql.add(format(ps[1]));
            } else if(_sql.getType().equals(ps[0])) {
                _sql.add(format(ps[1]));
            } else {
                list.add(_sql);
                _sql = new Sql(ps[0]);
                _sql.add(format(ps[1]));
            }
        }
        list.add(_sql);
        return list;
    }

    private void exeJob() {
        List<String> layers = dom.get(DW.LAYER);
        for (String layer : layers) {//分层
            logger.info("-----------------------start job layer:"+layer+"---------------------");
            List<String> sqls = dom.get(layer);
            List<Sql> parse = parse(sqls);
            System.out.println("11111111111111");

            for (Sql sql : parse) {//层内分段
                switch (sql.getType()) {
                    case DW.TYPE_HQL:
                        hive.execute(sql.getSqls());
                        break;
                    case DW.TYPE_HBASE_CREATE_NS:
                        hBase.createNameSpace(sql.getSqls());
                        break;
                    case DW.TYPE_HBASE_CREATE_TABLE:
                        hBase.createTable(sql.getSqls());
                        break;
                }
            }
        }
    }

    public void start(String xmlPath) {
        long time = new Date().getTime();
        try {
            init(xmlPath);
            logger.info("[ start dw_job_"+time+"]");
            System.out.println("111");
            exeJob();
            logger.info("[ end dw_job_"+time+"]");
        } catch (Exception e) {
            logger.error("[ error dw_job_"+time+"]"+e.getMessage());
        }
    }
}

6、执行

ToolBar->Run->Edit Configuration->左上角±>Application->Name写主类名->Main class写主类路径->Program arguments设置参数路径(本例为xml路径)

image-20210202015527768

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值