之前对Storm集成JDBC写了一个简单的demo,最近深度研究了下,代码如下

首先,先写一个抽象类,便于减少代码的重复性:


import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.jdbc.common.Column;
import org.apache.storm.jdbc.common.ConnectionProvider;
import org.apache.storm.jdbc.common.HikariCPConnectionProvider;
import org.apache.storm.jdbc.common.JdbcClient;
import org.apache.storm.jdbc.mapper.JdbcLookupMapper;
import org.apache.storm.jdbc.mapper.JdbcMapper;
import org.apache.storm.jdbc.mapper.SimpleJdbcLookupMapper;
import org.apache.storm.jdbc.mapper.SimpleJdbcMapper;
import org.apache.storm.tuple.Fields; import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; /**
* @author cwc
* @date 2018年6月30日
* @description:这里创建一个抽象类,提高代码的重用性
* @version 1.0.0
*/
public abstract class AbstractUserTopology {
//sql语句 建标,建字段,自己灵活使用
private static final List<String> setupSqls = Lists.newArrayList(
"drop table if exists user",
"drop table if exists department",
"drop table if exists user_department",
"create table if not exists user (user_id integer, user_name varchar(100), dept_name varchar(100), create_date date)",
"create table if not exists department (dept_id integer, dept_name varchar(100))",
"create table if not exists user_department (user_id integer, dept_id integer)",
"insert into department values (1, 'R&D')",
"insert into department values (2, 'Finance')",
"insert into department values (3, 'HR')",
"insert into department values (4, 'Sales')",
"insert into user_department values (1, 1)",
"insert into user_department values (2, 2)",
"insert into user_department values (3, 3)",
"insert into user_department values (4, 4)"
); protected JdbcSpout jdbcSpout;//测试使用的spout
protected JdbcMapper jdbcMapper;//用于映射的Mapper
protected JdbcLookupMapper jdbcLookupMapper; //线程安全的 实现了ConnectionProvider接口 有三个方法 prepare(),getConnection() 获取连接,cleanUp(),接口采用直接赋值
protected ConnectionProvider connectionProvider; protected static final String TABLE_NAME = "storms";//表名
protected static final String JDBC_CONF = "jdbc.conf";//jdbc配置
protected static final String SELECT_QUERY = "select dept_name from department, user_department where department.dept_id = user_department.dept_id" +
" and user_department.user_id = ?";//查询sql语句 public void execute(String[] args) throws Exception {
//将配置放入map当中
Map map = Maps.newHashMap();
map.put("dataSourceClassName", "com.mysql.jdbc.jdbc2.optional.MysqlDataSource");
map.put("dataSource.url", "jdbc:mysql://localhost:3306/mytest?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai");
map.put("dataSource.user", "root");
map.put("dataSource.password", "密码"); Config config = new Config();
config.put(JDBC_CONF, map);//加载到配置中 ConnectionProvider connectionProvider = new HikariCPConnectionProvider(map);
//对数据库连接池进行初始化
connectionProvider.prepare();
//数据查找超时时间
int queryTimeoutSecs = 60;
//获得数据库连接
JdbcClient jdbcClient = new JdbcClient(connectionProvider, queryTimeoutSecs);
//创建表及字段
for (String sql : setupSqls) {
System.err.println("sql:" + sql);
//执行sql语句
jdbcClient.executeSql(sql);
} this.jdbcSpout = new JdbcSpout();
//通过connectionProvider和table自己去获取数据表的metadata(元数据)表字段的类型,名称,初始化schemaColumns
// 使用tableName进行插入数据,需要指定表中的所有字段
this.jdbcMapper = new SimpleJdbcMapper(TABLE_NAME, connectionProvider);
//关闭数据库连接池
connectionProvider.cleanup();
//上面的代码可以独立运行
Fields outputFields = new Fields("user_id", "user_name", "dept_name", "create_date");
//指定查询条件字段 user_id的值是spout中发射出user_id的值
List<Column> queryParamColumns = Lists.newArrayList(new Column("user_id", Types.INTEGER));
//通过查询为outputFields中的 dept_name赋值 其他三个字段是原始spout中的
this.jdbcLookupMapper = new SimpleJdbcLookupMapper(outputFields, queryParamColumns);
//拿到还未初始化的连接
this.connectionProvider = new HikariCPConnectionProvider(map);
String topoName = "test";
if (args.length == 0||args ==null) {
//当args为0,就本地使用
LocalCluster cluster = new LocalCluster();
cluster.submitTopology(topoName, config, getTopology());
Thread.sleep(1000000);//这个时为了防止你忘记关闭程序,造成内存爆炸,但是不要设置时间太小,太小程序没跑完就终止了,要报错。
cluster.shutdown();
} else {
StormSubmitter.submitTopology(args[4], config, getTopology());
}
} public abstract StormTopology getTopology();
}

