一、概述
为了使JDBC更加易于使用,Spring在JDBC API上定义了一个抽象层,以此建立一个JDBC存取框架。
作为Spring JDBC框架的核心,JDBC模板的设计目的是为不同类型的JDBC操作提供模板方法,通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低
可以将Spring的JdbcTemplate看作是一个小型的轻量级持久化层框架,和我们之前使用过的DBUtils风格非常接近。
二、环境准备
1、导入 jar 包
① IOC 容器所需要的 jar 包
commons-logging-1.1.1.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
② JdbcTemplate 所需要的 jar 包
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
③ 数据库驱动和数据源
c3p0-0.9.5.jar
mysql-connector-java-5.1.7-bin.jar
2、连接数据库基本信息属性文件
jdbc_username=root
jdbc_password=root
jdbc_url=jdbc:mysql://localhost:3306/jdbc_template
jdbc_driverClassName=com.mysql.jdbc.Driver
initialPoolSize=30
minPoolSize=10
maxPoolSize=100
acquireIncrement=5
maxStatements=1000
maxStatementsPerConnection=10
3、在Spring配置文件中配置相关的bean
① 数据源对象
<!--引入外部配置文件-->
<context:property-placeholder location="db.properties"></context:property-placeholder>
<!--
${} :取出配置文件总的值
#{} :Spring 表达式的值
-->
<!-- 测试数据源 -->
<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>
</bean>
② JdbcTemplate 对象
<!-- Spring 提供了一个类 JdbcTemplate,我们用它操作数据库,导入 Spring 的数据库模块 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
三、持久化操作
1、增删改操作
方法:
1 2 | JdbcTemplate.update(sql) //执行 SQL 语句 JdbcTemplate.update(sql,Object... args) //执行可以赋值参数的SQL语句 |
案例:
@Test
public void testInsert() {
//插入
//jdbcTemplate.update("insert into emp values(null,'张三',23,'男')");
String sql = "insert into emp values(null,?,?,?)";
jdbcTemplate.update(sql, "李四",18,"女");
}
@Test
public void testUpdate() {
//更新
//jdbcTemplate.update("update emp set ename='王五',age=17,sex='男' where eid=1");
String sql = "update emp set ename=?,age=?,sex=? where eid=?";
jdbcTemplate.update(sql, "张三",22,"女",1);
}
@Test
public void testDelete() {
//删除
//jdbcTemplate.update("delete from emp where eid = 3");
String sql = "delete from emp where eid=?";
jdbcTemplate.update(sql, 3);
}
2、批量增删改操作
方法:
1 2 3 | JdbcTemplate.batchUpdate(sql, List<Object[]>) Object[]封装了SQL语句每一次执行时所需要的参数 List集合封装了SQL语句多次执行时的所有参数 |
案例:
@Test
public void testBatchInsert() {
//批量添加
String sql = "insert into emp values(null,?,?,?)";
List<Object[]> list = new ArrayList<>();
list.add(new Object[] {"a1",1,"男"});
list.add(new Object[] {"a2",2,"女"});
list.add(new Object[] {"a3",3,"女"});
list.add(new Object[] {"a4",4,"男"});
jdbcTemplate.batchUpdate(sql, list);
}
@Test
public void testBatchUpdate() {
//批量更新
String sql = "update emp set ename=?,age=?,sex=? where eid=?";
List<Object[]> list = new ArrayList<>();
list.add(new Object[] {"b1",11,"男",4});
list.add(new Object[] {"b2",12,"男",5});
jdbcTemplate.batchUpdate(sql, list);
}
@Test
public void testBatchDelete() {
//批量删除
String sql = "delete from emp where eid = ?";
List<Object[]> list = new ArrayList<>();
list.add(new Object[] {6});
list.add(new Object[] {7});
jdbcTemplate.batchUpdate(sql, list);
}
3、查询单行
方法:
1 2 3 | jdbcTemplate.queryForObject(sql, RowMapper)用来获取单条数据 jdbcTemplate.queryForObject(sql, new Object[]{}, RowMapper<T>)用来获取单条数据 jdbcTemplate.queryForObject(sql, RowMapper<T>, Object... args)用来获取单条数据 |
案例:
@Test
public void testQueryForObject() {
//jdbcTemplate.queryForObject(sql, RowMapper)用来获取单条数据
//jdbcTemplate.queryForObject(sql, new Object[]{} RowMapper)用来获取单条数据
//jdbcTemplate.queryForObject(sql, RowMapper, Object... args)用来获取单条数据
RowMapper<Emp> rowMapper = new BeanPropertyRowMapper<>(Emp.class); //将列名(字段名或字段名的别名)与属性名进行映射
String sql = "select eid,ename,age,sex from emp where eid=1";
Emp emp = jdbcTemplate.queryForObject(sql, rowMapper);
System.out.println(emp);
String sql2 = "select eid,ename,age,sex from emp where eid=?";
Emp emp2 = jdbcTemplate.queryForObject(sql2, new Object[] {4}, rowMapper);
System.out.println(emp2);
String sql3 = "select eid,ename,age,sex from emp where eid=?";
Emp emp3 = jdbcTemplate.queryForObject(sql3, rowMapper, 5);
System.out.println(emp3);
}
4、查询多行
方法:
1 2 3 | jdbcTemplate.query(String sql, RowMapper<T>); jdbcTemplate.query(String sql, Object[] args, RowMapper<T>); jdbcTemplate.query(String sql, RowMapper<T>, Object... args); |
RowMapper对象依然可以使用BeanPropertyRowMapper
案例:
@Test
public void testQuery() {
//查询多行记录
//jdbcTemplate.query(String sql, RowMapper<T>);
//jdbcTemplate.query(String sql, Object[] args, RowMapper<T>);
//jdbcTemplate.query(String sql, RowMapper<T>, Object... args);
RowMapper<Emp> rowMapper = new BeanPropertyRowMapper<>(Emp.class);
String sql = "select eid,ename,age,sex from emp";
List<Emp> list = jdbcTemplate.query(sql, rowMapper);
for (Emp emp : list) {
System.out.println(emp);
}
System.out.println("-----------");
String sql2 = "select eid,ename,age,sex from emp where eid > ?";
List<Emp> list2 = jdbcTemplate.query(sql2, new Object[] {2}, rowMapper);
for (Emp emp : list2) {
System.out.println(emp);
}
System.out.println("-----------");
String sql3 = "select eid,ename,age,sex from emp where eid > ?";
List<Emp> list3 = jdbcTemplate.query(sql3, rowMapper, 2);
for (Emp emp : list3) {
System.out.println(emp);
}
}
5、查询单个值
方法:
案例:
@Test
public void testQueryForSingleValue() {
//jdbcTemplate.queryForObject(sql, requiredType);
//jdbcTemplate.queryForObject(sql, requiredType, args);
String sql = "select count(*) from emp";
Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
System.out.println(count);
String sql2 = "select count(*) from emp where eid > ?";
Integer count2 = jdbcTemplate.queryForObject(sql2, Integer.class, 2);
System.out.println(count2);
}
四、使用具名参数的JdbcTemplate
1、关于具名参数
在Hibernate的HQL查询中我们体验过具名参数的使用,相对于基于位置的参数,具名参数具有更好的可维护性,在SQL语句中参数较多时可以考虑使用具名参数。
在Spring中可以通过NamedParameterJdbcTemplate类的对象使用带有具名参数的SQL语句
2、通过IOC容器创建NamedParameterJdbcTemplate对象
<!-- 配置一个具有 具名参数 供的 JdbcTemplate NamedParameterJdbcTemplate-->
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<!--使用构造器注入一个数据源-->
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
3、具名参数在SQL 语句中的格式
1 | INSERT INTO employee(emp_name, salary) VALUES(:empName, :salary) |
4、具名参数传入
① 通过 Map 对象传入
@Test
public void test8() throws Exception {
String sql = "INSERT INTO employee(emp_name, salary) VALUES(:empName, :salary)";
//将所有具名参数的值放在 map 中
HashMap<String, Object> paramMap = new HashMap<>();
paramMap.put("empName", "田七");
paramMap.put("salary", "9987.89");
namedParameterJdbcTemplate.update(sql, paramMap);
}
Map 的键是参数名,值是参数值;
② 通过 SqlParameterSource 对象传入
代码示例:
@Test
public void test() throws Exception {
String sql = "INSERT INTO employee(emp_name, salary) VALUES(:empName, :salary)";
Employee employee = new Employee();
employee.setEmpName("哈哈");
employee.setSalary(998.98);
int update = namedParameterJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(employee));
System.out.println("update = " + update);
}
bean 的属性名要与具名参数一致。
五、使用JdbcTemplate实现Dao
通过 IOC 容器自动注入:
JdbcTemplate类是线程安全的,所以可以在IOC容器中声明它的单个实例,并将这个实例注入到所有的Dao实例中。
代码示例:
@Repository
public class EmpDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public Emp getEmp(Integer id) {
}
}
六、注意
在给 SQL 赋值时,如果使用PreparedStatement给通配符赋值时,如果给赋值的是字符串类型,那它就会默认给所赋的值添加一对单引号。
示例1:
@Test
public void testDel() {
//错误的,不能通过 PreparedStatement 赋值,在批量删除,批量修改时
//调用PreparedStatement中 setString()方法时,因为字符串传到SQL语句中去自动加单引号的,所以不能使用通配符赋值
String sql = "delete from emp where eid in (?)";
String eids = "9,10,11";
jdbcTemplate.update(sql, eids); //delete from emp where eid in ('9,10,11'); //只删除eid为9的记录
//修改,使用拼接,不适用通配符赋值
String sql2 = "delete from emp where eid in (" + eids + ")";
jdbcTemplate.update(sql2);
}
示例2:
@Test
public void testSelect() {
//会使用PreparedStatement的 setString() 方法,会有单引号的拼接问题
String sql = "select * from emp where ename like '%?%'";
//如果问号处传入的 是 字符串 "a",SQL 语句就变成 :select * from emp where ename like '%'a'%' ,发生错误!!!
//修改,使用concat() 函数
String sql2 = "select * from emp where ename like concat('%', ?, '%')";
jdbcTemplate.update(sql2, "a"); // SQL 语句:select * from emp where ename like '%a%'
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· 面试官:你是如何进行SQL调优的?