NamedParameterJdbcTemplate是 Spring 框架中用于数据库操作的核心类之一,它拓展了JdbcTemplate,通过封装实现命名参数特性,相比传统占位符?,命名参数可读性和维护性更强,能有效避免参数顺序混淆问题。
一、核心支持类
1. SqlParameterSource 实现类
- MapSqlParameterSource:简单封装java.util.Map,可通过addValue方法添加参数,也能基于现有Map构建,如new MapSqlParameterSource(paramMap) 。
- BeanPropertySqlParameterSource:封装 JavaBean 对象,依据对象属性值为命名参数赋值,适用于参数来自对象属性的场景。
- EmptySqlParameterSource:为空的SqlParameterSource,常用于占位,如查询语句无实际参数时使用EmptySqlParameterSource.INSTANCE。
2. RowMapper 接口实现类
- SingleColumnRowMapper:用于处理单列数据查询结果,将查询结果映射为List<String>、Integer等单列数据类型。
- BeanPropertyRowMapper:可将查询结果匹配到对象,如List<XxxVO>,且会自动将数据库字段的下划线命名转换为驼峰命名属性。
二、数据库操作方法
1. 插入 / 修改 / 删除数据(update 及 batchUpdate 方法)
- 使用 Map 作为参数:通过int update(String sql, Map<String, ?> paramMap)方法,在Map中以键值对形式设置参数,键对应 SQL 语句中的命名参数,如:
Map<String, Object> paramMap = new HashMap<>(); paramMap.put("id", UUID.randomUUID().toString()); paramMap.put("name", "小明"); template.update( "insert into student(id,name) values (:id,:name)", paramMap ); |
- 使用 BeanPropertySqlParameterSource 作为参数:借助int update(String sql, SqlParameterSource paramSource),将 JavaBean 封装为BeanPropertySqlParameterSource传入,示例如下:
StudentDTO dto=new StudentDTO(); dto.setId(UUID.randomUUID().toString()); dto.setName("小红"); template.update("insert into student(id,name) values (:id,:name)", new BeanPropertySqlParameterSource(dto)); |
- 使用 MapSqlParameterSource 作为参数:同样通过int update(String sql, SqlParameterSource paramSource),可链式调用addValue添加参数,或基于现有Map构建:
MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource() .addValue("id", UUID.randomUUID().toString()) .addValue("name", "小王"); template.update("insert into student(id,name) values (:id,:name)",mapSqlParameterSource); |
2. 查询数据(query 及 queryForXXX 方法)
- 返回单行单列数据:有public < T > T queryForObject(String sql, Map<String, ?> paramMap, Class<T> requiredType)和public < T > T queryForObject(String sql, SqlParameterSource paramSource, Class<T> requiredType)两种形式,可传入Map、SqlParameterSource,如:
Integer count = template.queryForObject( "select count(*) from student", new HashMap<>(), Integer.class); |
- 返回(多行)单列数据:使用public < T> List< T> queryForList(String sql, Map<String, ?> paramMap, Class< T > elementType) 或public < T> List< T> queryForList(String sql, SqlParameterSource paramSource, Class< T> elementType) ,如:
List<String> namelist = template.queryForList("select name from student", new HashMap<>(), String.class); |
- 返回单行数据:public < T> T queryForObject(String sql, Map< String, ?> paramMap, RowMapper< T>rowMapper)和public < T> T queryForObject(String sql, SqlParameterSource paramSource, RowMapper< T> rowMapper) ,搭配RowMapper实现对象映射:
Student stu = template.queryForObject( "select * from student limit 1", new HashMap<>(), new BeanPropertyRowMapper<Student>(Student.class)); |
- 返回 Map 形式的单行数据:通过public Map< String, Object> queryForMap(String sql, Map< String, ?> paramMap)和public Map< String, Object> queryForMap(String sql, SqlParameterSource paramSource) ,将单行结果映射为Map 。
- 返回多行数据:包括public < T> List< T> query(String sql, Map< String, ?> paramMap, RowMapper< T> rowMapper)等三个重载方法,根据需求传入参数和RowMapper;public List< Map< String, Object>> queryForList(String sql, Map< String, ?> paramMap) 等方法则返回多行数据的Map集合。
三、使用建议
在实际开发中,推荐优先使用NamedParameterJdbcTemplate替代JdbcTemplate 。若仍需使用JdbcTemplate,可通过NamedParameterJdbcTemplate#getJdbcOperations()获取。同时,由于查询结果为Map的 API 在数据类型处理上存在局限性,不建议频繁使用此类 API,以免后期维护成本增加。
以上详细介绍了NamedParameterJdbcTemplate的使用方法。若你在实践中遇到问题,或希望了解某类操作的更多细节,欢迎随时与我交流。
四、完整例子
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import java.util.*;
public class NamedParameterJdbcTemplateExample {
private static NamedParameterJdbcTemplate template;
static {
// 配置数据源
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("password");
// 初始化NamedParameterJdbcTemplate
template = new NamedParameterJdbcTemplate(dataSource);
}
public static void main(String[] args) {
// 1. 插入数据 - 使用Map作为参数
insertWithMap();
// 2. 插入数据 - 使用BeanPropertySqlParameterSource作为参数
insertWithBean();
// 3. 查询单行单列数据
Integer count = getCount();
System.out.println("学生总数: " + count);
// 4. 查询多行单列数据
List<String> names = getNames();
System.out.println("所有学生姓名: " + names);
// 5. 查询单行数据
Student student = getStudent();
System.out.println("查询单个学生: " + student);
// 6. 查询多行数据
List<Student> students = getAllStudents();
System.out.println("所有学生: " + students);
// 7. 更新数据
updateStudent();
System.out.println("更新后所有学生: " + getAllStudents());
// 8. 删除数据
deleteStudent();
System.out.println("删除后所有学生: " + getAllStudents());
}
// 1. 插入数据 - 使用Map作为参数
private static void insertWithMap() {
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("id", UUID.randomUUID().toString());
paramMap.put("name", "小明");
paramMap.put("age", 33);
paramMap.put("homeAddress", "乐山");
paramMap.put("birthday", new Date());
template.update(
"insert into student(id,name,age,home_address,birthday) values (:id,:name,:age,:homeAddress,:birthday)",
paramMap
);
}
// 2. 插入数据 - 使用BeanPropertySqlParameterSource作为参数
private static void insertWithBean() {
StudentDTO dto = new StudentDTO();
dto.setId(UUID.randomUUID().toString());
dto.setName("小红");
dto.setHomeAddress("成都");
template.update(
"insert into student(id,name,home_address) values (:id,:name,:homeAddress)",
new BeanPropertySqlParameterSource(dto)
);
}
// 3. 查询单行单列数据
private static Integer getCount() {
return template.queryForObject(
"select count(*) from student",
new HashMap<>(),
Integer.class
);
}
// 4. 查询多行单列数据
private static List<String> getNames() {
return template.queryForList(
"select name from student",
new HashMap<>(),
String.class
);
}
// 5. 查询单行数据
private static Student getStudent() {
return template.queryForObject(
"select * from student limit 1",
new HashMap<>(),
new BeanPropertyRowMapper<>(Student.class)
);
}
// 6. 查询多行数据
private static List<Student> getAllStudents() {
return template.query(
"select * from student",
new BeanPropertyRowMapper<>(Student.class)
);
}
// 7. 更新数据
private static void updateStudent() {
MapSqlParameterSource params = new MapSqlParameterSource()
.addValue("age", 25)
.addValue("name", "小明");
template.update(
"update student set age = :age where name = :name",
params
);
}
// 8. 删除数据
private static void deleteStudent() {
MapSqlParameterSource params = new MapSqlParameterSource()
.addValue("name", "小明");
template.update(
"delete from student where name = :name",
params
);
}
// 学生DTO类
public static class StudentDTO {
private String id;
private String name;
private String homeAddress;
// getter和setter方法
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}
}
// 学生实体类
public static class Student {
private String id;
private String name;
private Integer age;
private String homeAddress;
private Date birthday;
// getter和setter方法
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getHomeAddress() {
return homeAddress;
}
public void setHomeAddress(String homeAddress) {
this.homeAddress = homeAddress;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Student{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", age=" + age +
", homeAddress='" + homeAddress + '\'' +
", birthday=" + birthday +
'}';
}
}
}