接下来是普通的storm方法来写入数据:


import com.google.common.collect.Lists;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.jdbc.bolt.JdbcInsertBolt;
import org.apache.storm.jdbc.bolt.JdbcLookupBolt;
import org.apache.storm.jdbc.common.Column;
import org.apache.storm.jdbc.mapper.JdbcMapper;
import org.apache.storm.jdbc.mapper.SimpleJdbcMapper;
import org.apache.storm.topology.TopologyBuilder; import java.sql.Types;
import java.util.List;
/**
* @author cwc
* @date 2018年7月4日
* @version 2.0.0
* @description:将数据批量写入表中
*/
public class PersistanceTopology extends AbstractUserTopology {
private static final String USER_SPOUT = "USER_SPOUT";
private static final String LOOKUP_BOLT = "LOOKUP_BOLT";
private static final String PERSISTANCE_BOLT = "PERSISTANCE_BOLT"; public static void main(String[] args) throws Exception {
new PersistanceTopology().execute(args);//继承的方法,从而获得了连接
} @Override
public StormTopology getTopology() {
JdbcLookupBolt departmentLookupBolt = new JdbcLookupBolt(connectionProvider, SELECT_QUERY, this.jdbcLookupMapper); //获取映射字段
List<Column> schemaColumns = Lists.newArrayList(new Column("create_date", Types.DATE),
new Column("dept_name", Types.VARCHAR), new Column("user_id", Types.INTEGER), new Column("user_name", Types.VARCHAR));
JdbcMapper mapper = new SimpleJdbcMapper(schemaColumns);
//创建bolt
JdbcInsertBolt userPersistanceBolt = new JdbcInsertBolt(connectionProvider, mapper)
.withInsertQuery("insert into user (create_date, dept_name, user_id, user_name) values (?,?,?,?)"); TopologyBuilder builder = new TopologyBuilder(); builder.setSpout(USER_SPOUT, this.jdbcSpout, 1);
builder.setBolt(LOOKUP_BOLT, departmentLookupBolt, 1).shuffleGrouping(USER_SPOUT);
builder.setBolt(PERSISTANCE_BOLT, userPersistanceBolt, 1).shuffleGrouping(LOOKUP_BOLT);
return builder.createTopology();
}
}

使用Trident方法写入数据库:



