在这个Spring JDBC 教程中,我将与您分享如何使用Spring SimpleJdbcCall类来调用存储过程并在数据库中执行函数。您将看到Spring如何简化您需要编写的代码,而不是使用普通的JDBC代码来调用存储过程。假设我们有一个声明如下的数据源:
DriverManagerDataSource dataSource = new DriverManagerDataSource();;
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/dbname");
dataSource.setUsername("root");
dataSource.setPassword("password");
基本上,以下是在Spring 使用SimpleJdbcCall数据库存储过程的步骤:
1. 创建一个新实例 SimpleJdbcCall 并指定过程的名称:
SimpleJdbcCall actor = new SimpleJdbcCall(dataSource).withProcedureName("name");
2. 如果过程需要,请指定一些 IN 参数:
SqlParameterSource params = new MapSqlParameterSource();
params.addValue("in_param_1", "value1")
.addValue("in_param_2", "value2");
3. 执行该过程并将 OUT 参数的值获取到 Map 中:
Map<String, Object> out = actor.execute(params);
4. 读出从过程中返回的值:
String value1 = (String) out.get("out_param_1");
Integer value2 = (Integer) out.get("out_param_2");
请注意,IN 和 OUT 参数的名称必须与存储过程/函数声明的名称匹配。
现在,让我们看一些具体的例子。
1. 使用SimpleJdbcCall具有输入和输出参数的存储过程
假设我们在MySQL数据库中有一个名为contact的表,结构如下:
CREATE TABLE IF NOT EXISTS `contact` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
`email` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
`address` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
`telephone` varchar(45) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
)
假设我们在MySQL数据库中有一个名为get_contact的存储过程,声明如下:
DELIMITER //
CREATE PROCEDURE `get_contact`(IN contact_id INTEGER,
OUT _name varchar(45),
OUT _email varchar(45),
OUT _address varchar(45),
OUT _phone varchar(45))
BEGIN
SELECT name, email, address, telephone
INTO _name, _email, _address, _phone
FROM Contact WHERE id = contact_id;
END
//
DELIMITER ;
请注意,此存储过程具有一个 IN 参数 contact_id 和 4 个 OUT 参数_name、_email、_address和_phone。下面的代码段说明了如何使用SimpleJdbcCall来调用该存储过程:
int contactId = 10;
SimpleJdbcCall actor = new SimpleJdbcCall(dataSource).withProcedureName("get_contact");
SqlParameterSource inParams = new MapSqlParameterSource().addValue("contact_id", contactId);
Map<String, Object> outParams = actor.execute(inParams);
String name = (String) outParams.get("_name");
String email = (String) outParams.get("_email");
String address = (String) outParams.get("_address");
String phone = (String) outParams.get("_phone");
System.out.println(name + ", " + email + ", " + address + ", " + phone);
如果只有一个 IN 参数,则可以将值直接传递给 execute() 方法,如下所示:
Map<String, Object> out = simpleJdbcCall.execute(10);
2. 使用SimpleJdbcCall返回结果集的存储过程
假设我们有一个存储过程,它从表中返回行,如下所示:
CREATE PROCEDURE `list_contact`()
BEGIN
SELECT * FROM Contact ORDER BY name ASC;
END
下面的代码示例演示如何调用此存储过程并读取结果:
SimpleJdbcCall procedureActor = new SimpleJdbcCall(dataSource)
.withProcedureName("list_contact")
.returningResultSet("contacts", new RowMapper<Contact>() {
@Override
public Contact mapRow(ResultSet rs, int rowNum) throws SQLException {
Contact contact = new Contact();
contact.setId(rs.getInt("id"));
contact.setName(rs.getString("name"));
contact.setEmail(rs.getString("email"));
contact.setAddress(rs.getString("address"));
contact.setTelephone(rs.getString("telephone"));
return contact;
}
});
Map<String, Object> out = procedureActor.execute();
List<Contact> listContacts = (List<Contact>) out.get("contacts");
如您所见,我们用两个参数调用
返回ResultSet()方法:第一个参数是返回的Map中键的名称,我们将使用它来读取结果。第二个是
行映射器,用于直接读取结果集。如果您有一个域类,其中包含的字段名称与数据库表中的列名完全匹配,则可以使用
BeanPropertyRowMapper 类来简化代码,如下所示:
SimpleJdbcCall procedureActor = new SimpleJdbcCall(dataSource)
.withProcedureName("list_contact")
.returningResultSet("contacts", BeanPropertyRowMapper.newInstance(Contact.class));
Map<String, Object> out = procedureActor.execute();
List<Contact> listContacts = (List<Contact>) out.get("contacts");
Contact
类的代码如下所示:
public class Contact {
private Integer id;
private String name;
private String email;
private String address;
private String telephone;
// getters...
// setters...
}
3. 使用SimpleJdbcCall来执行函数
假设我们在数据库中有一个函数,声明如下:
CREATE FUNCTION `calculate_book_rating`(book_title varchar(128)) RETURNS double
READS SQL DATA
BEGIN
DECLARE out_value DOUBLE;
SELECT AVG(r.rating) AS AvgRating FROM Review r JOIN Book b
ON r.book_id = b.book_id AND b.title = book_title
INTO out_value;
RETURN out_value;
END
此函数有一个名为 book_title的参数,它返回双精度值。下面的代码示例演示如何在春季使用SimpleJdbcCall来执行此函数:
SimpleJdbcCall procedureActor = new SimpleJdbcCall(dataSource)
.withFunctionName("calculate_book_rating");
String bookTitle = "Effective Java (3rd Edition)";
Double rating = procedureActor.executeFunction(Double.class, bookTitle);
这就是如何在春季使用SimpleJdbcCall
l类来调用存储过程并执行函数。