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

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: MyBatis 是一个开源的持久层框架,它可以通过映射器将 Java 程序与数据库相连,使得访问数据库变得简单和高效。在 MyBatis 中,可以通过以下步骤调用存储过程: 1. 定义存储过程的映射:在 XML 映射文件中定义存储过程的映射,其中包括存储过程的名称和参数。 2. 编写 Java 代码:通过 MyBatis 的 SqlSession 对象调用存储过程。 3. 设置存储过程参数:设置存储过程的输入和输出参数。 以下是一个简单的存储过程调用示例: ``` <select id="getUserCount" statementType="CALLABLE"> { call getUserCount(#{param1, mode=IN, jdbcType=INTEGER}) } </select> ``` ``` SqlSession sqlSession = sqlSessionFactory.openSession(); try { Map<String, Object> paramMap = new HashMap<>(); paramMap.put("param1", 1); sqlSession.selectOne("getUserCount", paramMap); } finally { sqlSession.close(); } ``` 在上面的示例中,我们通过 MyBatis 的 SqlSession 对象调用存储过程 `getUserCount`,并将参数 `1` 作为输入参数传递给该存储过程。 ### 回答2: MyBatis 是一种用于 Java 的持久层框架,它可以方便地与数据库进行交互。在 MyBatis调用存储过程可以通过以下几个步骤实现: 1. 定义存储过程的 SQL 语句:在数据库中创建一个存储过程,定义其输入参数、输出参数和执行逻辑。 2. 在 MyBatis 的 Mapper XML 文件中编写对应的 SQL 语句:使用 `<select>` 元素并设置 `statementType` 属性为 `CALLABLE`,然后编写存储过程调用语句,将输入参数和输出参数与对应的 Java 对象进行映射。 3. 在 Java 代码中调用 MyBatis 的 Mapper 接口:使用注入或动态获取 Mapper 接口对象,在需要调用存储过程的方法中调用对应的 Mapper 方法。 4. 传递参数获取存储过程的执行结果:通过调用方法时传递参数MyBatis 会将参数传递给存储过程,并获取执行结果。 需要注意的是,存储过程调用方式可能有所不同,根据具体的数据库类型和版本,可能需要在 MyBatis 的配置文件中进行一些额外的设置,以支持存储过程调用。此外,对于不同的数据库,存储过程的语法也会有所不同,需要根据目标数据库的文档进行相应的调整。 总之,使用 MyBatis 调用存储过程可以方便地与数据库进行交互,并通过参数传递和结果获取实现存储过程的数据交换。 ### 回答3: 在MyBatis调用存储过程方法需要经过以下步骤: 首先,在MyBatis的映射文件中定义一个存储过程调用语句。可以使用<select>、<insert>、<update>或<delete>标签来定义,具体取决于存储过程的操作类型。例如,我们可以使用<select>标签来调用返回结果集的存储过程。 其次,在映射文件中定义的存储过程调用语句中,使用<statementType>标签指定调用存储过程的类型。可以使用“CALLABLE”或“PREPARED”参数来指定调用方式。 然后,在调用存储过程的时候,使用MyBatis的SqlSession对象的selectOne、selectList、insert、update或delete方法来执行映射文件中的定义。 最后,在调用存储过程方法时,需要传递参数存储过程。可以使用parameterType属性来指定参数类型。如果存储过程返回值,可以使用resultType属性来指定返回结果的类型。 以下是一个示例映射文件中调用存储过程的代码片段: <select id="callProcedure" statementType="CALLABLE" resultType="Integer"> CALL my_procedure(#{param1, jdbcType=VARCHAR, mode=IN}, #{param2, jdbcType=VARCHAR, mode=INOUT}) </select> 在这个例子中,我们定义了一个调用名为"my_procedure"的存储过程的select语句。存储过程有两个参数,“param1”和“param2”,分别是传入参数和传出参数传入参数使用“mode=IN”,传出参数使用“mode=INOUT”。 使用以上的步骤,就可以在MyBatis调用存储过程方法了。希望对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值