import org.apache.storm.generated.StormTopology;
import org.apache.storm.tuple.Fields;
import com.google.common.collect.Lists;
import com.sunsheen.jfids.bigdata.storm.demo.count.TestSpout;
import com.sunsheen.jfids.bigdata.storm.demo.jdbc.AbstractUserTopology;
import com.sunsheen.jfids.bigdata.storm.demo.jdbc.JdbcSpout; import org.apache.storm.jdbc.common.Column;
import org.apache.storm.jdbc.mapper.SimpleJdbcLookupMapper;
import org.apache.storm.jdbc.trident.state.JdbcQuery;
import org.apache.storm.jdbc.trident.state.JdbcState;
import org.apache.storm.jdbc.trident.state.JdbcStateFactory;
import org.apache.storm.jdbc.trident.state.JdbcUpdater;
import org.apache.storm.trident.Stream;
import org.apache.storm.trident.TridentState;
import org.apache.storm.trident.TridentTopology; import java.sql.Types;
/**
* @author cwc
* @date 2018年7月4日
* @version 1.0.0
* @description:将数据通过Trident的方法写入数据库表中
*/
public class UserPersistanceTridentTopology extends AbstractUserTopology { public static void main(String[] args) throws Exception {
new UserPersistanceTridentTopology().execute(args);
} @Override
public StormTopology getTopology() {
TridentTopology topology = new TridentTopology();
//这里通过Trident的方式将数据写入数据库,代替了bolt等类的使用
JdbcState.Options options = new JdbcState.Options()
.withConnectionProvider(connectionProvider)
.withMapper(this.jdbcMapper)
.withJdbcLookupMapper(new SimpleJdbcLookupMapper(new Fields("dept_name"), Lists.newArrayList(new Column("user_id", Types.INTEGER))))
.withTableName(TABLE_NAME)
.withSelectQuery(SELECT_QUERY); JdbcStateFactory jdbcStateFactory = new JdbcStateFactory(options); Stream stream = topology.newStream("userSpout", new JdbcSpout());
TridentState state = topology.newStaticState(jdbcStateFactory);
stream = stream.stateQuery(state, new Fields("user_id","user_name","create_date"), new JdbcQuery(), new Fields("dept_name"));
stream.partitionPersist(jdbcStateFactory, new Fields("user_id","user_name","dept_name","create_date"), new JdbcUpdater(), new Fields());
return topology.build();
}
}

spout类:



import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values; import com.google.common.collect.Lists; import java.util.List;
import java.util.Map;
import java.util.Random;
/**
* @author cwc
* @date 2018年5月31日
* @description:存储数据的spout,我的读与写共用的这一个spout
* @version 1.0.0
*/
public class JdbcSpout extends BaseRichSpout {
private static final long serialVersionUID = 1L;
private SpoutOutputCollector collector;
//模拟数据
public static final List<Values> rows = Lists.newArrayList(
new Values(1,"peter",System.currentTimeMillis()),
new Values(2,"bob",System.currentTimeMillis()),
new Values(3,"alice",System.currentTimeMillis())); @Override
public void nextTuple() {
Random rand = new Random();
Values row = rows.get(rand.nextInt(rows.size() - 1));
this.collector.emit(row);
Thread.yield();
System.out.println("信息加载中---------------------");
} @Override
public void open(Map arg0, TopologyContext arg1, SpoutOutputCollector collector) {
this.collector =collector;
} @Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("user_id","user_name","create_date"));
} }

今天的代码就分享到这,各位共勉,努力、

Storm-jdbc-2讲 高级API及Trident的更多相关文章

  1. jdbc java数据库连接 2)jdbc接口核心的API

    JDBC接口核心的API java.sql.*   和  javax.sql.*(java2.0以后更新的扩展) |- Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接 ...

  2. UNET学习笔记2 - 高级API(HLAPI)

    高级API是在实时传输低级API基础上建立起来的,为多人游戏提供大量通用的组件.通过HLAPI开发者仅需少量的工作就可以搭建多人联网游戏. HLAPI 使用命名空间 UnityEngine.Netwo ...

  3. PJSUA2开发文档--第三章 PJSUA2高级API

    3. PJSUA2高级API PJSUA2是PJSUA API以上的面向对象抽象.它为构建会话发起协议(SIP)多媒体用户代理应用程序(也称为IP / VoIP软电话)提供高级API.它将信令,媒体和 ...

  4. Kafka技术内幕 读书笔记之(三) 生产者——消费者:高级API和低级API——基础知识

    1. 使用消费组实现消息队列的两种模式 分布式的消息系统Kafka支持多个生产者和多个消费者,生产者可以将消息发布到集群中不同节点的不同分区上:消费者也可以消费集群中多个节点的多个分区上的消息 . 写 ...

  5. Qt 事件系统浅析 (用 Windows API 描述,分析了QCoreApplication::exec()和QEventLoop::exec的源码)(比起新号槽,事件机制是更高级的抽象,拥有更多特性,比如 accept/ignore,filter,还是实现状态机等高级 API 的基础)

    事件系统在 Qt 中扮演了十分重要的角色,不仅 GUI 的方方面面需要使用到事件系统,Signals/Slots 技术也离不开事件系统(多线程间).我们本文中暂且不描述 GUI 中的一些特殊情况,来说 ...

  6. Qt多线程-QtConcurrent并行运算高级API

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-QtConcurrent并行运算高级API     本文地址:http://tec ...

  7. Hadoop(四)HDFS的高级API操作

    一 HDFS客户端环境准备 1.1 jar包准备 1)解压hadoop-2.7.6.tar.gz到非中文目录 2)进入share文件夹,查找所有jar包,并把jar包拷贝到_lib文件夹下 3)在全部 ...

  8. NetCore基于EasyNetQ的高级API使用RabbitMq

    一.消息队列 消息队列作为分布式系统中的重要组件,常用的有MSMQ,RabbitMq,Kafa,ActiveMQ,RocketMQ.至于各种消息队列的优缺点比较,在这里就不做扩展了,网上资源很多. 更 ...

  9. Kafka高级API和低级API

    Kafka消费过程分析 kafka提供了两套consumer API:高级Consumer API和低级API. 1 高级API 1)高级API优点 高级API 写起来简单 不需要去自行去管理offs ...

