在经典的 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. 执行结果