Mysql存储过程调用

项目结构:

准备数据

CREATE TABLE `demo_entity` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  `age` bigint(20) DEFAULT '0',
  `cdate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `udate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

1、存储过程的调用
存储过程主要返回三类

1、返回数值的存储过程,其执行完后返回一个值,例如数据库中执行一个有返回值的函数或命令。
2、返回记录集的存储过程:执行结果是一个记录集,例如,从数据库中检索出符合某一个或几个条件的记录。
3、行为存储过程,用来实现数据库的某个功能,而没有返回值,例如在数据库中的更新和删除操作。
1、接收一个返回值
1.1、创建存储过程
1.2、返回out变量

DROP PROCEDURE IF EXISTS pro;
CREATE PROCEDURE pro (
  IN userId INT,
  OUT userCount INT
)
  BEGIN
    DECLARE user_name VARCHAR (64);
    #SELECT d.name FROM demo_entity d WHERE d.id = userId INTO user_name;
    #INSERT INTO demo_entity (name) VALUES (user_name);
    SELECT COUNT(*) FROM demo_entity INTO userCount;
end;

call pro(1,@userCount);
select @userCount ;

1.2、返回集合和out变量

DROP PROCEDURE IF EXISTS pro_one_list;
CREATE PROCEDURE pro_one_list (
  IN p_name varchar(20),
  OUT userCount INT
)
  BEGIN
    select count(*) from demo_entity d where d.name = p_name into userCount ;
    SELECT * FROM demo_entity d  where  d.name = p_name;
  end;


call pro_one_list('小芳',@userCount);
select @userCount ;

1.3、返回多列集合和变量

drop procedure IF EXISTS pro_many_list ;
CREATE PROCEDURE pro_many_list (
  IN one_name varchar(20),
  IN two_name varchar(20),
  OUT userCount INT
)
  BEGIN
    select count(*) from demo_entity d where d.name = one_name into userCount ;
    SELECT d.* FROM demo_entity d  where  d.name = one_name;
    SELECT e.* FROM demo_entity e  where  e.name = two_name;
  end;


call pro_many_list('小芳','小小芳',@userCount);
select @userCount ;

2、mybatis xml 配置

out 中必须制定jdbc类型,因为存储过程会对它进行赋值操作

<?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.example.cache.mapper.DemoEntityMapper">




    <!--out 中必须制定jdbc类型,因为存储过程会对它进行赋值操作-->
    <select id="procedureGetOut" parameterType="java.util.Map" statementType="CALLABLE" >
      call pro (
              #{userId,   mode=IN},
              #{userCount,mode=OUT,jdbcType=INTEGER}
      )
  </select>



    <select id="procedureGetOneList" parameterType="java.util.Map" statementType="CALLABLE" resultType="com.example.cache.entity.DemoEntity" >
      call pro_one_list (
              #{userName, mode=IN},
              #{userCount,mode=OUT,jdbcType=INTEGER}
      )
  </select>




    <resultMap id="twoList" type="com.example.cache.entity.DemoEntity">
        <result column="id" property="id"></result>
        <result column="name" property="name"></result>
    </resultMap>

    <resultMap id="oneList" type="com.example.cache.entity.DemoEntity">
        <result column="id" property="id"></result>
        <result column="name" property="name"></result>
    </resultMap>

    <!--resultMap中会提示报错,但是实际上启动项目不会报错-->
    <select id="procedureGetManyList" parameterType="java.util.Map" statementType="CALLABLE" resultMap="oneList,twoList">
      call pro_many_list (
              #{oneName, mode=IN},
              #{twoName, mode=IN},
              #{userCount,mode=OUT,jdbcType=INTEGER}
      )
   </select>


</mapper>

3、mapper接口

@Mapper
public interface DemoEntityMapper {

    /**
     * 1、获取 存储过程out参数值
     * @param map
     * @return
     */
    void procedureGetOut(Map map);


    /**
     * 2、获取 存储过程的结果集合-只有一个
     * @param map
     * @return
     */
    List<DemoEntity> procedureGetOneList(Map map) ;



    /**
     * 3、获取 存储过程的 获取多个集合 使用了泛型,有可能集合中是不同的
     * @param
     * @return
     */
    List<List<?>> procedureGetManyList(Map map);

}

4、业务层

@Service
public class ProcedureServiceImpl implements IProcedureService {
    @Autowired
    DemoEntityMapper demoEntityMapper;

    @Override
    public Integer procedureGetOut(Long id) {
        Map<String, Object> param = new HashMap<>();
        param.put("userId", id) ;
        //执行完存储过程会自动更新这个map值
        demoEntityMapper.procedureGetOut(param);
        return Integer.valueOf(param.get("userCount").toString());
    }


