SpringBoot+Mybatis項目使用mybatis調用存儲過程傳入參數並接收返回值實現方式

背景:項目中需要使用存儲過程做積分與餘額的轉化,需要傳入類型來決定處理哪種類型的賬戶進行轉化,也需要接收轉化數目。存儲過程已經寫好,但是一直接收不到存儲過程的返回值,糾結了很久終於解決,在網上搜索的處理方式也都是看的一知半解,所以做下記錄。

一、存儲過程:

DROP PROCEDURE pro_member_credits_transfer;

CREATE  PROCEDURE pro_member_credits_transfer(IN accountType int,OUT transferAmount int)
BEGIN 
	 DECLARE vcreditsId int(20);
	 DECLARE vmemberId int(20) ;
	 DECLARE vnowCredits decimal(20,4);
	 DECLARE vlevel int(10);
	 DECLARE vrate decimal(10,4);
	 DECLARE accountCount int  DEFAULT(1);	#賬戶數量 需要轉化的積分賬戶數量
	 DECLARE startNum INT DEFAULT 0;	#開始位置
	 DECLARE done INT DEFAULT FALSE;   #結束標誌變量
	 #DECLARE total int default 0;			#總條數變量
	 DECLARE coin decimal(10,4);			#積分轉微幣數目
	 DECLARE nowCoin decimal(20,4);   #當前微幣數目
	 DECLARE coinId int(20);					#微幣賬戶ID
	 DECLARE xact_abort int;
	 #聲明遊標
	 DECLARE credits_cur CURSOR FOR SELECT 
			id,member_id,now_credits,level,IFNULL((select transfer_rate from common_coin_transfer_config where member_level = level),0.03) as rate
    FROM
    common_coin_credits 
    WHERE status = 0 and account_type = accountType and now_credits > 0.3 and  transfer_date != (select DATE_FORMAT(SYSDATE(),'%Y-%m-%d') from dual) for update;
	 #將結束標誌綁定到遊標,若沒有數據返回,程序繼續,並將變量done設爲TRUE 
	 DECLARE CONTINUE HANDLER FOR NOT FOUND 
	 SET done = TRUE;
	 #捕獲執行過程中異常 
	 DECLARE continue HANDLER FOR SQLEXCEPTION 
    GET DIAGNOSTICS CONDITION 1 
    @errno = MYSQL_ERRNO, @errmsg = MESSAGE_TEXT;
	 SELECT count(1) into accountCount from common_coin_credits where status = 0 and account_type = accountType and now_credits > 0.3;
	 SET transferAmount = 0;
	 START TRANSACTION;
	 OPEN credits_cur;
	 read_loop:loop
	 fetch credits_cur into vcreditsId,vmemberId,vnowCredits,vlevel,vrate;
	 #判斷遊標的循環是否結束
	 if done then
		 leave read_loop;	#跳出遊標循環
	 end if;
	 #獲取一條數據時,將count值進行累加操作,這裏可以做任意你想做的操作,
	 set transferAmount = transferAmount + 1;
	 #計算積分轉微幣數目
	 set coin = vnowCredits*vrate/100;
	 if coin >= 0.0001 THEN 
		 #查找該會員對應的微幣賬戶 並獲取微幣賬戶ID
		 select id,now_coin into coinId,nowCoin from common_coin_coin where member_id = vmemberId and account_type = accountType for update;
		 #更新微幣賬戶表
		 update common_coin_coin set now_coin = nowCoin+coin, today_increase = coin,today_decrease = 0, update_time = SYSDATE() where id = coinId ;
		 #插入微幣變更日誌
		 insert into common_coin_coin_log(coin_id, now_coin, coin, child_type, create_time, remark) VALUES (coinId,nowCoin+coin,coin,'CA',SYSDATE(),CONCAT('用戶積分轉微幣,微幣收益:',coin));
		 #修改積分賬戶
		 update common_coin_credits set now_credits = now_credits-coin, today_decrease = coin ,today_increase = 0 ,update_time = SYSDATE(),transfer_date = SYSDATE() where id = vcreditsId;
		 #記錄積分變更日誌
		 insert into common_coin_credits_log(credits_id, now_credits, credits, child_type, create_time, remark) VALUES (vcreditsId,vnowCredits-coin,-coin,'BRS',SYSDATE(),CONCAT(	'用戶積分轉微幣,積分扣減:',coin));
	   #結束遊標循環
	 else
		  ITERATE read_loop;
	 end if;
	 end loop;
		 #關閉遊標
	 close credits_cur;
	 IF @errno>0 THEN
			SELECT @errno,@errmsg;
			set transferAmount = -1;
			ROLLBACK;-- 事務回滾
	 ELSE
			SELECT 'success' as result;
			COMMIT;-- 事務提交
	 END IF;
end;

存儲過程很簡單,可以做下參考

二、Mybatis的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.common.task.dao.TransferCreditsDao">
    
    <select id="transferCredits" parameterType="java.util.Map"  statementType="CALLABLE" resultType="java.util.Map">
       {call pro_member_credits_transfer(
	    #{accountType,mode=IN,jdbcType=INTEGER},#{transferAmount,mode=OUT,jdbcType=INTEGER})}
    </select>

</mapper>

 

這裏定義執行方法,其中有幾個重要的點:

  1、parameterType 參數類型一定要爲java.util.Map類型

  2、要增加屬性 statementType="CALLABLE" 來標識這是調用存儲過程

  3、返回值類型需要定義

其他的遵從Mybatis規範即可 參數順序需要和存儲過程中的保持一直,入參用:mode=IN 來標識  出參用 mode=OUT 標識

 

三、在Service層接收返回值:

@Scheduled(cron = "1 0 2 * * ?")
    public void transferCredits(){
        Map<String, Object> map = new HashMap<>();
        map.put("accountType", Constants.ACCOUNT_TYPE_MEMBER);
        int retryCount = 0;
        try {
            transferCreditsDao.transferCredits(map);
            System.out.println("轉化總數:"+map.get("transferAmount"));
            while (Integer.valueOf(map.get("transferAmount").toString()) == -1) {
                transferCreditsDao.transferCredits(map);
                retryCount++;
                if (retryCount >=3)
                    break;
            }
        } catch (Exception e) {
            if (retryCount <3)
                transferCreditsDao.transferCredits(map);
        }
    }

這裏在執行存儲過程後 通過我們定義的入參的Map的get(key)方法來獲取對應的返回值  ,其中的key值爲我們定義的出參名。

 

下面是測試結果

{conn-10001, cstmt-20001} enter cache
[DEBUG] 2019-11-14 21:29:21,656 method:com.alibaba.druid.filter.logging.Log4jFilter.connectionLog(Log4jFilter.java:132)
{conn-10001} commited
[DEBUG] 2019-11-14 21:29:21,658 method:com.alibaba.druid.filter.logging.Log4jFilter.connectionLog(Log4jFilter.java:132)
{conn-10001} pool-recycle
轉化總數:109

到此使用使用Mybatis獲取存儲過程的出參 的流程已經走完了,有不清楚的地方歡迎留言一起討論學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章