在经典的 JDBC 用法中,SQL 参数是用占位符 ? 表示,并且受到位置的限制。定位参数的问题在于, 一旦参数的顺序发生变化,就必须改变参数绑定。在 Spring JDBC 框架中,绑定 SQL 参数的另一种选择是使用具名参数(named parameter)。
具名参数
SQL 按名称(以冒号开头)而不是按位置进行指定。
具名参数更易于维护,也提升了可读性。
具名参数由框架类在运行时用占位符取代。
具名参数只在 org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate 中得到支持,其API如下:
public int update(String sql, Map<String, ?> paramMap) throws DataAccessException
public int update(String sql, SqlParameterSource paramSource) throws DataAccessException
public int[] batchUpdate(String arg0, Map<String, ?>[] arg1)
public int[] batchUpdate(String sql, SqlParameterSource[] batchArgs)
在 SQL 语句中使用具名参数时,可以在一个 Map 中提供参数值,参数名为键。也可以使用 SqlParameterSource 参数。批量更新时可以提供 Map 或 SqlParameterSource 的数组。
示例
1. 在MySQL中添加表结构
create table user(id int(10),username varchar(100),password varchar(100));
2. 添加模型类
package xyz.huning.spring4.jdbc;
public class User {
private int id;
private String name;
private String password;
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 String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password
+ "]";
}
}
3. 添加DB配置文件
################################################### ## database configuration ## ################################################### jdbc.driverClass=com.mysql.jdbc.Driver jdbc.jdbcUrl=jdbc:mysql://localhost:3306/spring4jdbc jdbc.user=root jdbc.password=root ################################################### ## c3p0 configuration ## ################################################### c3p0.initialPoolSize=3 c3p0.minPoolSize=2 c3p0.maxPoolSize=10 c3p0.maxIdleTime=28000 c3p0.idleConnectionTestPeriod=3600
4. 添加Spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"> <context:component-scan base-package="xyz.huning.spring4.jdbc.dao"></context:component-scan> <!-- 导入资源文件 --> <context:property-placeholder location="classpath:db.properties"/> <!-- 配置 C3P0 数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="user" value="${jdbc.user}"></property> <property name="password" value="${jdbc.password}"></property> <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property> <property name="driverClass" value="${jdbc.driverClass}"></property> <property name="initialPoolSize" value="${c3p0.initialPoolSize}"></property> <property name="minPoolSize" value="${c3p0.minPoolSize}"></property> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property> <property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property> <property name="idleConnectionTestPeriod" value="${c3p0.idleConnectionTestPeriod}"></property> </bean> <!-- 配置 NamedParameterJdbcTemplate, 该对象可以使用具名参数, 其没有无参数的构造器, 所以必须为其构造器指定参数 --> <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg ref="dataSource"></constructor-arg> </bean> </beans>
5. 添加测试类
package xyz.huning.spring4.jdbc.namedparameter;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import xyz.huning.spring4.jdbc.User;
public class Main {
public static void main(String[] args) throws SQLException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("jdbc-namedparameter.xml");
/**
* 使用NamedParameterJdbcTemplate的优缺点:
* 优点:有多个参数时不用再去对应位置,直接对应参数名,便于维护,减少错误的概率
* 缺点:较为麻烦
*/
NamedParameterJdbcTemplate npJdbcTemplate = ctx.getBean("namedParameterJdbcTemplate", NamedParameterJdbcTemplate.class);
String sql = "insert into user (id,username,password) values (:id,:name,:pass)";
Map<String,Object> paramMap = new HashMap<String,Object>();
paramMap.put("id", "100");
paramMap.put("name", "BluceLi");
paramMap.put("pass", "585858");
npJdbcTemplate.update(sql, paramMap);
/**
* 批量更新
*/
@SuppressWarnings("unchecked")
Map<String,Object>[] paramMaps = new HashMap[1];
paramMaps[0] = paramMap;
npJdbcTemplate.batchUpdate(sql, paramMaps);
/**
* 对上面方法的改进
*
* 通过SqlParameterSource可以传入对象,sql中名称占位符(:id,:name,:password)必须和对象的属性名相同。
*
* 使用具名参数时,可以使用update(String sql, SqlParameterSource paramSource)方法进行更新操作
* 1. SQL语句中的参数名和类的属性一致
* 2. 使用SqlParameterSource的BeanPropertySqlParameterSource实现类作为参数
*
*/
sql = "insert into user (id,username,password) values (:id,:name,:password)";
User user = new User();
user.setId(99);
user.setName("TomQi");
user.setPassword("181818");
SqlParameterSource paramSource = new BeanPropertySqlParameterSource(user);
npJdbcTemplate.update(sql, paramSource);
/**
* 批量更新
*/
SqlParameterSource[] paramSources = new BeanPropertySqlParameterSource[1];
paramSources[0] = paramSource;
npJdbcTemplate.batchUpdate(sql, paramSources);
((ClassPathXmlApplicationContext)ctx).close();
}
}
6. 执行结果