    /**
     * 2、获取 存储过程的结果集合-只有一个
     * @param name
     * @return
     */
    @Override
    public List<DemoEntity> procedureGetOneList(String name) {
        Map<String, Object> param = new HashMap<>();
        param.put("userName", name) ;

        //获取结果集
        List<DemoEntity> list  = demoEntityMapper.procedureGetOneList(param);
        System.out.println(Integer.valueOf(param.get("userCount").toString()));

        return list;
    }

    /**
     * 3、获取 存储过程的 获取多个集合 使用了泛型,有可能集合中是不同的
     * @param
     * @return
     */
    @Override
    public List<List<?>> procedureGetManyList(String oneName, String twoName) {
        Map<String, Object> param = new HashMap<>();
        param.put("oneName", oneName) ;
        param.put("twoName", twoName) ;
        List<List<?>> lists =   demoEntityMapper.procedureGetManyList(param) ;
        System.out.println("数组大小"+lists.size());
        System.out.println("某个数量"+Integer.valueOf(param.get("userCount").toString()));
        return lists;
    }
}

5、控制层

@RestController
@RequestMapping("/procedure")
public class ProcedureController {
    @Autowired
    IProcedureService procedureService;

    @GetMapping("/procedureGetOut")
    @ResponseBody
    public String  procedureGetOut(Long id){
        Integer integer = procedureService.procedureGetOut(id);
        return String.valueOf(integer);
    }

    /**
     * @Author
     * @Description //TODO 获取返回结果集
     * @Date
     * @Param
     * @return
     **/
    @GetMapping("procedureGetOneList")
    @ResponseBody
    public List<?> procedureGetOneList(String name){
        return procedureService.procedureGetOneList(name);
    }


    /**
     * @Author
     * @Description //TODO 获取返回结果集(多个)
     * @Date
     * @Param
     * @return
     **/
    @GetMapping("procedureGetManyList")
    @ResponseBody
    public List<?> procedureGetManyList(String oneName,String twoName){
        return procedureService.procedureGetManyList(oneName,twoName);
    }

}

6、application.properties配置文件

server.port=9090
spring.datasource.url=jdbc:mysql://localhost:3306/procedure
spring.datasource.username=root
spring.datasource.password=root
#数据库驱动
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# 打开驼峰命名规则
mybatis.configuration.map-underscore-to-camel-case=true
# classpath和classpath*的区别
#classpath:只会到你的class路径中查找找文件。
#classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找。
#注意: 用classpath*:需要遍历所有的classpath,所以加载速度是很慢的;因此,在规划的时候,应该尽可能规划好资源文件所在的路径,尽量避免使用classpath*。
#接口的配置文件的位置-映射用
mybatis.mapper-locations=classpath*:com/example/cache/mapper/xml/*Mapper.xml

# mapper包下打印日志
logging.level.com.example.cache.mapper=debug


spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=''


#debug=true

7、pom文件依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

调用回报错:

报错问题:
mapper绑定异常 nested exception is org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): xxx.xxxx.mapper.UserMapper.getAllUser] with root cause

背景:

mapper接口和**mapper.xml映射文件**在同一个包下。

在看到 **Invalid bound statement (not found)**后,提示未找到mapper映射文件,然后打开编译后的target包或生成的jar包后,找到mapper映射文件存放位置,发现编译后的jar包内并没有此映射文件,进而将问题指向到Maven编译的过程中没有将普通配置文件编译进jar包内。

报错原因:

​ 由于我把mapper映射文件放在mapper接口的同一包里,并没有放在resources目录下,导致通过Maven编译后没有把除Java以外的映射文件、配置文件编译到target和jar包内,在运行时,调用mapper映射文件时,发现在同一个目录下没有找到mapper映射文件而报错。

​ 我们知道Maven是根据pom.xml执行任务,其中build标签描述了如何来编译及打包项目,而具体的编译和打包工作是通过build中配置的 plugin 来完成。而对于resources目录下资源,往往不是代码(.properties或XML配置文件),无需编译,所以在构建过程中往往会将资源文件从源路径直接复制到指定的目标路径。

​ src/main/java和src/test/java这两个目录中的所有*.java文件会分别在comile和test-comiple阶段被编译,编译结果分别放到了target/classes和targe/test-classes目录中,但是这两个目录中的其他文件都会被忽略掉。

解决办法:

需要在你的项目的pom文件中添加一下配置

<build>
        <resources>
        <!-- 解决mapper绑定异常 -->
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.yml</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <!-- 解决未找到数据源等配置异常 -->
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.yml</include>
                <include>**/*.properties</include>
            </includes>
        </resource>
    </resources>
</build>

猜你喜欢

转载自blog.csdn.net/weixin_43695211/article/details/127883536