一.背景
很多时候我们的系统往往使用的是mysql数据库,却突然遇上要使用oracle数据库了,这时候就要考虑给系统做兼容多种数据库了。
二.步骤
1.在配置文件或者配置中心对应的服务配置文件里配置对应的数据源,配置哪个数据库,你的系统就使用哪个数据库
datasource: druid: url: jdbc:oracle:thin:@//你数据库的ip地址:端口号/orcl username: (拾万个为什么)你的账号 password: (拾万个为什么)你的密码 driver-class-name: oracle.jdbc.driver.oracledriver max-active: 20 initial-size: 1 max-wait: 60000 min-idle: 1 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 validation-query: select 'x' from dual test-while-idle: true test-on-borrow: false test-on-return: false pool-prepared-statements: true max-open-prepared-statements: 20 filters: stat, wall
这里由于是做兼容oracle的,所以在这里配置oracle的数据源
2.继续在配置文件或者配置中心里配置mybatis-plus的database-id
我的项目使用的是mybatis-plus,使用mybatis也一样,需要在这里配置你的database-id。
# mybatis 配置 mybatis-plus: mapper-locations: classpath:mapper/*mapper.xml typealiasespackage: com.shiwangeweishenme.provider.entity(你模块实体类的包) configuration: database-id: oracle map-underscore-to-camel-case: true jdbc-type-for-null: 'null' log-impl: org.apache.ibatis.logging.stdout.stdoutimpl
这里说下我在做这个的过程中遇到的问题,也就是为什么要在这里配置jdbc-type-for-null:
我在做swagger测试的时候,插入空值会提示如下错误
nested exception is org.apache.ibatis.type.typeexception: could not set parameters for mapping: parametermapping{property='stationbo', mode=in, javatype=class java.lang.object, jdbctype=null, numericscale=null, resultmapid='null', jdbctypename='null', expression='null'}. cause: org.apache.ibatis.type.typeexception: error setting null for parameter #1 with jdbctype other . try setting a different jdbctype for this parameter or a different jdbctypefornull configuration property. cause: java.sql.sqlexception: 无效的列类型: 1111
直接上直观点(狗头)
找了很久原因,发现,使用mybatis在插入oracle数据库的数据为空的时候,在configuration类中初始化jdbctypefornull默认值是other,这样就会报错
public void setjdbctypefornull(jdbctype jdbctypefornull) { this.jdbctypefornull = jdbctypefornull; }
jdbc-type-for-null的作用是,当mybatis插入空值的时候,需要指定jdbctype,这个也很容易理解的吧,假如你不指定这个空值类型,那插入的空值到底是null还是0呢?
所以,jdbc-type-for-null的作用就是指定你插入的空值是什么类型的。
解决办法就是在配置文件、配置中心里配置这个值为null,在插入的数据为空的时候就让空值为null.
3.在你项目的pom.xml里引入oracle的依赖
<dependency> <groupid>com.oracle</groupid> <artifactid>ojdbc7</artifactid> <version>12.1.0.2.0</version> </dependency>
值得注意的是,有些依赖包会和jdk的版本不对应,这个依赖包可以适应jdk8
4.修改你的sql
修改你的mapper.xml的语句,很简单,就是在每个sql映射里加上databaseid=”oracle”,前面让配置这个东西就是这个原因。
比如:
<select id="get" resulttype="java.util.map" parametertype="java.util.map" databaseid="oracle"> select type,name,desc,state , modify_date from inspect_type where 1=1 <if test="params.type != null and params.type != '' "> and type like '${params.type}%' </if> <if test="params.name != null and params.name != ''"> and name like '${params.name}%' </if> <if test="params.desc != null and params.desc != ''"> and desc like '${params.desc}%' </if> <if test="params.state != null and params.state != ''"> and state = '${params.state}' </if> </select> <select id="get" resulttype="java.util.map" parametertype="java.util.map" databaseid="ms-sql"> select type,name,desc,state , modify_date from inspect_type where 1=1 <if test="params.type != null and params.type != '' "> and type like '${params.type}%' </if> <if test="params.name != null and params.name != ''"> and name like '${params.name}%' </if> <if test="params.desc != null and params.desc != ''"> and desc like '${params.desc}%' </if> <if test="params.state != null and params.state != ''"> and state = '${params.state}' </if> </select>
发现这两个映射有什么不同吗,那就是databaseid不同,当你的配置文件配置ms-sql的并且数据源是mysql的数据源的时候,它就使用mysql数据库;当databaseid=”oracle”并且数据源配置的是oracle的数据源的时候,就是使用oracle数据库。
这些过程忽略某一步了,那就是搬迁数据库,这里不做延伸了。
三.兼容带来的问题
1.表名、字段名长度的问题
由于每个人开发的规范都不一样,有些人建表建字段的时候长度太长,会导致做兼容数据库的一些问题,很麻烦。
mysql中字段名最大允许64个字节,oracle不能超过32个字符(一个英文字符等于一个字节)。所以可以通俗地讲,oracle不能超过30长度,mysql无限制。
2.索引的问题
oracle中的索引不能重复,而mysql可以。
如果重复,报错:
ora-00955: name is already used by an existing object
比如:表student中有两个索引grade_index和name_index,它两的字段一模一样(两个索引的字段都是grade),oracle不通过。
解决办法:删除grade_index这个索引。
表contry中,index_tid和tid,两个索引的字段一模一样,oracle不通过。
解决办法:删除tid这个索引。
3.sql的问题
insert语句,对于mysql,values后面可以不写全所有字段,插入时mysql会自动插入默认值;但是oracle不行,会报:
ora-00947: not enough values
4.oracle表的别名不能加as,列的别名可以加as
select a.name from appinfo a;-- 正确 select a.name from appinfo as a;-- 错误
5.其他问题
实际的开发过程遇到的问题很多,这里不一一总结了。