人大金仓KingbaseV8适配文档
1 应用及对应版本
MybatisPlus(3.4.2)
kingbaseES 数据库版本(V008R006C007B0024)
kingbase驱动包版本(8.6.0)
mysql 数据库(8.0.31)
mysql 驱动包版本(8.0.20)
2 主要改造点
数据库连接方式;
pom.xml 依赖包修改;
数据库改造点;
mybatis: *Mapper.xml 文件改造;
java 类改造(含实体类、Service和Controller等);
3 改造内容
3.1 数据库连接方式
spring.datasource.type = com.zaxxer.hikari.HikariDataSource
spring.datasource.driverClassName = com.kingbase8.Driver
spring.datasource.url = jdbc:kingbase8://localhost:54321/xxxx?characterEncoding=utf8
spring.datasource.username = xxx
spring.datasource.password = xxx
spring.datasource.initialSize = 10
spring.datasource.minIdle = 10
spring.datasource.maxActive = 345
spring.datasource.maxWait = 60000
spring.datasource.timeBetweenEvictionRunsMillis = 60000
spring.datasource.minEvictableIdleTimeMillis = 300000
spring.datasource.validationQuery = SELECT 1 FROM T_ETC
spring.datasource.testWhileIdle = true
spring.datasource.testOnBorrow = false
spring.datasource.testOnReturn = false
spring.datasource.poolPreparedStatements = true
spring.datasource.maxPoolPreparedStatementPerConnectionSize = 20
spring.datasource.filters = stat,wall,log4j
spring.datasource.connectionProperties = druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
spring.datasource.driver-class-name=com.kingbase8.Driver
spring.datasource.hikari.minimum-idle=1
spring.datasource.hikari.connection-test-query=SELECT 1
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.pool-name=GHHikariCP
spring.datasource.hikari.max-lifetime=120000
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.db-type=oracle
#处理数据库中 Boolean 和 实体类中的 Integer 的类型转换,看下面的 3.4
mybatis-plus.type-handlers-package=com.test.tools.model.typehandler
#设置数据库配置的模式
mybatis-plus.global-config.db-config.schema=xxxx
3.2 pom.xml文件修改
<!--mysql 驱动包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--KingBase 驱动包-->
<dependency>
<groupId>com.xh</groupId>
<artifactId>kingbase-x86</artifactId>
<version>8.6.0</version>
</dependency>
3.3 数据库调整点
1、数据库的数据类型与服务对应关系
注意:如果出现下图问题,则需要把字段设置 timestamp WITHOUT time ZONE ;或出现Java的LocalDateTime 映射 TimeStampZ类型失败的问题,也是需要把字段设置成 timestamp WITHOUT time ZONE。
2、创建若干函数,例如:date_format、exec 等
(很多 mysql 函数不被人大金仓数据库支持,需要手动创建)
-- 创建 date_format 函数,并支持若干日期格式
-- kingbase 没有这个函数,需要自定义,以下为参考,具体还需要结合业务看是否适配,可自行增减
CREATE OR REPLACE FUNCTION "public"."date_format"("indate" anyelement, "intext" text)
RETURNS "pg_catalog"."text" AS $BODY$
BEGIN
IF upper(inText) = upper('%Y%m%d_%H%i') THEN
return to_char(inDate,'YYYYMMDD_HH24MI');
END IF;
IF upper(inText) = upper('%Y-%m-%d %H:%i:%s') THEN
return to_char(inDate,'YYYY-MM-DD HH24:MI:SS');
END IF;
IF upper(inText) = upper('%Y%m%d%H%i%s') THEN
return to_char(inDate,'YYYYMMDDHH24MISS');
END IF;
IF upper(inText) = upper('%Y-%m-%d %H') THEN
return to_char(inDate,'YYYY-MM-DD HH24');
END IF;
IF upper(inText) = upper('%Y-%m-%d') THEN
return to_char(inDate,'YYYY-MM-DD');
END IF;
IF upper(inText) = upper('%Y-%m') THEN
return to_char(inDate,'YYYY-MM');
end if;
IF upper(inText) = upper('%Y') THEN
return to_char(inDate,'YYYY');
end if;
IF upper(inText) = upper('%m%d') THEN
return to_char(inDate,'MMDD');
END IF;
IF upper(inText) = upper('%k') THEN
return to_char(inDate,'HH24');
END IF;
IF upper(inText) = upper('%c') THEN
return to_char(inDate,'MM');
END IF;
return '';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
-- 创建 exec 函数
CREATE OR REPLACE FUNCTION "public"."exec"("sqlstring" varchar)
RETURNS "pg_catalog"."varchar" AS $BODY$
declare
res varchar(50);
BEGIN
EXECUTE sqlstring;
RETURN 'ok';
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
3、检查各表、表字段名,统一修改为小写
4、检查各字段名是否存在驼峰式命名,统一修改为下划线的形式,并与对应的实体类一一对应——>即带下划线的数据库表字段对应驼峰命名的实体类字段
3.4 Boolean转Integer 转换器
package com.test.tools.model.typehandler;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* kingbase不支持boolean值,需要转换成int
*
* @author
* @date 2024/3/4 18:00
*/
public class BooleanHandler extends BaseTypeHandler<Boolean> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, Boolean aBoolean, JdbcType jdbcType) throws SQLException {
ps.setInt(i, aBoolean ? 1 : 0);
}
@Override
public Boolean getNullableResult(ResultSet resultSet, String columnName) throws SQLException {
int man = resultSet.getInt(columnName);
return man == 1;
}
@Override
public Boolean getNullableResult(ResultSet resultSet, int columnIndex) throws SQLException {
int man = resultSet.getInt(columnIndex);
return man == 1;
}
@Override
public Boolean getNullableResult(CallableStatement callableStatement, int columnIndex) throws SQLException {
int man = callableStatement.getInt(columnIndex);
return man == 1;
}
}
3.5 mybatis: *Mapper.xml 文件改造;
1、 凡是碰到 limit 关键字,需按照 postgre 语法重新更改
– 对已知表查询前五条数据
修改前:limit 1,5
修改后:limit 0 offset 5
2、逐个检查 java 中 Mapper.xml 文件中的 update 语句,update 条件不能使用别名操作
修改前:update t_device t set t.band_flag = #{bandFlag} where t.id = #{id} ;
修改后:update t_device set band_flag = #{bandFlag} where id = #{id} ;
3、 关联表字段存在类型不一致的情况,需要用 :: varchar 做类型转换,因为 mysql 的语法对字符串和数值类型做了兼容处理,而 kingbase 是严格区分字符串和数值,所以在遇到一些类型不一致的情况,需要类型转换
– device_id 字段是int4类型,后面concat函数转换后的是字符串类型,得使用 :: 先将device_id临时转化成字符串
SELECT * FROM t_alarm h
LEFT JOIN t_config c on c.device_id=d.id or c.device_id :: varchar = CONCAT('cam_',d.id);
4、sql查询过程中自定义的别名不要出现数据库关键字。例:select 字段名 as year (多见于统计年份)
5、kingbase数据库char存储是按照定长存储,不够的自动填充空字符,sql查询出来之后会带上缺少的空字符,比对的时候会出问题,变长字符串没有这个问题
6、 kingbase 分组查询不能将上级查询结果放到子查询中作为条件
7、 若该方法的返回类型为 resultMap ,则需要看情况修改该 resultMap 映射的 column 中的字段名;
8、 需要注意的一点在mysql中排序的时候null默认是最小的,在kingbase里面null默认是排序最大值;
9、 sql中包含 ` 符号需要替换掉,kingbase不支持这种写法,全部替换为空,或者替换成英文的 ’ 。(重点)
3.6 java 类改造(含实体类、Service和Controller等)
1、 修改 @TableName 注解,将注解内的表名统一修改为小写,若表名是按照驼峰命名规则,建议改为带下划线形式
– 已知表命名为 t_device 的情况下,以下为错误实例:
1)@TableName(“T_DEVICE”)
2)@TableName(“tDevice”)
3)@TableName(“T_device”)
2、 对于表自增的 id,应当加上注解:@TableId(type = IdType.AUTO) ,不要使用@TableId(type = IdType.NONE) 注解,否则 id 不会自增长;
3、 检查实体类中的字段是否有非驼峰命名,驼峰命名不需要任何修改,最主要的是需要跟数据库中的字段保持对应,即带下划线的数据库表字段对应驼峰命名的实体类字段。
--修改前的建表语句:
CREATE TABLE "public"."t_device" (
"manualPath" varchar(64) COLLATE "pg_catalog"."default"
);
-- 修改前对应的实体类字段申明:
private String manualPath ;
-- 修改后的建表语句:
CREATE TABLE "public"."t_device" (
"manual_path" varchar(64) COLLATE "pg_catalog"."default"
);
原理:(MybatisPlus 会自动将数据库中带下划线的字段转换成驼峰形式)
4、 检索工程中使用 Wrapper 形式写 sql 语句或者字段的部分,必须将条件中的字段名称与表字段保持相同。Wrapper 中使用的字段,必须要和数据库保持一致,否则会报字段找不到的错误。
5、 若实体类中 username 字段没有按驼峰命名,需要在该字段上加上注解@TableField(“user_name”) 其他字段类似,最好保持一致,使用 userName 驼峰式命名规则。