MybatisPlus中調用Oracle存儲過程

起因

由於需要將新數據同步到另外的數據庫,所以需要使用dblink進行操作,但是dblink不支持寫入操作,因此需要調用寫好的存儲過程才能實現將新數據插入新數據的同時插入舊數據庫。

準備工作

預先準備好新舊兩個數據庫

舊的數據庫

create table OLD_USER
(
  USER_ID                    NUMBER(6) not null primary key,
  LOGIN_NAME                 VARCHAR2(100) not null,
  REAL_NAME                  VARCHAR2(300),
  PASSWORD                   CHAR(64)
)

新的數據庫

create table NEW_USER
(
  ID            NUMBER(11) not null primary key,
  CREATE_TIME   TIMESTAMP(6),
  UPDATE_TIME   TIMESTAMP(6),
  DELETED       NUMBER(1),
  ACCOUNT       VARCHAR2(255),
  USERNAME      VARCHAR2(255),
  PASSWORD      VARCHAR2(255)
)

對應的實體爲:

package com.donlex.demo.entity;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.util.Date;
import java.util.List;

@Getter
@Setter
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel("新數據庫對應實體")
@KeySequence("s_old_user")
public class NewUser {
    @ApiModelProperty("主鍵")
    @TableId(type = IdType.INPUT)
    private Long id;

    @ApiModelProperty(value = "創建時間", hidden = true)
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    @ApiModelProperty(value = "更新時間", hidden = true)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

    @ApiModelProperty(value = "刪除標誌", hidden = true)
    @TableField(fill = FieldFill.INSERT)
    @TableLogic
    private Boolean deleted;

    @ApiModelProperty("用戶賬號")
    private String account;

    @ApiModelProperty("用戶名稱")
    private String username;

    @ApiModelProperty("密碼")
    private String password;

    @ApiModelProperty("插入舊數據庫返回的id")
    @TableField(exist = false)
    private Integer oldUserId;
}

創建存儲過程

創建一個存儲過程用於將新數據庫的數據字段和舊的數據庫字段映射上,同時使用序列自增作爲id值,將新數據插入舊數據庫中。

create or replace procedure PRO_TO_OLD_USER(
                                         v_account in varchar2,
                                         v_username in varchar2,
                                         v_password in varchar2,
                                         v_result out varchar2) is

  V_ID number;
  PRAGMA AUTONOMOUS_TRANSACTION;
begin
-- 使用序列自增做爲主鍵,s_old_user爲序列名, @dklinkName 是dblink名
  SELECT s_old_user.NEXTVAL @dklinkName into V_ID FROM DUAL;
  insert into OLD_USER(USER_ID,
                        LOGIN_NAME,
                        REAL_NAME,
                        PASSWORD
                      )
  VALUES (V_ID,
-- 使用case進行判斷 v_account 字段是否爲空
          case when v_account is null
                 then
                 '空'
               else
                 v_account
          end,
          v_username,
          v_password
        );
  commit;
-- 返回自增的序列值
  v_result := V_ID;
  DBMS_OUTPUT.put_line('添加到舊數據庫賬號成功ID爲' || V_ID);

end PRO_TO_OLD_USER;

創建mapper中的方法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.donlex.demo.mapper.NewUserMapper">
 <!-- statementType 聲明指向的是什麼類型,其中CALLABLE是執行存儲過程和函數的-->
 <select id="insertIntoOldUser" statementType="CALLABLE" parameterType="com.donlex.demo.entity.NewUser">
    {call PRO_TO_OLD_USER
         (
             #{account,mode=IN},
             #{username,mode=IN},
             #{password,mode=IN},
             #{oldUserId,mode=OUT,jdbcType=INTEGER}
         )
    }
  </select>

</mapper>

注意點:

  1. statementType 設置爲 CALLABLE
  2. 在存儲過程中使用參數時,除了寫上必要的屬性名外,還必須指定參數的 mode(模式),可選值爲 INOUTINOUT 三種,入參使用 IN,出參使用 OUT,輸入輸出參數使用 INOUT。
  3. OUT 模式的參數,必須指定 jdbcType。因爲在 IN 模式下,MyBatis 提供了默認的 jdbcType,在 OUT 模式下沒有提供,因此必須指定 jdbcType
  4. 當入參存在無法識別,執行報錯時,最好指定 jdbcType

創建mapper接口

@Mapper
@Repository
public interface NewUserMapper extends BaseMapper<NewUser> {
  /**
   * 
   * 將新數據新增的賬號插入舊數據庫
   * @author donlex
   * @param req
   */
  void insertIntoOldUser(NewUser req);
}

這裏定義的是void方法,但是實際上是會返回NewUser實體對象,所以可以通過get方法獲取屬性值,這就是爲什麼在實體中定義了一個oldUserId,但是它不是數據表中真實存在的字段 @TableField(exist = false)

創建controller方法

這裏爲了方便就直接在controller中寫方法調用了。

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
public class SysUserController {
    @Autowired
    private NewUserMapper newUserMapper;
    @ApiOperation("將新數據寫入舊數據庫中")
    @PostMapping("/test")
    public Boolean addNewUserToOldUser(NewUser newUser){
        newUserMapper.insertIntoNewUser(newsUser);
        log.info("oldUserId爲{}",newUser.getOldUserId())
    }
}

執行的debug日誌

2019-12-30 15:58:31.850 DEBUG  ==>  Preparing: {call PRO_TO_OLD_USER ( ?, ?, ?, ? ) } 
2019-12-30 15:58:31.885 DEBUG  ==>  Parameters: 357869(String), donlex(String), a493fe7c29ce(String), 0(Integer)

歡迎訪問我的個人博客站點:https://donlex.cn

發佈了76 篇原創文章 · 獲贊 125 · 訪問量 22萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章