- Mysql和达梦数据库数据源切换提升兼容性
-
配置文件关于切换数据源的配置规范
- Mysql
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://145.170.28.77:3306/test_db?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true username: root password: 123456
- Oracle
spring: datasource: driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://145.170.33.104:5236/test_db username: test_db password: dmP@ssw0rd
-
持久层常用的编码规范以及注意事项
-
建库时的数据库名必须为大写
-
表名必须都为大写
-
日期字段最好都用字符串
-
插入数据
- Mysql没有自增序列这东西,只有建表时选择的自增选项,因此插入数据时需要添加属性==keyProperty==
<insert id="insertAndGetId" useGeneratedKeys="true" keyProperty="userId" parameterType="User"> insert into user(userName,password,comment) values(#{userName},#{password},#{comment}) </insert>
- 达梦虽然可以兼容上者,但是通过序列来实现主键自增情况下,因此插入数据时需要加入selectKey标签
<insert id="insertProduct" parameterType="domain.model.ProductBean" > <selectKey resultType="java.lang.Long" order="BEFORE" keyProperty="id"> SELECT AUTH_RESOURCE_SEQ.nextval FROM dual </selectKey> insert into AUTH_RESOURCE (ID, CODE) values (#{id,jdbcType=INTEGER}, #{code,jdbcType=VARCHAR}) </insert>
-
分页
- Mysql分页很简单,就是limit m,n
select t.* from table t limit ?, ?;
- 达梦分页就很麻烦了,分页通过rownum实现,rownum只能用<,<=或!=,绝不能用大于,这就意味着需要通过嵌套查询进行分页
select * from (select t.*,rownum rn from table t where rn >?) where rn<?
-
查询
- 查询中所有的表必须加上别名
- 字符串必须使用单引号
-
函数
Mysql 达梦 CHAR_LENGTH LENGTH CONCAT ` `
-
-
实现数据源切换的思路
- 核心思路: 通过mybatis的databaseId来进行切换
- 优点
- 由于Mysql和达梦数据库只有少数sql需要特别区分外,大部分的sql都是可以通用的,所以没必要Mysql和达梦各建一套mapper.xml
- 改动少,两个数据库可以共用一个mapper.xml,只需要通过databaseId进行区分即可
- 缺点
- 运行时不支持动态切换,但是基本可以忽略,没有什么不是重启项目不能解决的
- 实现
- 引入依赖(省略)
- 创建相关测试库(数据库名和字段名都为大写,达梦数据库创建了自增序列)
create sequence STUDENT_INFO_SEQ maxvalue 99999
- 配置文件
datasource: # 用于切换的数据库类型,MyBatis自动识别 type: dameng # 数据源 spring: datasource: # [MySql] # driver-class-name: com.mysql.cj.jdbc.Driver # url: jdbc:mysql://47.106.166.202:3306/test_db?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true # username: root # password: 123456 # [达梦] driver-class-name: dm.jdbc.driver.DmDriver url: jdbc:dm://localhost:5236/TEST username: TEST password: dmpassword # [Oracle] # driver-class-name: oracle.jdbc.OracleDriver # url: jdbc:oracle:thin:@145.170.33.133:1521:orcl # username: test # password: 123456
- xml修改
- 注意: 只能在sql有区别的方法中加入databaseId,其他相同的切勿加入databaseId否则会报mybatis databaseId Invalid bound statement (not found)错误
<insert id="insertSelective" parameterType="com.powerchen.datasourceswitch.domain.StudentInfo" useGeneratedKeys="true" keyProperty="id" databaseId="mysql"> insert into STUDENT_INFO (NAME) values ( #{name,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="com.powerchen.datasourceswitch.domain.StudentInfo" databaseId="oracle"> <selectKey keyProperty="id" resultType="java.lang.Integer" order="BEFORE"> SELECT STUDENT_INFO_SEQ.nextval FROM dual </selectKey> insert into STUDENT_INFO (NAME) values ( #{name,jdbcType=VARCHAR}) </insert> <insert id="insertSelective" parameterType="com.powerchen.datasourceswitch.domain.StudentInfo" databaseId="dameng"> <selectKey keyProperty="id" resultType="java.lang.Integer" order="BEFORE"> SELECT STUDENT_INFO_SEQ.nextval FROM dual </selectKey> insert into STUDENT_INFO (NAME) values ( #{name,jdbcType=VARCHAR}) </insert>
- 配置类
- 自动识别使用的数据库类型
- 在mapper.xml中databaseId的值就是跟properties的value对应
- properties的key都是连接池去数据库查的数据库名而定的,否则取不到报错
- 如果没有databaseId选择则说明该sql适用所有数据库
- 相关源码可查看VendorDatabaseIdProvider.getDatabaseName
@Bean public DatabaseIdProvider getDatabaseIdProvider() { DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider(); Properties properties = new Properties(); properties.setProperty("Oracle", "oracle"); properties.setProperty("MySQL", "mysql"); properties.setProperty("DM DBMS", "dameng"); databaseIdProvider.setProperties(properties); return databaseIdProvider; }
- 注意点
- 如果一个接口有多个不同的databaseId,如果有一个没有配置databaseId则该接口为默认接口
- 若没有配置datasource.type或者为空,则会去根据配置的数据源去调用对接的接口