Mybatis切换MySql和达梦数据库数据源

1,084 阅读2分钟
  • Mysql和达梦数据库数据源切换提升兼容性
  1. 配置文件关于切换数据源的配置规范

    • 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
    
  2. 持久层常用的编码规范以及注意事项

    • 建库时的数据库名必须为大写

    • 表名必须都为大写

    • 日期字段最好都用字符串

    • 插入数据

      1. Mysql没有自增序列这东西,只有建表时选择的自增选项,因此插入数据时需要添加属性==keyProperty==
          <insert id="insertAndGetId" useGeneratedKeys="true" keyProperty="userId" parameterType="User">
              insert into user(userName,password,comment)
              values(#{userName},#{password},#{comment})
          </insert>
      
      1. 达梦虽然可以兼容上者,但是通过序列来实现主键自增情况下,因此插入数据时需要加入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>
      
    • 分页

      1. Mysql分页很简单,就是limit m,n
          select t.*  from table t limit ?, ?;
      
      1. 达梦分页就很麻烦了,分页通过rownum实现,rownum只能用<,<=或!=,绝不能用大于,这就意味着需要通过嵌套查询进行分页
          select * from (select t.*,rownum rn from table t where rn >?) where rn<?
      
    • 查询

      1. 查询中所有的表必须加上别名
      2. 字符串必须使用单引号
    • 函数

      Mysql达梦
      CHAR_LENGTHLENGTH
      CONCAT``
  3. 实现数据源切换的思路

    • 核心思路: 通过mybatis的databaseId来进行切换
    • 优点
      1. 由于Mysql和达梦数据库只有少数sql需要特别区分外,大部分的sql都是可以通用的,所以没必要Mysql和达梦各建一套mapper.xml
      2. 改动少,两个数据库可以共用一个mapper.xml,只需要通过databaseId进行区分即可
    • 缺点
      1. 运行时不支持动态切换,但是基本可以忽略,没有什么不是重启项目不能解决的
    • 实现
      1. 引入依赖(省略)
      2. 创建相关测试库(数据库名和字段名都为大写,达梦数据库创建了自增序列)
          create sequence STUDENT_INFO_SEQ maxvalue 99999
      
      1. 配置文件
          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
      
      1. 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>
      
      1. 配置类
        • 自动识别使用的数据库类型
        • 在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;
          }
      
    • 注意点
      1. 如果一个接口有多个不同的databaseId,如果有一个没有配置databaseId则该接口为默认接口
      2. 若没有配置datasource.type或者为空,则会去根据配置的数据源去调用对接的接口