一.概述
为了使JDBC更加易于使用,Spring在JDBC API上定义了一个抽象层,以此建立一个JDBC存取框架。作为Spring JDBC框架的核心,JDBC模板的设计目的是为不同类型的JDBC操作提供模板方法,通过这种方式,可以在尽可能保留灵活性的情况下,将数据库存取的工作量降到最低。
可以将Spring的JdbcTemplate看作是一个小型的轻量级持久化层框架,和我们之前使用过的DBUtils风格非常接近。
二.实验
2.1测试数据源
在之前进行Spring IOC实验时,学习了怎么连接数据连接池,现在来复习一下:
首先将有关数据库的信息写入文件jdbc.properties中:
jdbc.user=root
jdbc.password=password
jdbc.jdbcUrl=jdbc:mysql://localhost:3306/jdbc_template?serverTimezone=UTC
jdbc.driverClass=com.mysql.jdbc.Driver
然后在配置文件applicationContext中配置:
<!-- 引入外部配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<!-- 测试数据源 -->
<!--
要注意:
#{}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>
然后在测试类中获取Connection对象,对其进行操作。
1.现在我们要使用Spring 的JdbcTemplate类,首先在原来包(已导入Spring基础包和数据库池包和连接包)的基础上要导入三个包:
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
2.在配置文件applicationContext中进行配置:
<bean class="org.springframework.jdbc.core.JdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
<!-- 有一个参数的构造器 -->
</bean>
3.测试:
package com.test.test;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
public class TxTest {
ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
JdbcTemplate jdbc=ioc.getBean(JdbcTemplate.class);
@Test
public void test01() throws SQLException {
System.out.println(jdbc);
}
}
2.2 增删改
JdbcTemplate.update(String, Object...)
//对数据库中的信息进行更新
public void test02(){
String sql="UPDATE employee SET salary=? WHERE emp_id=?";
int update=jdbc.update(sql, 1300.00,5);
System.out.println("更新员工"+update);
}
2.3 批量增删改
JdbcTemplate.batchUpdate(String, List<Object[]>)
Object[]封装了SQL语句每一次执行所需要的参数。
List集合封装了SQL语句多次执行的所有参数。
/*
* 批量插入
*/
@Test
public void test03(){
String sql="INSERT INTO employee(emp_name,salary) VALUES(?,?)";
//List的长度就是SQL执行的次数
//Object[],就是每次执行要用的参数
List<Object[]> list=new ArrayList<Object[]>();
list.add(new Object[]{"张三",998.99});
list.add(new Object[]{"李四",998.99});
list.add(new Object[]{"王麻子",998.99});
int[] is=jdbc.batchUpdate(sql,list);
for(int i:is)
{
System.out.println(i);
}
}
2.4 查询
返回值不同的查询如下所示;
- 查询一条数据库记录(符合条件),封装为一个Java对象返回
JdbcTemplate.queryForObject(String, RowMapper<Department>, Object...)
- 查询多条数据库记录(符合条件),封装为List集合返回
JdbcTemplate.query(String, RowMapper<Department>, Object...)
RowMapper对象依然可以使用BeanPropertyRowMapper
- 查询一条数据库数据(符合条件)
JdbcTemplate.queryForObject(String, Class, Object...)
/*
*1. 查询符合条件的一条数据库记录,封装为一个Java对象返回
* JavaBean需要和数据库中的字段名一样,否则无法完成封装
* jdbcTemplate在方法级别进行了区分
* 查询集合:jdbcTemplate.query()
* 查询单个对象:jdbc.queryForObject
* 查询没结果报错
*
* queryForObject中有一个参数RowMapper:
* RowMapper:用于将结果集每行数据转换为需要的类型
*
*/
@Test
public void Test04(){
String sql="SELECT emp_id empId,emp_name empName,salary FROM employee WHERE emp_id=?";
//RowMapper:每一条记录和JavaBean的属性如何映射
Employee emplyoee=jdbc.queryForObject(sql,new BeanPropertyRowMapper<>(Employee.class) ,5);
System.out.println(emplyoee);
}
/*
* 2.查询符合条件多条数据库记录,封装为List集合返回
*/
@Test
public void test05(){
String sql="SELECT emp_id empId,emp_name empName,salary FROM employee WHERE salary>?";
//封装list:集合里面的元素
List<Employee> list=jdbc.query(sql,new BeanPropertyRowMapper<>(Employee.class),4000);
for(Employee emplyoee:list)
{
System.out.println(emplyoee);
}
}
/*
* 3.查询符合条件的单条数据(查询最大salary),
*
*/
@Test
public void test06(){
String sql="SELECT MAX(salary) FROM employee";
//无论是返回单个数据还是单个对象,都是调用queryForObject
//queryForObject其实支持的是标量子查询,只能传入一个基本类型的包装类的class,并返回一个基本类型对应包装类型的对象.
Double object=jdbc.queryForObject(sql, Double.class);
System.out.println(object);
}
2.5 使用带有具名参数的SQL语句插入一条记录,并以Map形式传入参数值
具名参数具有更好的维护性,在SQl语句中参数较多的时候可以考虑具名参数。在Spring中可以通过NamedParameterJdbcTemplate类的对象使用带有具名参数的SQL语句。
通过IOC容器创建NamedParameterJdbcTemplate对象:
<!-- 配置可以使用具名参数的JDBCTemplate类对象 -->
<bean
id="namedTemplate"
class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<!-- 没有无参构造器,必须传入数据源或JdbcTemplate对象 -->
<constructor-arg ref="dataSource"/>
</bean>
通过Map对象传入:
NamedParameterJdbcTemplate.update(String, Map<String, ?>)
/*
* 使用带有具名参数的SQL语句插入一条记录,并以Map形式传入参数值
* 具名参数:(具有名字的参数,参数不是占位符了,而是一个变量名)
* 语法格式: :参数名
* Spring有一个支持具名参数功能的JdbcTemplate
* 占位符参数:?的顺序千万不能乱,传入参数的时候一定要注意。
*/
@Test
public void test07(){
String sql="INSERT INTO employee(emp_name,salary) VALUES(:empName,:salary)";
Map<String,Object> paramMap=new HashMap<>();
//将所有具名参数都放在map中;
paramMap.put("empName", "周六");
paramMap.put("salary", 999);
int update=namedJdbcTemplate.update(sql, paramMap);
System.out.println(update);
}
2.6 重复实验1.5,以SqlParameterSource形式传入参数值
/*
* 重复实验7,以SqlParameterSource形式传入参数值
*/
@Test
public void test08(){
String sql="INSERT INTO employee(emp_name,salary) VALUES(:empName,:salary)";
Employee em=new Employee();
em.setEmpName("哈哈");
em.setSalary(997.90);
//
int update=namedJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(em));
System.out.println(update);
}
2.7 使用JdbcTemplate实现Dao
配置文件:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="com.test"></context:component-scan>
<!-- 引入外部配置文件 -->
<context:property-placeholder location="classpath:dbconfig.properties"/>
<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>
<bean class="org.springframework.jdbc.core.JdbcTemplate" >
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
<!-- 有一个参数的构造器 -->
</bean>
<!-- 配置一个具有具名参数功能的JdbcTemplate -->
<bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
<!-- 使用构造器方式注入数据源 -->
<constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
</bean>
</beans>
通过IOC容器自动注入:
package com.test.dao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import com.test.bean.Employee;
@Repository
public class EmployeeDao {
@Autowired
JdbcTemplate jdbcTemplate;
public void saveEmployee(Employee em)
{
String sql="INSERT INTO employee(emp_name,salary) VALUES(?,?)";
jdbcTemplate.update(sql, em.getEmpName(),em.getSalary());
}
}
测试:
/*
* 创建Dao,自动装配JdbcTemplate对象
*/
@Test
public void test09(){
EmployeeDao bean= ioc.getBean(EmployeeDao.class);
Employee em=new Employee();
em.setEmpName("哈哈");
em.setSalary(997.90);
bean.saveEmployee(em);
}
三.注意
3.1 BeanPropertyRowMapper
在之前的查询实验中,发现使用了这个参数。
使用BeanPropertyRowMapper可以将数据库查询结果转化为Java类对象。常应用于使用Spring的JdbcTemplate
查询数据库,获取List
结果列表,数据库表字段和实体类自动对应
内部实现分析:BeanPropertyRowMapper