经过JDBC(一)、(二),对JDBC原理和使用都有了比较清晰的认识。JDBC(三)就总结一个JDBC的简单封装的工具类JDBCTemplate,它是Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象简化JDBC的程序开发步骤。
1.为什么使用JDBCTemplate
JDBC数据库连接池已经能够满足大部分用户最基本的需求,但我们在使用JDBC开发时,必须自己来管理数据库资源如:获取PreparedStatement,设置SQL语句参数,关闭连接等常规步骤。
而JdbcTemplate是Spring对JDBC的封装,目的是使JDBC更加易于使用。提供的JdbcTemplate类已经处理了资源的建立和释放,帮助我们避免一些常见的错误,比如忘了总要关闭连接。它是运行核心的JDBC工作流,如Statement的建立和执行,而我们只需要提供想要执行SQL语句和提取SQL处理结果。它还能将查询的结果自动封装指定的数据类型,极大提高了我们的开发效率;
2.JDBCTemplate基本使用步骤
这里先说一下使用JdbcTemplate步骤,非常的简单,关键的是中间三个步骤:
1.导入jar包
2.创建JdbcTemplate对象
3.定义sql语句
4.调用JdbcTemplate里面的方法执行sql语句
5.处理结果
步骤1:导入jar包(所用jar包资源在文末分享)
导入JdbcTemplate依赖的jar包,因为是Spring框架提供的,想要使用需要导入下面4个包:
1.spring-beans-5.0.0.RELEASE.jar
2.spring-core-5.0.0.RELEASE.jar
3.spring-jdbc-5.0.0.RELEASE.jar
4.spring-tx-5.0.0.RELEASE.jar
5.commons.logging-1.2.jar
当然还需要导入电脑上对应数据库的驱动程序Jar包,本文中使用的是Mysql,步骤2中创建JdbcTemplate对象时,还要给它传入一个数据库连接池对象,所以要有数据库连接池对应的Jar包。
1.mysql-connector-java-5.1.37-bin.jar
2.druid-1.0.9.jar
步骤2:创建JdbcTemplate对象
创建JdbcTemplate对象,方便执行SQL语句,使用的构造方法:
//JdbcTemplate构造方法
public JdbcTemplate(DataSource dataSource)
//创建一个JdbcTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
创建JdbcTemplate对象时,还要给它传入一个数据库连接池对象,这里使用的是Druid连接池、和Druid的工具类JDBCUtils都在上一篇文章有详细描述:JDBC(二):数据库连接池(C3P0、Druid),后面贴出JDBCUtils工具类。
步骤3:定义sql语句
拼接SQL语句,SQL中的参数建议通过占位符?,来代替SQL语句中给定的参数值。好处在文章:JDBC(一):基础有详细提到。
步骤4:调用JdbcTemplate里面的方法执行sql语句
在JdbcTemplate中执行SQL语句的方法大致分为3类:
1.execute
:可以执行所有SQL语句,一般用于执行DDL语句。
2.update
:用于执行insert、update、delete等DML语句。
3.queryXxx
:用于DQL数据查询语句。
execute方法,数据库创建、表、列字段创建删改等操作很少在JDBC程序中进行,不多说。主要总结下JdbcTemplate 常用查询数据库的方法:
- queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作为value 将这条记录封装为一个map集合
* 注意:这个方法查询的结果集长度只能是1,即只能查询一条记录
- queryForList():查询结果,并将结果集封装为list集合
* 注意:将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
- query():查询结果,将结果封装为JavaBean对象
* query的参数:RowMapper接口
* 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
* new BeanPropertyRowMapper<类型>(类型.class)
- queryForObject():查询结果,将结果封装为对象
* 一般用于聚合函数的查询
上面只是大致说了方法的,方法参数没有给出,下面是方法详情:
public long queryForLong(String sql)
:执行查询语句,返回查询到的一个long类型的数据。还有很多返回不同数据类型的方法。public Map<String, Object> queryForMap(String sql)
:执行查询语句,只能将一条记录放到一个Map中。public List<Map<String, Object>> queryForList(String sql)
:执行查询语句,将结果集封装为List集合,注意:是将每一条记录封装为一个Map集合,再将Map集合装载到List集合中public <T> List<T> query(String sql, RowMapper<T> rowMapper)
:执行查询语句,返回一个List集合,List中存放的是RowMapper接口指定类型的数据。我们一般不用RowMapper接口,而是用RowMapper的实现类BeanPropertyRowMapper,将数据自动封装,代码更加简洁。
public class BeanPropertyRowMapper<T> implements RowMapper<T>
:BeanPropertyRowMapper类实现了RowMapper接口public <T> T queryForObject(String sql, Class<T> requiredType)
:执行查询语句,返回一个指定类型的数据。
步骤5:处理执行SQL得到的结果
进行自己的处理逻辑。
Druid连接池配置文件、和Druid的工具类JDBCUtils
druid.properties
# 加载数据库驱动
driverClassName=com.mysql.jdbc.Driver
# 连接数据库的url,db1表示数据库名,useSSL=false表示不使用SSL规范
url=jdbc:mysql://127.0.0.1:3306/db1?useSSL=false&characterEncoding=UTF-8
# 用户登录数据库的账号和密码
username=root
password=123456
# 初始化连接数量
initialSize=5
# 最大连接数量
maxActive=10
# 最大等待时间
maxWait=3000
/**
* Druid连接池的工具类
*/
public class JDBCUtils {
//1.定义成员变量DataSource
private static DataSource ds;
static {
try {
//1.加载配置文件
Properties pro=new Properties();
pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties"));
//2.获取DataSource
ds= DruidDataSourceFactory.createDataSource(pro);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接对象
* @return
*/
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
/**
* 释放资源
* @param stmt
* @param conn
*/
public static void close(Statement stmt,Connection conn){
close(null,stmt,conn);
}
/**
* 释放资源
* @param rs
* @param stmt
* @param connection
*/
public static void close(ResultSet rs,Statement stmt, Connection connection){
if (rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();//归还连接
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 获取数据库连接池
* @return
*/
public static DataSource getDataSource(){
return ds;
}
}
2.1 JdbcTemplate完成CRUD
调用JdbcTemplate的方法来完成CRUD的操作。现有如下的数据库表emp,使用JdbcTemplate完成一些需求,来理解上面所提到的方法。
需求:
1. 修改1号数据的 address 为 广州
2. 添加一条记录
3. 删除刚才添加的记录
4. 查询id为1的记录,将其封装为Map集合
5. 查询所有记录,将其封装为List
6. 查询所有记录,将其封装为Emp对象的List集合
7. 查询总记录数
2.2 代码实现
需求1. 修改1号数据的 address 为 广州
调用JdbcTemplate的update方法:public int update(String sql, @Nullable Object... args)
- 参数sql:执行的SQL语句;
- 参数 Object… args :可以有多个参数,按顺序依此对应SQL语句中多个占位符?的值;
public class Demo02 {
//Junit单元测试,可以让方法独立执行
/*
使用JdbcTemplate步骤
1.导入jar包
2.创建JDBCTemplate对象
3.调用JdbcTemplate里面的方法
*/
//1. 修改1号数据的 address 为广州
@Test
public void test1() {
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
String sql = "update emp set address=? where id=?";
//调用JdbcTemplate方法,执行sql
int count = template.update(sql, "广州", 1);
//获取执行结果,修改成功返回被修改的记录数
System.out.println(count);//1
}
...
}
需求2. 添加一条记录
//2. 向数据添加一条记录
@Test
public void test2() {
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
String sql = "insert into emp(name,address) value(?,?)";
//调用JdbcTemplate方法,执行sql
int count = template.update(sql, "赵子龙", "蜀国");
//获取执行结果,添加成功返回被添加的记录数
System.out.println(count);//1
}
需求3. 删除刚才添加的记录
//3. 删除刚才添加的记录
@Test
public void test3() {
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
String sql = "delete from emp where id=?";
//调用JdbcTemplate方法,执行sql
int count = template.update(sql, 9);
//获取执行结果,删除成功返回被删除的记录数
System.out.println(count);//1
}
需求4. 查询id为1的记录,将其封装为Map集合
public Map<String, Object> queryForMap(String sql)
:执行查询语句,只能将一条记录放到一个Map中。超过了一条则会报错:IncorrectResultSizeDataAccessException错误的结果大小数据访问异常
//4. 查询id为1的记录,将其封装为Map集合
@Test
public void test4() {
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
//String sql = "select * from emp where id=? or id = ?";
String sql = "select * from emp where id=? ";
//调用JdbcTemplate方法,执行sql
//注意:这个方法查询的结果集长度只能是1,超过1则报错
//Map<String, Object> map = template.queryForMap(sql, 1, 2);//IncorrectResultSizeDataAccessException
Map<String, Object> map = template.queryForMap(sql, 1);
//获取执行结果
System.out.println(map);//{id=1, name=董桌, address=广州, hireDate=2020-07-05 19:27:50.0}
}
需求5. 查询所有记录,将其封装为List
public List<Map<String, Object>> queryForList(String sql)
:执行查询语句,将结果集封装为List集合,注意:是将每一条记录封装为一个Map集合,再将Map集合装载到List集合中
//5. 查询所有记录,将其封装为List
@Test
public void test5(){
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
String sql = "select * from emp";
//调用JdbcTemplate方法,执行sql
List<Map<String, Object>> list = template.queryForList(sql);
//获取执行结果
for (Map<String, Object> map : list) {
System.out.println(map);
}
}
打印结果:
{id=1, name=董桌, address=广州, hireDate=2020-07-05 19:27:50.0}
{id=2, name=张飞, address=武汉, hireDate=2020-05-31 12:33:35.0}
{id=3, name=李小龙, address=武汉, hireDate=2020-05-31 12:34:02.0}
{id=4, name=王麻子, address=长沙, hireDate=2020-05-31 12:34:08.0}
{id=5, name=赵天, address=北京, hireDate=2020-05-31 12:34:16.0}
{id=6, name=刘长云, address=深圳, hireDate=2020-05-31 12:34:25.0}
{id=7, name=曹德, address=上海, hireDate=2020-05-31 12:33:55.0}
需求6. 查询所有记录,将其封装为Emp对象(自定义对象)的List集合
public <T> List<T> query(String sql, RowMapper<T> rowMapper)
:执行查询语句,将结果封装为JavaBean对象,返回一个List集合;
自定义的Emp类
public class Emp {
private int id;
private String name;
private String address;
private Date hireDate;
public Emp() {
}
public Emp(int id, String name, String address, Date hireDate) {
this.id = id;
this.name = name;
this.address = address;
this.hireDate = hireDate;
}
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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getHireDate() {
return hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", name='" + name + '\'' +
", address='" + address + '\'' +
", hireDate='" + hireDate + '\'' +
'}';
}
}
//6. 查询所有记录,将其封装为Emp对象(自定义对象)的List集合
@Test
public void test6(){
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
String sql = "select * from emp";
//调用JdbcTemplate方法,执行sql
List<Emp> list = template.query(sql, new RowMapper<Emp>() {
@Override
public Emp mapRow(ResultSet rs, int i) throws SQLException {
Emp emp=new Emp();
//从结果集中获取列字段对应的数据记录
int id = rs.getInt("id");
String name = rs.getString("name");
String address = rs.getString("address");
Date hireDate = rs.getDate("hireDate");
//存入Emp对象中
emp.setId(id);
emp.setName(name);
emp.setAddress(address);
emp.setHireDate(hireDate);
return emp;
}
});
//打印List集合
for (Emp emp : list) {
System.out.println(emp);
}
}
用RowMapper的实现类BeanPropertyRowMapper,将数据自动封装,代码更加简洁。
/*
6. 查询所有记录,将其封装为Emp对象(自定义对象)的List集合
一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装
new BeanPropertyRowMapper<类型>(类型.class)
*/
@Test
public void test7(){
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
String sql="select * from emp";
//调用JdbcTemplate方法,执行sql
//将查询到的记录自动封装成自定义对象
List<Emp> list = template.query(sql, new BeanPropertyRowMapper<Emp>(Emp.class));
//遍历List集合,打印
for (Emp emp : list) {
System.out.println(emp);
}
}
两种方式输出结果都是一样的:
Emp{id=1, name='董桌', address='广州', hireDate='2020-07-05 19:27:50.0'}
Emp{id=2, name='张飞', address='武汉', hireDate='2020-05-31 12:33:35.0'}
Emp{id=3, name='李小龙', address='武汉', hireDate='2020-05-31 12:34:02.0'}
Emp{id=4, name='王麻子', address='长沙', hireDate='2020-05-31 12:34:08.0'}
Emp{id=5, name='赵天', address='北京', hireDate='2020-05-31 12:34:16.0'}
Emp{id=6, name='刘长云', address='深圳', hireDate='2020-05-31 12:34:25.0'}
Emp{id=7, name='曹德', address='上海', hireDate='2020-05-31 12:33:55.0'}
需求7. 查询总记录数
public <T> T queryForObject(String sql, Class<T> requiredType)
:执行查询语句,返回一个指定类型的数据。
//7. 查询总记录数
@Test
public void test8(){
//创建JDBCTemplate对象
JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
//定义sql
String sql="select count(id) from emp";
//调用JdbcTemplate方法,执行sql
Long total = template.queryForObject(sql, Long.class);
System.out.println(total);//打印结果:7
}
3.小结
使用JdbcTemplate能够简化我们对JDBC的操作,它是JDBC的一个辅助类(JDBC Template),它封装了JDBC的操作,使用起来非常方便。可以对比前两篇文章来看JdbcTemplata类的方便之处,这篇JDBC(三)拖了挺久,笔者正在努力学习中,哈哈其实是我忘了。
使用JdbcTemplate用到的jar包:点我. 提取码:lp3b
本文有所帮助的话,欢迎点赞评论,指出不足,笔者由衷感谢o!
推荐阅读:
JDBC(一):基础(本质,操作步骤,类对象详解,工具类,事务)
JDBC:API实战(CURD,封装结果集,批量处理sql,处理二进制大数据文件,获取主键列、元数据).
JDBC(二):数据库连接池(C3P0、Druid)
JDBC(三):Spring的JDBCTemplate基本使用