您好,登錄后才能下訂單哦!
這篇文章主要講解了“怎么將Mybatis連接到ClickHouse”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么將Mybatis連接到ClickHouse”吧!
最近在做數(shù)據(jù)分析項(xiàng)目,里面有這樣一個(gè)業(yè)務(wù):把匹配的數(shù)據(jù)打上標(biāo)簽,放到新的索引中。
數(shù)據(jù)量:累計(jì)億級的數(shù)據(jù)
使用場景:可能會(huì)單次查詢大量的數(shù)據(jù),但不會(huì)設(shè)置復(fù)雜的條件,且這些數(shù)據(jù)不會(huì)被再次修改
原來使用的數(shù)據(jù)庫:ElasticSearch
問題:上面也說了我這里打上標(biāo)記后,這些數(shù)據(jù)幾乎不會(huì)再修改了。ES 是一個(gè)全文檢索引擎,更適用于進(jìn)行大量文本檢索的情況。這里與我上面的使用場景就不太匹配了。
技術(shù)選型的考慮:改用戰(zhàn)斗民族開發(fā)的 ClickHouse,它適用于 OLAP 也就是數(shù)據(jù)分析的場景,當(dāng)數(shù)據(jù)寫入后,通過不同維度不斷挖掘、分析,發(fā)現(xiàn)其中的商業(yè)價(jià)值。ClickHouse 適用于讀遠(yuǎn)大于寫的情況。
此外,相比ES,ClickHouse 占用的硬盤空間更小,也有利于降低運(yùn)維成本。
下面是我在嘗試接入 ClickHouse 時(shí)的一些實(shí)踐,以及關(guān)于 ClickHouse數(shù)組類型轉(zhuǎn)換問題的解決方案。
關(guān)于 ClickHouse 更詳細(xì)的知識參考:https://zhuanlan.zhihu.com/p/98135840
示例代碼已經(jīng)上傳到了 Git,目前更新第 28 節(jié):https://github.com/laolunsi/spring-boot-examples/
以前一直用 Mybatis 去操作 MySQL,其實(shí) Mybatis 還可以操作 ClickHouse,這里用 Druid 進(jìn)行連接管理。
maven 配置
<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>
配置文件:
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource # 注意這里是自定義的配置,通過 JdbcParamConfig 來加載配置到 Spring 中 # 然后由 DruidConfig 來配置數(shù)據(jù)源 click: driverClassName: ru.yandex.clickhouse.ClickHouseDriver url: jdbc:clickhouse://127.0.0.1:8123/test # ip:port/database userName: default password: default # 按照自己連接的 clickhouse 數(shù)據(jù)庫來 initialSize: 10 maxActive: 100 minIdle: 10 maxWait: 6000 validationQuery: SELECT 1
加載配置項(xiàng)的類:
@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:
@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()); // 實(shí)體 model的 路徑 比如 com.order.model factory.setTypeAliasesPackage("com.example.clickhousedemo.model"); //添加XML目錄 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); factory.setMapperLocations(resolver.getResources("classpath:mapper/*.xml")); //開啟駝峰命名轉(zhuǎn)換 factory.getObject().getConfiguration().setMapUnderscoreToCamelCase(true); return factory.getObject(); } }
定義一個(gè) UserInfo 類,建表語句如下:
CREATE TABLE test.user ( `id` Int16, `name` String, `score` Float32, `score2` Float64, `state` Int8, `createTime` DateTime, `ranks` Array(UInt8) ) ENGINE = MergeTree() ORDER BY id;
實(shí)體類:
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 類型需要進(jìn)行類型轉(zhuǎn)換 // 具體轉(zhuǎn)換方法與配置參考 ClickArrayToIntHandler 類與 UserMapper.xml 中關(guān)于查詢和插入時(shí) ranks 字段的配置 // ignore getters and setters }
DAO 和 Mapper 文件就按照連接 MYSQL 時(shí)的寫法一樣。
這里有個(gè)需要注意的點(diǎn),ClickHouse 有個(gè) Array 類型,可以用來存數(shù)組,就像 ES 一樣。問題是類型轉(zhuǎn)換需要自己定義。網(wǎng)上一些資料僅列出了基本類型的場景,我自己實(shí)現(xiàn)了一個(gè)轉(zhuǎn)換器,可以參考一下:
/** * Java Int 數(shù)組與 ClockHouse Array Int 轉(zhuǎn)換器 * @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 也給一個(gè)示例:
<?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>
感謝各位的閱讀,以上就是“怎么將Mybatis連接到ClickHouse”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對怎么將Mybatis連接到ClickHouse這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。