当前位置: 首页 > article >正文

SpringBoot实战——详解JdbcTemplate操作存储过程

        对于一些复杂的业务逻辑,使用存储过程可以提高数据库操作的效率和安全性。本文将详细介绍如何在SpringBoot项目中使用 JdbcTemplate 工具操作存储过程,方便地与数据库进行交互,调用存储过程。

本文目录

    • 一、存储过程创建
    • 二、配置数据库连接
    • 三、存储过程返回单条数据
    • 四、存储过程返回多条数据

一、存储过程创建

新建一个商品表存放商品数据,并创建一个获取商品信息的存储过程。

-- 商品表
CREATE TABLE products (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    stock INT NOT NULL
);

-- 创建存储过程
DELIMITER //

CREATE PROCEDURE GetProductById(IN productId INT, OUT productName VARCHAR(255), OUT productPrice DECIMAL(10, 2), OUT productStock INT)
BEGIN
    SELECT name, price, stock INTO productName, productPrice, productStock
    FROM products
    WHERE id = productId;
END //

DELIMITER ;

参数使用 IN、OUT区分输入和输出



二、配置数据库连接

操作存储过程之前需要在 application.properties 中配置数据库连接信息:

spring.datasource.url=jdbc:mysql://localhost:3306/ecommerce
spring.datasource.username=root
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver



三、存储过程返回单条数据

接下来使用 JdbcTemplate 来调用存储过程。首先,需要创建一个 ProductRepository 类来封装数据库操作进行MVC分层,之后创建对应的Service以及Controller编写一个接口进行测试。

ProductRepository :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

import java.sql.Types;
import java.util.HashMap;
import java.util.Map;

@Repository
public class ProductRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public Map<String, Object> getProductById(int productId) {
        // 输入参数
        Map<String, Object> inParams = new HashMap<>();
        inParams.put("productId", productId);

        // 输出参数
        Map<String, Integer> outParams = new HashMap<>();
        outParams.put("productName", Types.VARCHAR);
        outParams.put("productPrice", Types.DECIMAL);
        outParams.put("productStock", Types.INTEGER);

        // 调用
        return jdbcTemplate.call(new java.util.function.Function<Connection, CallableStatement>() {
            @Override
            public CallableStatement apply(Connection con) {
                try {
                    // 准备存储过程调用
                    String callString = "{call GetProductById(?, ?, ?, ?)}";
                    CallableStatement cs = con.prepareCall(callString);
                    // 设置输入参数
                    cs.setInt(1, productId);
                    // 注册输出参数
                    cs.registerOutParameter(2, Types.VARCHAR);
                    cs.registerOutParameter(3, Types.DECIMAL);
                    cs.registerOutParameter(4, Types.INTEGER);
                    return cs;
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }, inParams, outParams);
    }
}

ProductService :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public Map<String, Object> getProductById(int productId) {
        return productRepository.getProductById(productId);
    }
}

ProductController :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/products/{productId}")
    public Map<String, Object> getProductById(@PathVariable int productId) {
        return productService.getProductById(productId);
    }
}

如上,可以看到上面的操作只能获取单条商品信息数据,如果需要获取多条还需要再优化一下。



四、存储过程返回多条数据

创建一个存储过程,用于返回价格大于某个阈值的所有商品信息。

DELIMITER //

CREATE PROCEDURE GetProductsByPriceThreshold(IN priceThreshold DECIMAL(10, 2))
BEGIN
    SELECT id, name, price, stock
    FROM products
    WHERE price > priceThreshold;
END //

DELIMITER ;

这个时候会返回多条数据,上面的Map是不适用的,这时我们需要将返回的数据封装成实体类进行操作。
Product:

public class Product {
    private int id;
    private String name;
    private double price;
    private int stock;

    public Product(int id, String name, double price, int stock) {
        this.id = id;
        this.name = name;
        this.price = price;
        this.stock = stock;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getStock() {
        return stock;
    }

    public void setStock(int stock) {
        this.stock = stock;
    }

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                '}';
    }
}

ProductRepository 类中,使用 JdbcTemplate 调用存储过程并处理结果集:
ProductRepository :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Repository
public class ProductRepository {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    public List<Product> getProductsByPriceThreshold(double priceThreshold) {
        String sql = "{call GetProductsByPriceThreshold(?)}";
        return jdbcTemplate.query(sql, new Object[]{priceThreshold}, new ProductRowMapper());
    }

    private static class ProductRowMapper implements RowMapper<Product> {
        @Override
        public Product mapRow(ResultSet rs, int rowNum) throws SQLException {
            int id = rs.getInt("id");
            String name = rs.getString("name");
            double price = rs.getDouble("price");
            int stock = rs.getInt("stock");
            return new Product(id, name, price, stock);
        }
    }
}

ProductService :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public List<Product> getProductsByPriceThreshold(double priceThreshold) {
        return productRepository.getProductsByPriceThreshold(priceThreshold);
    }
}

ProductController :

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/products/byPriceThreshold")
    public List<Product> getProductsByPriceThreshold(@RequestParam double priceThreshold) {
        return productService.getProductsByPriceThreshold(priceThreshold);
    }
}

可以看到使用用 JdbcTemplatequery 方法调用存储过程,并通过 RowMapper 可以将结果集映射为 Product 对象列表。



← 上一篇 Java进阶——常用类及常用方法详解
记得点赞、关注、收藏哦!
下一篇 Java进阶——数组超详细整理 →

http://www.kler.cn/a/611986.html

相关文章:

  • 第十六届蓝桥杯模拟二(串口通信)
  • 数据结构每日一题day3(顺序表)★★★★★
  • 国际机构Gartner发布2025年网络安全趋势
  • 微软KBLaM:当语言模型学会“查字典”的下一代AI革命
  • 信息系统安全保护等级详解
  • 一文读懂Python之json模块(33)
  • Axure RP设计软件中的各种函数:包括数字、数学、字符串、时间及中继器函数,详细解释了各函数的用途、参数及其应用场景。
  • SpringMVC请求与响应深度解析:从核心原理到高级实践
  • 吴恩达机器学习笔记复盘(十一)逻辑回归的代价和损失函数
  • 扭蛋机小程序开发,潮玩娱乐消费风口下的机遇
  • 右击没有Word、PPT、Excel功能
  • 蓝桥与力扣刷题(蓝桥 蓝桥骑士)
  • Centos 前准备工作
  • Rust vs. Go: 性能测试(2025)
  • 深入解析libsunrpc:构建分布式系统的核心RPC库
  • 考研408-数据结构完整代码 线性表的链式存储结构 - 单链表
  • 微商生态的技术重构:定制开发开源AI智能名片与S2B2C商城小程序源码的赋能逻辑
  • 登录接口带验证码自动化(tesseract-OCR)
  • Crypto Architecture Kit简介
  • DiskGenius 硬盘管理工具下载+D盘空间扩容给C盘教程