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获取存储过程的出参 的流程已经走完了,有不清楚的地方欢迎留言一起讨论学习。

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