数据库原理学习——存储过程详解

news2024/12/27 22:23:33

目录

一、什么是存储过程?

二、MySQL 中的存储过程代码演示

(一)不带参数的存储过程

(二)带参数的存储过程

三、在SpringBoot+Mybatis项目中使用过程存储

完整代码示例


一、什么是存储过程?

        存储过程(Stored Procedure)是数据库中的一种可编程对象,它是一组为了完成特定功能的SQL语句集合,存储在数据库中并以名称标识。存储过程可以接收输入参数,返回输出参数,并在服务器端运行。这种方式提高了代码的复用性和性能,因为多次执行只需要发送调用命令,而不是多次传输SQL语句。

存储过程的优点包括:

  1. 性能优化:由于存储过程在数据库端运行,减少了网络通信。
  2. 代码复用:可以定义复杂的逻辑并重复使用。
  3. 安全性:通过限制访问权限,可以防止直接访问底层表。
  4. 简化复杂性:封装复杂的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项目中使用过程存储

 详细步骤如下:

  1. 存储过程的定义 存储过程在 MySQL 数据库中定义并创建。建议使用 SQL 脚本直接在数据库中执行,而不是通过 MyBatis 的 <sql> 标签动态创建。

  2. Mapper XML 配置 在 Mapper XML 中,通过 CALLABLE 类型调用存储过程,并为输入和输出参数明确指定 jdbcType

  3. DAO 层 使用 Map 或单独参数的方式传递输入和输出参数。Map 是一种更灵活的方式。

  4. Service 层 在 Service 层封装调用逻辑,并处理业务逻辑或错误情况。

  5. 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>

具体说明

  1. jdbcType 的必要性

    • MyBatis 在处理存储过程时,对于 OUT 参数,需要知道参数的 JDBC 类型。
    • 常用的 JDBC 类型包括 INTEGERVARCHARDECIMAL 等,具体类型需要与你的存储过程输出参数的实际类型一致。
  2. mode 属性

    • IN 表示输入参数。
    • OUT 表示输出参数。
  3. 完整参数说明

    • #{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_counttotal_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_counttotal_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    
          } 
}

关键点说明

  1. 参数名与 MyBatis XML 配置一致resultMap 中的键名(如 face_collected_counttotal_count)必须与 MyBatis XML 文件中的参数名称一致。

  2. jdbcType 是必需的: 在 MyBatis 中调用存储过程时,jdbcType 是输出参数的必填项,必须与数据库字段类型匹配。

  3. Map 的使用: Map 是一种灵活的方式,用于传递输入参数和接收输出参数,适用于存储过程的复杂调用。

  4. Service 层封装逻辑: Service 层处理存储过程调用的逻辑,并将异常和错误信息统一处理,提高代码的可维护性。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2266615.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux shell脚本用于常见图片png、jpg、jpeg、webp、tiff格式批量转PDF文件

Linux Debian12基于ImageMagick图像处理工具编写shell脚本用于常见图片png、jpg、jpeg、webp、tiff格式批量转PDF文件&#xff0c;”多个图片分开生成多个PDF文件“或者“多个图片合并生成一个PDF文件” BiliBili视频链接&#xff1a; Linux shell脚本对常见图片格式批量转换…

详细介绍Sd-WebUI提示词的语法规则

AI绘画中最大的门槛就是提示词&#xff0c;对英语水平、文学水平、想象力、灵感等要求较高。不能每次一输入正向提示词&#xff08;positive prompt&#xff09;&#xff0c;就只会写a girl, big eyes, red hair。虽然sd-webui软件可以直接翻译&#xff0c;输入一个子母后会立刻…

对Python中队列三种实现方式的测试

一、结论 本程序模拟比较队列的三种情况&#xff1a; 一、deque当作队列使用&#xff1b; 二、queue当作队列使用&#xff1b; 三、list当作队列使用。 结论&#xff1a; Python队列可以用deque、queue、list实现&#xff0c;其中list极慢、queue较慢&#xf…

【VScode】第三方GPT编程工具-CodeMoss安装教程

一、CodeMoss是什么&#xff1f; CodeMoss是一款集编程、学习和办公于一体的高效工具。它兼容多种主流平台&#xff0c;包括VSCode、IDER、Chrome插件、Web和APP等&#xff0c;支持插件安装&#xff0c;尤其在VSCode和IDER上的表现尤为出色。无论你是编程新手还是资深开发者&a…

Unity中如何修改Sprite的渲染网格

首先打开SpriteEditor 选择Custom OutLine,点击Genrate 则在图片边缘会出现边缘线&#xff0c;调整白色小方块可以调整边缘 调整后&#xff0c;Sprite就会按照调整后的网格渲染了。 如何在UI中使用&#xff1f; 只要在UI的Image组件中选择Use Sprite Mesh 即可 结果&#xff1…

【机器学习】探索机器学习与人工智能:驱动未来创新的关键技术

探索机器学习与人工智能&#xff1a;驱动未来创新的关键技术 前言&#xff1a;人工智能的核心技术深度学习&#xff1a;自然语言处理&#xff08;NLP&#xff09;&#xff1a;计算机视觉&#xff1a; 机器学习与人工智能的驱动创新医疗健康领域金融行业智能制造与工业互联网智慧…

Visual Studio Code(VS Code)配置C/C++环境

一、Visual Studio Code安装 Visual Studio Code&#xff0c;下文中简称为VS Code的详细安装方法请参考VSCode安装教程&#xff08;超详细&#xff09;-CSDN博客 二、MinGW编译器下载与配置 1、MinGW介绍 MinGW(Minimalist GNU for Windows)是一款用于Windows 平台的轻…

