欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

记一次基于mybatis的Springboot项目数据库从Mysql迁移至Oracle的全过程(超详细)

程序员文章站 2022-03-06 20:59:22
...

前言

自己做了一个后端使用springboot,前端使用vue的前后端分离的知识图谱系统,图数据库用Neo4j,关系数据库用的mysql,在项目上线前一周,甲方爸爸要求关系数据库要使用Oracle11g,无情,加班几天终于完成了Mysql8.5迁移至Oracle11g的全过程,技术点不难,但是太麻烦了,因此在此记录一下,希望能帮到一些小伙伴,初次在CSDN上写博客,希望大家体谅一下,不喜勿喷!

(一)MySQL数据库中的表数据迁移到Oracle数据库

具体的操作流程和方法见链接:
从 MySQL 迁移数据到 Oracle 中的全过程

在这里主要补充一些细节:

Navicat安装**

详情见链接:
Navicat安装**教程
使用上述方法将Mysql数据迁移至Oracle数据库之后,有一些要注意的地方,在这里,我只对自己修改的地方进行一下记录:

  1. 表名及其中的字段名全部变为大写
  2. int类型的字段迁移至Oracle后变为Number
  3. date类型的字段没有变化
  4. varchar和text类型的字段统一改为varchar2
  5. mysql自定义的存储过程需要重写

关于序列自增的问题,上述教程已经说的较为详细,在这里将新增序列的代码贴上作为补充:

-- auto-generated definition
create sequence KGDEPARTMENT
start with 1000
increment by 1
minvalue 1000
maxvalue 99999999
nocycle 
nocache  

tinyint字段需要重新定义

因为在mysql中,tinyint值为0时,默认为false,值为1时,返回的是true。但是在oracle中,并没有这类字段,很多时候我们用到此字段作为是否有效的标识,因此,包括使用SpringSecurity的过程中,登录用户是否有效也需要enabled这个字段。
因此之前写的用此字段判断true和false的代码逻辑需要重写,改为使用int类型的数字0和1来判断。

登录用户类处理enabled字段的方法:
   @Override
    public boolean isEnabled() {
        return enabled==1?true:false;
    }
后端其他常用类处理enabled字段的方法:
    private Integer enabled;
        public Integer getEnabled() {
        return enabled;
    }
    public void setEnabled(Integer enabled) {
        this.enabled = enabled;
    }
前端使用了Element组件中Switch滑块,因此要对返回的Enabled子段进行处理
是否启用:
   <el-table-column
           label="是否启用">
           <template slot-scope="scope">
           <el-tag size="small" type="success" v-if="scope.row.enabled==1">已启用</el-tag>
           <el-tag size="small" type="danger" v-else>未启用</el-tag>
          </template>
   </el-table-column>
    showEditView(index, data) {
                //console.log(data)
                if( data.enabled==1){
                    data.enabled=true;
                }else {
                    data.enabled=false;
                }
                Object.assign(this.updateDevelopPhase, data);
                this.dialogVisible = true;
               // console.log(this.updateDevelopPhase)
            },
    doUpdate() {
                if(this.updateDevelopPhase.enabled==true){
                    this.updateDevelopPhase.enabled=1;
                }else {
                    this.updateDevelopPhase.enabled=0;
                }
                this.putRequest("/system/dic/developPhase/", this.updateDevelopPhase).then(resp => {
                    if (resp) {
                        this.initDevelopPhases();
                        this.updateDevelopPhase.name = '';
                        this.dialogVisible = false;
                    }
                })
            },

(二)使用mybatis逆向工具生成Oracle对应表的实体类以及对应的映射方法

在这里我使用的mybatis逆向生成工具已上传至百度网盘,内附使用说明,如何使用大家下载阅读使用说明即可:
网盘链接:https://pan.baidu.com/s/1Kn7LMoyQoyHjDYBq9fuYMQ
提取码:9jqi
生成对应的类以及mapper文件后,并不能立即在项目中使用,有些命名规则或者细节上需要修改:

1 生成的Model实体类中字段名以及.xml文件中property的属性名统统改为驼峰法则命名的形式,此字段名为返回到前端数据的数据属性。

