一、前言
因项目需求,小编要将项目从mysql迁移到oracle中 ~
现在将完成 基于MyBatis-Plus将项目中的MySQL语句全部转换成Oracle语句
大概实现步骤:
将项目改成支持双库配置(因项目基于mysql数据库已经全部完成,也不想直接替换掉,于是新增oracle库,让整个项目可支持多个数据库,这里不是多数据源哦!)
Oracle中创建常用函数
遍历项目中的xxxMapper.xml文件,找到mysql与oracle语句的区别,然后替换绝大部分SQL
最后将一些特殊的mysql语句手动修改为oracle语句
二、MyBatis-Plus 支持双库配置 【mysql,oracle】
1、application.yml中配置mybatis-plus的database-id
# mybatis-plus配置
mybatis-plus:
configuration:
jdbc-type-for-null: 'null' # 解决oracle更新数据为null时无法转换报错
database-id: oracle # 支持多库配置 mysql,oracle
2、MybatisPlus核心配置文件 -> 根据不同的数据库厂商执行不同的SQL
@Configuration
@MapperScan("com.zhengqing.demo.modules.**.mapper*")
public class MybatisPlusConfig {
/**
* `xxxMapper.xml`文件中的`databaseId`会自动识别使用的数据库类型与这里相对应
* 注: 如果没有指定`databaseId`则该SQL语句适用于所有数据库哦~
*
* databaseIdProvider:支持多数据库厂商
* VendorDatabaseIdProvider: 得到数据库厂商的标识(驱动getDatabaseProductName()),mybatis就能根据数据库厂商标识来执行不同的sql;
* MySQL,Oracle,SQL Server,xxxx
*/
@Bean
public DatabaseIdProvider getDatabaseIdProvider(){
DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
Properties properties = new Properties();
// 为不同的数据库厂商起别名
properties.setProperty("MySQL","mysql");
properties.setProperty("Oracle","oracle");
databaseIdProvider.setProperties(properties);
return databaseIdProvider;
}
}
3、xxxMapper.xml中通过databaseId指定数据库类型
SELECT * FROM 表名 LIMIT 1
SELECT * FROM 表名 WHERE ROWNUM <= 1
三、Oracle中创建常用函数
这里根据个人项目情况去实际应用即可~
1、ORACLE_TO_UNIX
Oracle时间 Date类型转换为Unix时间戳,等同于mysql中的UNIX_TIMESTAMP
create or replace function ORACLE_TO_UNIX(in_date IN DATE) return number is
begin
return( ROUND( (in_date -TO_DATE('19700101','yyyymmdd'))*86400 - TO_NUMBER(SUBSTR(TZ_OFFSET(sessiontimezone),1,3))*3600, 0) );
end ORACLE_TO_UNIX;
2、FIND_IN_SET
CREATE OR REPLACE FUNCTION FIND_IN_SET(piv_str1 varchar2, piv_str2 varchar2, p_sep varchar2 := ',')
RETURN NUMBER IS
l_idx number:=0; -- 用于计算piv_str2中分隔符的位置
str varchar2(500); -- 根据分隔符截取的子字符串
piv_str varchar2(500) := piv_str2; -- 将piv_str2赋值给piv_str
res number:=0; -- 返回结果
loopIndex number:=0;
BEGIN
-- 如果piv_str中没有分割符,直接判断piv_str1和piv_str是否相等,相等 res=1
IF instr(piv_str, p_sep, 1) = 0 THEN
IF piv_str = piv_str1 THEN
res:= 1;
END IF;
ELSE
-- 循环按分隔符截取piv_str
LOOP
l_idx := instr(piv_str,p_sep);
loopIndex:=loopIndex+1;
-- 当piv_str中还有分隔符时
IF l_idx > 0 THEN
-- 截取第一个分隔符前的字段str
str:= substr(piv_str,1,l_idx-1);
-- 判断 str 和piv_str1 是否相等,相等 res=1 并结束循环判断
IF str = piv_str1 THEN
res:= loopIndex;
EXIT;
END IF;
piv_str := substr(piv_str,l_idx+length(p_sep));
ELSE
-- 当截取后的piv_str 中不存在分割符时,判断piv_str和piv_str1是否相等,相等 res=1
IF piv_str = piv_str1 THEN
res:= loopIndex;
END IF;
-- 无论最后是否相等,都跳出循环
EXIT;
END IF;
END LOOP;
-- 结束循环
END IF;
-- 返回res
RETURN res;
END FIND_IN_SET;
四、工具类(MySQL语句转换Oracle语句)
替换步骤:
在 xxxMapper.xml 中将所有sql语句上加入 databaseId="mysql"
复制一份mysql的sql(即 将替换的oracle语句)
在复制的sql上加入databaseId="oracle"
找出mysql与oracle语句区别,然后替换sql
温馨小提示: 这里工具类只供参考,实际操作根据自己的项目做修改哦,操作前建议先备份自己的项目,以防操作不当丢失代码哦!
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;
import java.io.*;
import java.util.*;
/**
*
mysql迁移oracle 测试工具类
*
* @description :
* @author : zhengqing
* @date : 2020/1/08 10:10
*/
public class MySQLToOracleTest {
private final static String ORACLE_SQL = " ";
@Test // 替换项目中的sql语句
public void testSQL() throws Exception {
String path = System.getProperty("user.dir") + "\\src\\main\\java\\com\\zhengqing\\xxx"; // TODO 这里替换为自己的项目路径
File file = new File(path);
HashMap fileMap = new HashMap<>();
getAllFileByRecursion(fileMap, file);
fileMap.forEach((key, value) -> {
String fileXmlName = (String) key;
File fileXml = (File) value;
String filePath = fileXml.getPath();
if (fileXmlName.equals("Test.xml")) {
System.out.println(filePath);
try {
// 1、加入 databaseId="mysql"
addMysql(filePath);
// 2、复制一份oracle的sq