Postman接口测试01|接口测试基础概念、http协议、RESTful风格、接口文档

目录 一、接口测试基础概念 1、什么是接口 2、接口的类型 3、什么是接口测试 4、为什么要做接口测试 5、接口测试的实现方式 6、什么是自动化接口测试&#xff1f; 二、接口返回的数据格式 1、三种格式 2、Json 三、接口协议 1、webservice协议 2、dubbo协议 3、…

HDR视频技术之十一:HEVCH.265 的 HDR 编码方案

前文我们对 HEVC 的 HDR 编码优化技术做了介绍&#xff0c;侧重编码性能的提升。 本章主要阐述 HEVC 中 HDR/WCG 相关的整体编码方案&#xff0c; 包括不同应用场景下的 HEVC 扩展编码技术。 1 背景 HDR 信号一般意味着使用更多比特&#xff0c;一般的 HDR 信号倾向于使用 10…

ThinkPHP 8开发环境安装

【图书介绍】《ThinkPHP 8高效构建Web应用》-CSDN博客 《ThinkPHP 8高效构建Web应用 夏磊 编程与应用开发丛书 清华大学出版社》【摘要 书评 试读】- 京东图书 1. 安装PHP8 Windows系统用户可以前往https://windows.php.net/downloads/releases/archives/下载PHP 8.0版本&am…

CAN201 Introduction to Networking(计算机网络)Pt.2 传输层

文章目录 3. Transport Layer&#xff08;传输层&#xff09;3.1 Multiplexing and demultiplexing&#xff08;多路复用和多路分解&#xff09;3.2 Connectionless transport&#xff1a;UDP3.3 Principles of reliable data transfer3.4 Pipelined communication3.5 TCP: con…

linux系统上SQLPLUS的重“大”发现

SQL plus版本&#xff1a; [oraclepg-xc2 ~]$ sqlplus -v SQL*Plus: Release 19.0.0.0.0 - Production Version 19.3.0.0.0 操作系统&#xff1a;CentOS Linux 7 (Core) 数据库&#xff1a;Oracle 19c Version 19.3.0.0.0 同样的SQL脚本在windos CMD sqlplus 执行没问题。…

Unity中实现人物残影效果

今天火柴人联盟3公测了&#xff0c;看到一个残影的效果&#xff0c;很有意思&#xff0c;上网查询了一下实现方式&#xff0c; 实现思路&#xff1a; 将角色的网格复制出来&#xff0c;然后放置到新建的物体的MeshFilter组件上&#xff0c;每隔几十毫秒在玩家的位置生成一个&a…

mysql mmm和mha对比

本文简单介绍MySQL的两个high availability方案&#xff0c;MMM和MHA。 MMM MMM(Master-Master replication managerfor Mysql)的基本组成如下&#xff0c; 主节点master1&#xff1a;承载写流量备主节点master2&#xff1a;replicate主节点master1的写流量&#xff0c;在主节…

探秘“香水的 ChatGPT”:AI 开启嗅觉奇幻之旅!

你没有看错&#xff0c;AI也能闻到味道了&#xff01;这是一家名为Osmo公司公布的信息&#xff0c;他们成功创造出了由AI生成的李子味道&#xff0c;快跟着小编一探究竟吧~ 【图片来源于网络&#xff0c;侵删】 Osmo公司的这项技术&#xff0c;通过分析香味的化学成分和人类嗅…

uniapp实现为微信小程序扫一扫的功能

引言 随着微信小程序的快速发展,越来越多的开发者开始关注和学习微信小程序的开发。其中,微信小程序的扫一扫功能是非常常用且实用的功能之一。通过扫描二维码,用户可以获取到相关的信息或者实现特定的功能。 正文 在过去,开发者需要使用微信开发者工具以及相关的开发文档…

网络ip地址改成什么比较好

在数字化时代&#xff0c;网络IP地址作为设备在网络中的唯一标识&#xff0c;扮演着至关重要的角色。然而&#xff0c;随着网络环境的日益复杂和网络安全问题的频发&#xff0c;许多用户开始考虑更改自己的网络IP地址&#xff0c;以期获得更好的网络体验和安全保障。那么&#…

iOS从Matter的设备认证证书中获取VID和PID

设备认证证书也叫 DAC, 相当于每个已经认证的设备的标识。包含了 VID 和 PID. VID: Vendor ID &#xff0c;标识厂商 PID: Product ID&#xff0c; 标识设备的 根据 Matter 对于设备证书的规定&#xff0c;DAC证书subject应该包含VID 和 PID. 可通过解析 X509 证书读取subject…

聊一聊 C#线程池 的线程动态注入

提高注入速度的两种方法 1. 降低GateThread的延迟时间 上一篇跟大家聊过 Result 默认情况下GateThread每秒会注入4个&#xff0c;底层逻辑是由 Blocking.MaxDelayMs250ms 变量控制的&#xff0c;言外之意就是能不能减少这个变量的值呢&#xff1f;当然可以的&#xff0c;这里我…

【嵌入式C语言】指针数组结构体

指针与数组 指针与数组指针数组数组指针 多维数组数组名的保存 结构体定义结构体定义结构体变量使用typedef简化结构体声明访问结构体成员结构体内存分配字节对齐位域定义位域位域的限制示例 指针与数组 指针数组和数组指针是两个不同的概念&#xff0c;它们涉及到指针和数组的…