概述
它是 spring 提供的一个对象,对原始的 JDBC 的 API 操作进行简单的封装。它更像是一个工具,和 DButils 很像,只是 Spring 不叫 util,叫 Template(模板)。
除此之外,Spring 还提供了很多的模板,例如操作关系型数据库的 HibernateTemplate,操作 NoSql 数据库的 RedisTemplate,操作消息队列的 JmsTemplate等等
下面采用的是 Maven 创建的工程
使用步骤
- 导入 Spring-jdbc 和 spring-tx 的依赖
- 创建数据库表和实体
- 创建 JdbcTemplate 对象
- 执行数据库操作。
导入依赖
<dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.19</version></dependency><dependency><groupId>c3p0</groupId><artifactId>c3p0</artifactId><version>0.9.1.2</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>5.0.2.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>RELEASE</version><scope>test</scope></dependency>
</dependencys>
其中 spring-jdbc 是 jdbcTemplate 基本支持,spring-tx 用于控制事务,spring-context 是 spring 的基本,mysql 是驱动,c3p0 是连接池,junit 使用了测试方便,这样无需写 main 函数。
创建数据库和实体
有一张 acc 表,里面有两个字段,分别为 account( varchar ) 和 age( varchar ),实体类 account 如下
public class Account {
private String account;private String age;@Overridepublic String toString() {
return "Account{" +"account='" + account + '\'' +", age='" + age + '\'' +'}';}public void setAccount(String account) {
this.account = account;}public void setAge(String age) {
this.age = age;}public String getAccount() {
return account;}public String getAge() {
return age;}
}
创建 JdbcTemplate 对象
配置数据源
因为是用在数据库上的,所以需要在 spring 的配置文件配置数据源,这里使用的 c3p0 连接池技术。
<!--配置数据源对象--><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${jdbc.drivar}"></property><property name="jdbcUrl" value="${jdbc.url}"></property><property name="user" value="${jdbc.user}"></property><property name="password" value="${jdbc.password}"></property></bean>
配置 JdbcTemplate 对象
这里配置对象,并且交给 Spring 容器管理。
<!--配置 jdbc 模板对象--><bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"></property></bean>
执行数据库的操作
插入操作
// 把 junit 的测试加给 spring,这样在每次运行测试之前,他都可以帮我们生成 spring 容器。
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class MainTestCRUD {
@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test1() throws PropertyVetoException {
int row = jdbcTemplate.update("insert into acc values(?,?)","t","18");System.out.println(row);}
}
修改操作
// 把 junit 的测试加给 spring,这样在每次运行测试之前,他都可以帮我们生成 spring 容器。
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class MainTestCRUD {
@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test2() throws PropertyVetoException {
int row = jdbcTemplate.update("update acc set age=? where account= ? ","20","tom");System.out.println(row);}
}
删除操作
// 把 junit 的测试加给 spring,这样在每次运行测试之前,他都可以帮我们生成 spring 容器。
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class MainTestCRUD {
@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test3() throws PropertyVetoException {
int row = jdbcTemplate.update("delete from acc where account=?","tom");System.out.println(row);}
}
查询操作
查询多个对象
// 把 junit 的测试加给 spring,这样在每次运行测试之前,他都可以帮我们生成 spring 容器。
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class MainTestCRUD {
@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test4() throws PropertyVetoException {
List<Account> query = jdbcTemplate.query("select * from acc", new BeanPropertyRowMapper<>(Account.class));for (Account temp:query ) {
System.out.println(query);}}
}
查询单个对象
// 把 junit 的测试加给 spring,这样在每次运行测试之前,他都可以帮我们生成 spring 容器。
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class MainTestCRUD {
@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test4() throws PropertyVetoException {
Account query = jdbcTemplate.queryForObject("select * from acc where account=? ", new BeanPropertyRowMapper<>(Account.class),"tom");System.out.println(query);}
}
查询聚合函数的结果
// 把 junit 的测试加给 spring,这样在每次运行测试之前,他都可以帮我们生成 spring 容器。
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class MainTestCRUD {
@Autowiredprivate JdbcTemplate jdbcTemplate;@Testpublic void test4() throws PropertyVetoException {
int i = jdbcTemplate.queryForObject("select count(*) from acc",Integer.class);System.out.println(i);}
}
扩展
在 JdbcTemplate 中,都是对 sql 使用占位符 ?来占位,并且在 update 或者 query 参数传参时候,都有顺序要求,如果占位符很多,顺序记不清怎么办?
Spring 还提供了一个 JdbcTemplate 的子类 NamedParameterJdbcTemplate 来解决这个问题。那么如何用?
-
把 JdbcTemplate 的 bean 配置改成如下
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"><constructor-arg ref="dataSource"></constructor-arg></bean>
-
对数据库的操作,如插入改成如下,其他的操作类似
-
修改 Sql 语句
String sql = "insert into acc values(:account,:age)";
-
添加 Map 关系
Map<String,Object> map = new HashMap<>(); map.put("account", "haha"); map.put("age", "18");
-
执行
namedParameterJdbcTemplate.update(sql, map);
-
整个代码如下
// 把 junit 的测试加给 spring,这样在每次运行测试之前,他都可以帮我们生成 spring 容器。
@RunWith(SpringJUnit4ClassRunner.class)
//指定上下文配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class MainTestCRUD {
@Autowiredprivate NamedParameterJdbcTemplate namedParameterJdbcTemplate;@Testpublic void test4() throws PropertyVetoException {
String sql = "insert into acc values(:account,:age)";Map<String,Object> map = new HashMap<>();map.put("account", "haha");map.put("age", "18");namedParameterJdbcTemplate.update(sql, map);}
}