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);
}
}
可以看到使用用
JdbcTemplate
的query
方法调用存储过程,并通过RowMapper
可以将结果集映射为Product
对象列表。
← 上一篇 Java进阶——常用类及常用方法详解 |
记得点赞、关注、收藏哦!
| 下一篇 Java进阶——数组超详细整理 → |