如何将Mybatis连接到ClickHouse
场景
最近在做数据分析项目,里面有这样一个业务:把匹配的数据打上标签,放到新的索引中。
数据量:累计亿级的数据
使用场景:可能会单次查询大量的数据,但不会设置复杂的条件,且这些数据不会被再次修改
原来使用的数据库:ElasticSearch
问题:上面也说了我这里打上标记后,这些数据几乎不会再修改了。ES是一个全文检索引擎,更适用于进行大量文本检索的情况。这里与我上面的使用场景就不太匹配了。
技术选型的考虑:改用战斗民族开发的ClickHouse,它适用于OLAP也就是数据分析的场景,当数据写入后,通过不同维度不断挖掘、分析,发现其中的商业价值。ClickHouse适用于读远大于写的情况。
此外,相比ES,ClickHouse占用的硬盘空间更小,也有利于降低运维成本。
下面是我在尝试接入ClickHouse时的一些实践,以及关于ClickHouse数组类型转换问题的解决方案。
关于ClickHouse更详细的知识参考:https://zhuanlan.zhihu.com/p/98135840
示例代码已经上传到了Git,目前更新第28节:https://github.com/laolunsi/spring-boot-examples/
Mybatis+ClickHouse
以前一直用Mybatis去操作MySQL,其实Mybatis还可以操作ClickHouse,这里用Druid进行连接管理。
maven配置
com.alibaba druid 1.2.5 ru.yandex.clickhouse clickhouse-jdbc 0.2.6 org.mybatis.spring.boot mybatis-spring-boot-starter 2.1.3
配置文件:
spring: datasource: type:com.alibaba.druid.pool.DruidDataSource #注意这里是自定义的配置,通过JdbcParamConfig来加载配置到Spring中 #然后由DruidConfig来配置数据源 click: driverClassName:ru.yandex.clickhouse.ClickHouseDriver url:jdbc:clickhouse://127.0.0.1:8123/test#ip:port/database userName:default password:default#按照自己连接的clickhouse数据库来 initialSize:10 maxActive:100 minIdle:10 maxWait:6000 validationQuery:SELECT1
加载配置项的类:
@Component @ConfigurationProperties(prefix="spring.datasource.click") publicclassJdbcParamConfig{ privateStringuserName; privateStringpassword; privateStringdriverClassName; privateStringurl; privateIntegerinitialSize; privateIntegermaxActive; privateIntegerminIdle; privateIntegermaxWait; privateStringvalidationQuery; //ignoregettersandsetters }
配置Druid:
@Configuration @MapperScan(basePackages={ "com.aegis.analysis.clickhousestorage.dao" }) publicclassDruidConfig{ @Resource privateJdbcParamConfigjdbcParamConfig; @Bean(name="clickDataSource") publicDataSourcedataSource()throwsClassNotFoundException{ Classclasses=Class.forName("com.alibaba.druid.pool.DruidDataSource"); DruidDataSourcedataSource=(DruidDataSource)DataSourceBuilder .create() .driverClassName(jdbcParamConfig.getDriverClassName()) .type(classes) .url(jdbcParamConfig.getUrl()) .username(jdbcParamConfig.getUserName()) .password(jdbcParamConfig.getPassword()) .build(); dataSource.setMaxWait(jdbcParamConfig.getMaxWait()); dataSource.setValidationQuery(jdbcParamConfig.getValidationQuery()); returndataSource; } @Bean publicSqlSessionFactoryclickHouseSqlSessionFactoryBean()throwsException{ SqlSessionFactoryBeanfactory=newSqlSessionFactoryBean(); factory.setDataSource(dataSource()); //实体model的路径比如com.order.model factory.setTypeAliasesPackage("com.example.clickhousedemo.model"); //添加XML目录 ResourcePatternResolverresolver=newPathMatchingResourcePatternResolver(); factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml")); //开启驼峰命名转换 factory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true); returnfactory.getObject(); } }
定义一个UserInfo类,建表语句如下:
CREATETABLEtest.user( `id`Int16, `name`String, `score`Float32, `score2`Float64, `state`Int8, `createTime`DateTime, `ranks`Array(UInt8) )ENGINE=MergeTree()ORDERBYid;
实体类:
publicclassUserInfo{ privateIntegerid;//int16 privateStringname;//String privateFloatscore;//float16 privateDoublescore2;//float32 privateBooleanstate;//int8 privateDatecreateTime;//datetime privateInteger[]ranks;//Array-Array类型需要进行类型转换 //具体转换方法与配置参考ClickArrayToIntHandler类与UserMapper.xml中关于查询和插入时ranks字段的配置 //ignoregettersandsetters }
DAO和Mapper文件就按照连接MYSQL时的写法一样。
这里有个需要注意的点,ClickHouse有个Array类型,可以用来存数组,就像ES一样。问题是类型转换需要自己定义。网上一些资料仅列出了基本类型的场景,我自己实现了一个转换器,可以参考一下:
/** *JavaInt数组与ClockHouseArrayInt转换器 *@version1.0 *@since2019/11/149:59 */ publicclassClickArrayToIntHandlerextendsBaseTypeHandler{ @Override publicvoidsetNonNullParameter(PreparedStatementpreparedStatement,inti,Integer[]integers,JdbcTypejdbcType)throwsSQLException{ preparedStatement.setObject(i,integers); } @Override publicInteger[]getNullableResult(ResultSetresultSet,Strings)throwsSQLException{ Objectobj=resultSet.getObject(s); returnparseClickHouseArrayToInt(obj); } @Override publicInteger[]getNullableResult(ResultSetresultSet,inti)throwsSQLException{ Objectobj=resultSet.getObject(i); returnparseClickHouseArrayToInt(obj); } @Override publicInteger[]getNullableResult(CallableStatementcallableStatement,inti)throwsSQLException{ Objectobj=callableStatement.getObject(i); returnparseClickHouseArrayToInt(obj); } privateInteger[]parseClickHouseArrayToInt(Objectobj){ if(objinstanceofClickHouseArray){ int[]res=newint[0]; try{ res=(int[])((ClickHouseArray)obj).getArray(); }catch(SQLExceptionex){ ex.printStackTrace(); } if(res!=null&&res.length>0){ Integer[]resI=newInteger[res.length]; for(inti=0;i DAO.xml也给一个示例:
* INSERTINTOuser (id,name,score,score2,state,createTime,ranks) VALUES (#{id},#{name},#{score},#{score2},#{state},#{createTime},#{ranks,jdbcType=ARRAY, typeHandler=com.example.clickhousedemo.dao.ClickArrayToIntHandler}) select fromuser whereid=#{id} limit1 select fromuser 具体代码可以去我的Git仓库里查看,还有SpringBoot整合其他中间件技术的示例,欢迎Star!
https://github.com/laolunsi/spring-boot-examples
以上就是如何将Mybatis连接到ClickHouse的详细内容,更多关于Mybatis连接到ClickHouse的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。