2 由于mysql有主键自增的方式,而oracle只能通过序列自增的方式,因此插入方法中,要引入序列,具体实现看代码:

  <insert id="insert" parameterType="org.javaboy.vhr.model.KgReason1" >
  insert into KG_REASON1 (ID, NAME, CREATEDATE,
  ENABLED)
  values (KGREASON1.nextval, #{name,jdbcType=VARCHAR}, #{createDate,jdbcType=DATE},
  #{enabled,jdbcType=DECIMAL})
</insert>

3 批量插入方法也有很大不同,具体看Demo:

java方法:

    Integer addQualityResetProblems(@Param("list") List<KgQualityResetProblem> list);

mysql实现:

 <insert id="addQualityResetProblems" useGeneratedKeys="false"
            parameterType="org.javaboy.vhr.model.KgQualityResetProblem">
        INSERT INTO KG_QUALITYRESETPROBLEM(ID, ...)
        SELECT KGQUALITYRESETPROBLEM.nextval,s.* FROM
        (
        <foreach collection="list" item="qualityResetProblem" separator="UNION ALL">
            SELECT #{qualityResetProblem.fSecret,jdbcType=VARCHAR},
           ...}
            FROM dual
        </foreach>
        ) s
    </insert>

4 分页功能也有很大不同,具体看Demo:

java Service层方法:

    public RespPageBean getQualityResetProblemByPage(Integer page, Integer size) {
        if (page != null && size != null) {
            page = (page - 1) * size;
        }
        List<KgQualityResetProblem> data = kgQualityResetProblemMapper.getQualityResetProblemByPage(page, size);
        Long total = kgQualityResetProblemMapper.getTotal();
        RespPageBean bean = new RespPageBean();
        bean.setData(data);
        bean.setTotal(total);
        return bean;
    }

Dao层:

  List<KgQualityResetProblem> getQualityResetProblemByPage(@Param("page") Integer page, @Param("size") Integer size);

SQL语句:

  <select id="getQualityResetProblemByPage" resultMap="AllQualityResetProblemInfo">
        SELECT *
        from
        (select A.*,ROWNUM RN  from(
        SELECT qua.* ,
        D1."NAME" AS DESIGNDEPTNAME ,D1."ID" as DESIGNDEPTID ,
        D2."NAME" AS PRODUCEDEPTNAME , D2."ID" as PRODUCEDEPTID,
        D3."NAME" AS DUTYDEPTNAME ,D3."ID" as DUTYDEPTID,
        D4."NAME" AS OUTDEPTNAME ,D4."ID" as OUTDEPTID,
        KG_REASON1."NAME" AS CAUSECLASS1NAME ,KG_REASON1."ID" as CAUSECLASS1ID ,
        KG_REASON2."NAME" AS CAUSECLASS2NAME , KG_REASON2."ID" as CAUSECLASS2ID,
        KG_WORKPHASE."NAME" AS WNAME ,KG_WORKPHASE."ID" as WID,
        KG_PRODUCTLEVEL."NAME" AS PNAME ,KG_PRODUCTLEVEL."ID" as PID,
        KG_DEVELOPPHASE."NAME" AS DNAME ,KG_DEVELOPPHASE."ID" as DID
        from KG_QUALITYRESETPROBLEM qua
        left join KG_DEPARTMENT D1 on qua."FPRODUCTDESIGNDEPTID"=D1."ID"
        left join KG_DEPARTMENT D2 on qua."FPRODUCTPRODUCEDEPTID"=D2."ID"
        left join KG_DEPARTMENT D3 on qua."FDUTYDEPTID"=D3."ID"
        left join KG_DEPARTMENT D4 on qua."FOUTDEPTNAMEID"=D4."ID"
        left join KG_REASON1 on qua."FCAUSATIONCLASS1ID"=KG_REASON1."ID"
        left join KG_REASON2 on qua."FCAUSATIONCLASS2ID"=KG_REASON2."ID"
        left join KG_WORKPHASE on qua."FWORKPHASE1ID"=KG_WORKPHASE."ID"
        left join KG_PRODUCTLEVEL on qua."FPRODUCTLEVELID"=KG_PRODUCTLEVEL."ID"
        left join KG_DEVELOPPHASE on qua."FMODELDEVELOPPHASEID"=KG_DEVELOPPHASE."ID"
        order by qua.ID DESC
        )A
        where ROWNUM  &lt;=(#{page}+#{size})
        )
        where RN > #{page}
    </select>

在这里,补充一些mysql和oracle SQL语句踩得坑:

  1. mysql语句单引号,oracle都要转换为双引号
  2. mysql语句可以在句末加;号,oracle不能加;号
  3. mysql数据库表以及对应字段可以*大小写,oracle表和字段都要大写
  4. mysql中表类型为text的字段到oracle后为CLOB,但在这里我要改为varchar2字段类型,因此使用在oracle表中要先删除该字段,再重新添加该字段。

(三)Springboot项目中引入Oracle

propertie文件配置:

spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#spring.datasource.url=jdbc:oracle:thin:@localhost:1521:QQJG
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:QQJG
spring.datasource.username=
spring.datasource.password=

maven项目引入配置:

 		<dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.1.0</version>
        </dependency>

下载oracle相关依赖:

参考该链接:
下载oracle相关依赖