马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
一、什么是存储过程?
二、MySQL 中的存储过程代码演示
(一)不带参数的存储过程
(二)带参数的存储过程
三、在SpringBoot+Mybatis项目中利用过程存储
完备代码示例
一、什么是存储过程?
存储过程(Stored Procedure)是数据库中的一种可编程对象,它是一组为了完成特定功能的SQL语句聚集,存储在数据库中并以名称标识。存储过程可以吸收输入参数,返回输出参数,并在服务器端运行。这种方式进步了代码的复用性和性能,由于多次实行只必要发送调用下令,而不是多次传输SQL语句。
存储过程的长处包罗:
- 性能优化:由于存储过程在数据库端运行,镌汰了网络通讯。
- 代码复用:可以界说复杂的逻辑并重复利用。
- 安全性:通过限定访问权限,可以防止直接访问底层表。
- 简化复杂性:封装复杂的SQL逻辑,进步代码的可读性。
二、MySQL 中的存储过程代码演示
下面是一个完备的存储过程创建、调用和删除的示例:
(一)不带参数的存储过程
1. 创建示例数据库和表
- CREATE DATABASE IF NOT EXISTS example_db;
- USE example_db;
- CREATE TABLE employees (
- id INT AUTO_INCREMENT PRIMARY KEY,
- name VARCHAR(100),
- salary DECIMAL(10, 2),
- department VARCHAR(50)
- );
- -- 插入一些测试数据
- INSERT INTO employees (name, salary, department)
- VALUES
- ('Alice', 5000.00, 'HR'),
- ('Bob', 7000.00, 'IT'),
- ('Charlie', 6500.00, 'Finance');
复制代码 2. 创建存储过程
需求:创建一个存储过程,目的是,根据部门名称查询员工信息。
- DELIMITER $$
- CREATE PROCEDURE GetEmployeesByDepartment(
- IN dept_name VARCHAR(50) -- 输入参数,部门名称
- )
- BEGIN
- -- 查询指定部门的员工
- SELECT id, name, salary, department
- FROM employees
- WHERE department = dept_name;
- END $$
- DELIMITER ;
复制代码 阐明:
- DELIMITER $$:更改语句竣事符,防止存储过程界说中的分号辩论。
- IN dept_name VARCHAR(50):界说输入参数
- CALL GetEmployeesByDepartment('IT');
复制代码 ,表现调用时必要提供部门名称。
- SELECT ...:存储过程的主体逻辑。
3. 调用存储过程
利用 CALL 关键字调用存储过程。
- CALL GetEmployeesByDepartment('IT');
复制代码 输出示例:
- +----+------+--------+------------+
- | id | name | salary | department |
- +----+------+--------+------------+
- | 2 | Bob | 7000.00| IT |
- +----+------+--------+------------+
复制代码 (二)带参数的存储过程
需求:盘算某个部门的员工匀称工资,并通过输出参数返回。
- DELIMITER $$
- CREATE PROCEDURE GetAverageSalaryByDepartment(
- IN dept_name VARCHAR(50), -- 输入参数
- OUT avg_salary DECIMAL(10, 2) -- 输出参数
- )
- BEGIN
- -- 计算平均工资
- SELECT AVG(salary) INTO avg_salary
- FROM employees
- WHERE department = dept_name;
- END $$
- DELIMITER ;
复制代码 调用存储过程并获取效果:
- SET @avg_salary = 0; -- 定义变量
- CALL GetAverageSalaryByDepartment('HR', @avg_salary);
- SELECT @avg_salary AS AverageSalary; -- 查看结果
复制代码 输出示例:
- +---------------+
- | AverageSalary |
- +---------------+
- | 5000.00 |
- +---------------+
复制代码 5. 删除存储过程
如果必要删除存储过程,可以利用 DROP PROCEDURE 语句。
- DROP PROCEDURE IF EXISTS GetEmployeesByDepartment;
- DROP PROCEDURE IF EXISTS GetAverageSalaryByDepartment;
复制代码 总结
存储过程是数据库中一个强大的工具,它封装了复杂的业务逻辑,进步了性能和代码复用性。MySQL 的存储过程支持输入参数、输出参数和逻辑控制语句,可以满意多种业务需求。在计划存储过程时必要注意性能优化和安全性,克制过分复杂化导致难以维护。
三、在SpringBoot+Mybatis项目中利用过程存储
具体步调如下:
- 存储过程的界说 存储过程在 MySQL 数据库中界说并创建。发起利用 SQL 脚本直接在数据库中实行,而不是通过 MyBatis 的 <sql> 标签动态创建。
- Mapper XML 设置 在 Mapper XML 中,通过 CALLABLE 范例调用存储过程,并为输入和输出参数明确指定 jdbcType。
- DAO 层 利用 Map 或单独参数的方式转达输入和输出参数。Map 是一种更机动的方式。
- Service 层 在 Service 层封装调用逻辑,并处置处罚业务逻辑或错误环境。
- Controller 层 吸收前端哀求并调用 Service 层,将效果返回给前端。
完备代码示例
1. 存储过程界说
存储过程必要直接在数据库中创建:
- DELIMITER $$
- CREATE PROCEDURE GetFaceCollectedCount(
- IN input_community_id INT, -- 输入参数:社区ID
- OUT face_collected_count INT, -- 输出参数:已采集人脸的居民人数
- OUT total_count INT -- 输出参数:社区居民人数
- )
- BEGIN
- -- 查询社区居民总人数
- SELECT COUNT(*) INTO total_count
- FROM person
- WHERE community_id = input_community_id;
- -- 查询已采集人脸的居民人数
- SELECT COUNT(*) INTO face_collected_count
- FROM person
- WHERE community_id = input_community_id AND state = 2;
- END $$
- DELIMITER ;
复制代码 代码寄义:
- 输入参数 input_community_id:指定目的社区的 ID。
- 输出参数 total_count:存储该社区中住民的总人数。
- 输出参数 face_collected_count:存储该社区中已缴收罗人脸信息的住民人数。
- 逻辑:
- 第一部门统计符合条件的总人数,并赋值给 total_count。
- 第二部门统计符合条件且 state = 2 的人数(表现人脸收罗已完成的住民)。
作用:这是在数据库层界说的逻辑,用于处置处罚社区干体系计。
2. Mapper XML 设置
设置用于调用‘存储过程’的sql语句:
注意 statementType="CALLABLE" 是必须的,否则 MyBatis 无法准确调用存储过程。
- <?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.mapper.CommunityMapper">
- <!-- 调用存储过程 -->
- <select id="getFaceCollectedCount" statementType="CALLABLE">
- CALL GetFaceCollectedCount(
- #{input_community_id, mode=IN, jdbcType=INTEGER},
- #{face_collected_count, mode=OUT, jdbcType=INTEGER},
- #{total_count, mode=OUT, jdbcType=INTEGER}
- )
- </select>
- </mapper>
复制代码 具体阐明
- jdbcType 的须要性:
- MyBatis 在处置处罚存储过程时,对于 OUT 参数,必要知道参数的 JDBC 范例。
- 常用的 JDBC 范例包罗 INTEGER、VARCHAR、DECIMAL 等,具体范例必要与你的存储过程输出参数的现实范例同等。
- mode 属性:
- 完备参数阐明:
- #{input_community_id, mode=IN, jdbcType=INTEGER}:指定输入参数的 JDBC 范例。
- #{face_collected_count, mode=OUT, jdbcType=INTEGER}:指定输出参数 face_collected_count 的 JDBC 范例。
- #{total_count, mode=OUT, jdbcType=INTEGER}:指定输出参数 total_count 的 JDBC 范例。
3. DAO 接口
界说 Mapper 接口:
- package com.example.mapper;
- import java.util.Map;
- public interface CommunityMapper {
- /**
- * 调用存储过程获取人脸采集和总人数
- *
- * @param resultMap 包含输入参数和输出参数的 Map
- */
- void getFaceCollectedCount(Map<String, Integer> resultMap);
- }
复制代码 代码寄义:
- 参数:
- 利用 Map<String, Integer> 作为输入和输出容器。
- resultMap 中包罗输入参数(如 input_community_id)和输出参数(如 face_collected_count 和 total_count)。
- Map 的作用:
- MyBatis 会通过 Map 的键名找到与存储过程占位符相对应的参数。
- 输入参数会从 Map 中读取,存储过程的输出参数会写回到 Map 中。
作用:界说存储过程的调用方法,供 Service 层利用。
4. Service 层
封装存储过程的调用逻辑:
- package com.example.service;
- import com.example.mapper.CommunityMapper;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.HashMap;
- import java.util.Map;
- @Service
- public class CommunityService {
- @Autowired
- private CommunityMapper communityMapper;
- /**
- * 调用存储过程
- *
- * @param communityId 社区ID
- * @return 存储过程返回的数据
- */
- public Map<String, Integer> getFaceCollectedCount(int communityId) {
- // 创建 Map 用于存储输入和输出参数
- Map<String, Integer> resultMap = new HashMap<>();
- resultMap.put("input_community_id", communityId); // 输入参数
- resultMap.put("face_collected_count", null); // 初始化输出参数
- resultMap.put("total_count", null);
- // 调用存储过程
- communityMapper.getFaceCollectedCount(resultMap);
- return resultMap;
- }
- }
复制代码 getFaceCollectedCount()方法的寄义:
- 输入:参数 communityId是前端传入的社区 ID。
- 逻辑:
- 创建 resultMap,初始化输入参数(input_community_id)和输出参数(face_collected_count、total_count)。
- 调用 Mapper 的 getFaceCollectedCount 方法,实行存储过程,resultMap 会更新输出参数的值。
- 输出:返回包罗存储过程效果的 Map。
作用:封装业务逻辑,为 Controller 层提供服务。
5. Controller 层
处置处罚前端哀求并返回效果:
- package com.example.controller;
- import com.example.service.CommunityService;
- import com.example.utils.Result;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.*;
- import java.util.Map;
- @RestController
- @RequestMapping("/community")
- public class CommunityController {
- @Autowired
- private CommunityService communityService;
- /**
- * 调用存储过程
- *
- * @param id 前端传入的社区ID数组
- * @return 存储过程的返回结果
- */
- @PostMapping("/procedure")
- public Result procedure(@RequestBody Integer[] id) {
- int communityId = id[0];
- System.out.println("Community ID: " + communityId);
- Map<String, Integer> resMap = communityService.getFaceCollectedCount(communityId);
- if (resMap.get("face_collected_count") == null || resMap.get("total_count") == null) {
- return Result.error("存储过程调用失败");
- }
- return Result.ok().put("data", resMap);
- }
- }
复制代码
6. 前端哀求示例
返回示例:
- {
- "code": 200,
- "message": "成功",
- "data":
- {
- "face_collected_count": 10,
- "total_count": 50
- }
- }
复制代码 关键点阐明
- 参数名与 MyBatis XML 设置同等: resultMap 中的键名(如 face_collected_count 和 total_count)必须与 MyBatis XML 文件中的参数名称同等。
- jdbcType 是必须的: 在 MyBatis 中调用存储过程时,jdbcType 是输出参数的必填项,必须与数据库字段范例匹配。
- Map 的利用: Map 是一种机动的方式,用于转达输入参数和吸收输出参数,实用于存储过程的复杂调用。
- Service 层封装逻辑: Service 层处置处罚存储过程调用的逻辑,并将非常和错误信息同一处置处罚,进步代码的可维护性。
|