随机推荐

  1. Oracle数据库字段保留3位小数,程序读出来显示4位小数

    需求 项目需求从字段2位小数,改成3位小数,这事儿好办,数据库噼里啪啦敲了一行代码,发现居然报错,原因是不能修改字段精度问题,然后使用了冒泡排序,搞定 --新增临时字段 ,); --将原字段内容拷贝至 ...

  2. 模块sys,os

    Python的强大之处在于他有非常丰富和强大的标准库和第三方库,几乎你想实现的任何功能都有相应的Python库支持,以后的课程中会深入讲解常用到的各种库,现在,我们先来象征性的学2个简单的. 在Pyt ...

  3. HTML JavaScript 基础(下)

    一.JavaScript 函数 1.普通函数-有函数名 function func(){ } 2.匿名函数-无函数名 setInterval(function(){ console.log(123); ...

  4. 定了,这个vue.js开源项目,面试时,一定会考问

     因为现在的网店,都是用的商城系统, 而实体店都是入座后,扫码打开网上商城进行选购(餐饮,超市等),所以,vue.js迅速开发网上购物商城系统成为了香饽饽, 本人开源2020年4月开发的购物商城系统, ...

  5. CSS开发技巧(四):解决flex多行布局的行间距异常、子元素高度拉伸问题

    在使用flex布局时,若出现换行,有两种较为特殊的现象是值得我们研究的: 子元素高度被拉伸,其实际高度大于它的内容高度. 各行子元素之间的行间距过大,甚至我们根本没有给子元素设置margin. 现在我 ...

  6. visual stdio 2012快捷键

    为什么80%的码农都做不了架构师?>>>   VS2012变化的快捷键:注释::VS2010是(Ctrl+E,C),VS2012是(Ctrl+K, Ctrl+C),实际操作,按住Ct ...

  7. 用三维的视角理解二维世界:完美解释meshgrid函数,三维曲面,等高线,看完你就懂了。...

    完美解释meshgrid函数,三维曲面,等高线 #用三维的视角理解二维世界 #完美解释meshgrid函数,三维曲面,等高线 import numpy as np import matplotlib. ...

  8. 删除集群mds

    2019独角兽企业重金招聘Python工程师标准>>> 删除cephfs文件系统步骤: 1.停掉服务端mds: #systemctl stop {mds_service} 2.将md ...

  9. CSS3轻松实现彩色旋转六面体动画

    一.效果预览: 二.基本思路: 1.首先这个一个自动触发的动画,因此应使用animation设计,包括自动组装和组装完成后自动旋转的过程: 2.当鼠标放上去的时候六个面及上面的字体均变色,应在六个面设 ...

  10. 更安全的rm命令,保护重要数据

    更安全的rm命令,保护重要数据 网上流传的安全的rm,几乎都是提供一个rm的"垃圾"回收站,在服务器环境上来说,这实非良方. 我想,提供一个安全的rm去保护一些重要的文件或目录不被 ...