- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章如何将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 去操作 MySQL,其实 Mybatis 还可以操作 ClickHouse,这里用 Druid 进行连接管理.
maven 配置 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<
dependency
>
<
groupId
>com.alibaba</
groupId
>
<
artifactId
>druid</
artifactId
>
<
version
>1.2.5</
version
>
</
dependency
>
<
dependency
>
<
groupId
>ru.yandex.clickhouse</
groupId
>
<
artifactId
>clickhouse-jdbc</
artifactId
>
<
version
>0.2.6</
version
>
</
dependency
>
<
dependency
>
<
groupId
>org.mybatis.spring.boot</
groupId
>
<
artifactId
>mybatis-spring-boot-starter</
artifactId
>
<
version
>2.1.3</
version
>
</
dependency
>
|
配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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: SELECT 1
|
加载配置项的类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
@Component
@ConfigurationProperties
(prefix =
"spring.datasource.click"
)
public
class
JdbcParamConfig {
private
String userName;
private
String password;
private
String driverClassName ;
private
String url ;
private
Integer initialSize ;
private
Integer maxActive ;
private
Integer minIdle ;
private
Integer maxWait ;
private
String validationQuery;
// ignore getters and setters
}
|
配置 Druid
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
@Configuration
@MapperScan
(basePackages = {
"com.aegis.analysis.clickhousestorage.dao"
})
public
class
DruidConfig {
@Resource
private
JdbcParamConfig jdbcParamConfig ;
@Bean
(name =
"clickDataSource"
)
public
DataSource dataSource()
throws
ClassNotFoundException {
Class classes = Class.forName(
"com.alibaba.druid.pool.DruidDataSource"
);
DruidDataSource dataSource = (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());
return
dataSource;
}
@Bean
public
SqlSessionFactory clickHouseSqlSessionFactoryBean()
throws
Exception {
SqlSessionFactoryBean factory =
new
SqlSessionFactoryBean();
factory.setDataSource(dataSource());
// 实体 model的 路径 比如 com.order.model
factory.setTypeAliasesPackage(
"com.example.clickhousedemo.model"
);
//添加XML目录
ResourcePatternResolver resolver =
new
PathMatchingResourcePatternResolver();
factory.setMapperLocations(resolver.getResources(
"classpath:mapper/*.xml"
));
//开启驼峰命名转换
factory.getObject().getConfiguration().setMapUnderscoreToCamelCase(
true
);
return
factory.getObject();
}
}
|
定义一个 UserInfo 类,建表语句如下:
1
2
3
4
5
6
7
8
9
|
CREATE
TABLE
test.
user
(
`id` Int16,
`
name
` String,
`score` Float32,
`score2` Float64,
`state` Int8,
`createTime` DateTime,
`ranks` Array(UInt8)
) ENGINE = MergeTree()
ORDER
BY
id;
|
实体类:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
class
UserInfo {
private
Integer id;
// int16
private
String name;
// String
private
Float score;
// float16
private
Double score2;
// float32
private
Boolean state;
// int8
private
Date createTime;
// datetime
private
Integer[] ranks;
// Array - Array 类型需要进行类型转换
// 具体转换方法与配置参考 ClickArrayToIntHandler 类与 UserMapper.xml 中关于查询和插入时 ranks 字段的配置
// ignore getters and setters
}
|
DAO 和 Mapper 文件就按照连接 MYSQL 时的写法一样.
这里有个需要注意的点,ClickHouse 有个 Array 类型,可以用来存数组,就像 ES 一样。问题是类型转换需要自己定义。网上一些资料仅列出了基本类型的场景,我自己实现了一个转换器,可以参考一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
/**
* Java Int 数组与 ClockHouse Array Int 转换器
* @version 1.0
* @since 2019/11/14 9:59
*/
public
class
ClickArrayToIntHandler
extends
BaseTypeHandler<Integer[]> {
@Override
public
void
setNonNullParameter(PreparedStatement preparedStatement,
int
i, Integer[] integers, JdbcType jdbcType)
throws
SQLException {
preparedStatement.setObject(i, integers);
}
@Override
public
Integer[] getNullableResult(ResultSet resultSet, String s)
throws
SQLException {
Object obj = resultSet.getObject(s);
return
parseClickHouseArrayToInt(obj);
}
@Override
public
Integer[] getNullableResult(ResultSet resultSet,
int
i)
throws
SQLException {
Object obj = resultSet.getObject(i);
return
parseClickHouseArrayToInt(obj);
}
@Override
public
Integer[] getNullableResult(CallableStatement callableStatement,
int
i)
throws
SQLException {
Object obj = callableStatement.getObject(i);
return
parseClickHouseArrayToInt(obj);
}
private
Integer[] parseClickHouseArrayToInt(Object obj) {
if
(obj
instanceof
ClickHouseArray) {
int
[] res =
new
int
[
0
];
try
{
res = (
int
[]) ((ClickHouseArray) obj).getArray();
}
catch
(SQLException ex) {
ex.printStackTrace();
}
if
(res !=
null
&& res.length >
0
) {
Integer[] resI =
new
Integer[res.length];
for
(
int
i =
0
; i < res.length; i++) {
resI[i] = res[i];
}
return
resI;
}
}
return
new
Integer[
0
];
}
}
|
DAO.xml 也给一个示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<
mapper
namespace
=
"com.aegis.analysis.clickhousestorage.dao.UserInfoMapper"
>
<
resultMap
id
=
"BaseResultMap"
type
=
"com.example.clickhousedemo.model.UserInfo"
>
<
id
column
=
"id"
property
=
"id"
/>
<
result
column
=
"name"
property
=
"name"
/>
<
result
column
=
"name"
property
=
"name"
/>
<
result
column
=
"score"
property
=
"score"
/>
<
result
column
=
"score2"
property
=
"score2"
/>
<
result
column
=
"state"
property
=
"state"
/>
<
result
column
=
"createTime"
property
=
"createTime"
/>
<!-- <result column="ranks" property="ranks" jdbcType="JAVA_OBJECT" javaType="java.lang.Object" />-->
<
result
column
=
"ranks"
property
=
"ranks"
typeHandler
=
"com.example.clickhousedemo.dao.ClickArrayToIntHandler"
/>
</
resultMap
>
<
sql
id
=
"Base_Column_List"
>
*
</
sql
>
<
insert
id
=
"saveData"
parameterType
=
"com.aegis.analysis.clickhousestorage.model.UserInfo"
>
INSERT INTO user
(id,name, score, score2, state, createTime, ranks)
VALUES
(#{id},#{name}, #{score}, #{score2}, #{state}, #{createTime}, #{ranks, jdbcType=ARRAY,
typeHandler=com.example.clickhousedemo.dao.ClickArrayToIntHandler})
</
insert
>
<
select
id
=
"selectById"
resultMap
=
"BaseResultMap"
>
select
<
include
refid
=
"Base_Column_List"
/>
from user
where id = #{id}
limit 1
</
select
>
<
select
id
=
"selectList"
resultMap
=
"BaseResultMap"
>
select
<
include
refid
=
"Base_Column_List"
/>
from user
</
select
>
</
mapper
>
|
具体代码可以去我的 Git 仓库里查看,还有 SpringBoot 整合其他中间件技术的示例,欢迎 Star! 。
https://github.com/laolunsi/spring-boot-examples 。
以上就是如何将Mybatis连接到ClickHouse的详细内容,更多关于Mybatis连接到ClickHouse的资料请关注我其它相关文章! 。
原文链接:http://www.eknown.cn/index.php/spring-boot/clickhouse.html 。
最后此篇关于如何将Mybatis连接到ClickHouse的文章就讲到这里了,如果你想了解更多关于如何将Mybatis连接到ClickHouse的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我知道这个问题可能已经被问过,但我检查了所有这些,我认为我的情况有所不同(请友善)。所以我有两个数据集,第一个是测试数据集,第二个是我保存在数据框中的预测(预测值,这就是没有数据列的原因)。我想合并两
在 .loc 方法的帮助下,我根据同一数据框中另一列中的值来识别 Panda 数据框中某一列中的值。 下面给出了代码片段供您引用: var1 = output_df['Player'].loc[out
当我在 Windows 中使用 WinSCP 通过 Ubuntu 连接到 VMware 时,它提示: The server rejected SFTP connection, but it lis
我正在开发一个使用 xml web 服务的 android 应用程序。在 wi-fi 网络中连接时工作正常,但在 3G 网络中连接时失败(未找到 http 404)。 这不仅仅发生在设备中。为了进行测
我有一个XIB包含我的控件的文件,加载到 Interface Builder(Snow Leopard 上的 Xcode 4.0.2)中。 文件的所有者被设置为 someClassController
我在本地计算机上管理 MySQL 数据库,并通过运行以下程序通过 C 连接到它: #include #include #include int main(int argc, char** arg
我不知道为什么每次有人访问我网站上的页面时,都会打开一个与数据库的新连接。最终我到达了大约 300 并收到错误并且页面不再加载。我认为它应该工作的方式是,我将 maxIdle 设置为 30,这意味着
希望清理 NMEA GPS 中的 .txt 文件。我当前的代码如下。 deletes = ['$GPGGA', '$GPGSA', '$GPGSV', '$PSRF156', ] searchquer
我有一个 URL、一个用户名和一个密码。我想在 C# .Net WinForms 中建立 VPN 连接。 你能告诉我从哪里开始吗?任何第三方 API? 代码示例将受到高度赞赏... 最佳答案 您可以像
有没有更好的方法将字符串 vector 转换为字符 vector ,字符串之间的终止符为零。 因此,如果我有一个包含以下字符串的 vector "test","my","string",那么我想接收一
我正在编写一个库,它不断检查 android 设备的连接,并在设备连接、断开连接或互联网连接变慢时给出回调。 https://github.com/muddassir235/connection_ch
我的操作系统:Centos 7 + CLOUDLINUX 7.7当我尝试从服务器登录Mysql时 [root@server3 ~]# Mysql -u root -h localhost -P 330
我收到错误:Puma 发现此错误:无法打开到本地主机的 TCP 连接:9200(连接被拒绝 - 连接(2)用于“本地主机”端口 9200)(Faraday::ConnectionFailed)在我的
请给我一些解决以下错误的方法。 这是一个聊天应用....代码和错误如下:: conversations_controller.rb def create if Conversation.bet
我想将两个单元格中的数据连接到一个单元格中。我还想只组合那些具有相同 ID 的单元格。 任务 ID 名称 4355.2 参与者 4355.2 领袖 4462.1 在线 4462.1 快速 4597.1
我经常需要连接 TSQL 中的字段... 使用“+”运算符时 TSQL 强制您处理的两个问题是 Data Type Precedence和 NULL 值。 使用数据类型优先级,问题是转换错误。 1)
有没有在 iPad 或 iPhone 应用程序中使用 Facebook 连接。 这个想法是登录这个应用程序,然后能够看到我的哪些 facebook 用户也在使用该应用程序及其功能。 最佳答案 是的。
我在连接或打印字符串时遇到了一个奇怪的问题。我有一个 char * ,可以将其设置为字符串文字的几个值之一。 char *myStrLiteral = NULL; ... if(blah) myS
对于以下数据 - let $x := "Yahooooo !!!! Select one number - " let $y := 1 2 3 4 5 6 7 我想得到
我正在看 UDEMY for perl 的培训视频,但是视频不清晰,看起来有错误。 培训展示了如何使用以下示例连接 2 个字符串: #!usr/bin/perl print $str = "Hi";
我是一名优秀的程序员,十分优秀!