【Spring JDBC】JdbcTemplate(三)
传统Jdbc API与Spring jdbcTemplate比较
//JDBC API
Statement statement = conn.createStatement();
ResultSet resultSet = statement.executeQuery("select count(*) from COUNT student")
if(resultSet.next()){
Integer count = resultSet.getInt("COUNT");
} //JDBC Template
Integer count = jdbcTemplate.queryForObject("select count(*) from student",Integer.class);
Spring对数据库的操作在jdbc上面做了深层次的封装,使用spring的注入功能,可以把DataSource注册到JdbcTemplate之中,其全限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用JdbcTemlate一般还需要事务和异常的控制。
一、JdbcTemplate主要几类方法
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
- update方法及batchUpdate方法:update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语句;
- query方法及queryForXXX方法:用于执行查询相关语句;
- call方法:用于执行存储过程、函数相关语句。
二、JdbcTemplate常用API
//update操作单个增删改
int update(String sql,Object[] args)
int update(String sql,Objcet... args) //batchUpdate批量增删改
int[] batchUpdate(String[] sql)
int[] batchUpdate(String sql,List<Object[]>) //单个简单查询
T queryForObjcet(String sql,Class<T> type)
T queryForObjcet(String sql,Object[] args,Class<T> type)
T queryForObjcet(String sql,Class<T> type,Object... arg) //获取多个
List<T> queryForList(String sql,Class<T> type)
List<T> queryForList(String sql,Object[] args,Class<T> type)
List<T> queryForList(String sql,Class<T> type,Object... arg)
查询复杂对象(封装为Map):
//获取单个
Map queryForMap(String sql)
Map queryForMap(String sql,Objcet[] args)
Map queryForMap(String sql,Object... arg) //获取多个
List<Map<String,Object>> queryForList(String sql)
List<Map<String,Object>> queryForList(String sql,Obgject[] args)
List<Map<String,Object>> queryForList(String sql,Obgject... arg)
查询复杂对象(封装为实体对象):
Spring JdbcTemplate是通过实现org.springframework.jdbc.core.RowMapper这个接口来完成对entity对象映射。
//获取单个
T queryForObject(String sql,RowMapper<T> mapper)
T queryForObject(String sql,object[] args,RowMapper<T> mapper)
T queryForObject(String sql,RowMapper<T> mapper,Object... arg) //获取多个
List<T> query(String sql,RowMapper<T> mapper)
List<T> query(String sql,Object[] args,RowMapper<T> mapper)
List<T> query(String sql,RowMapper<T> mapper,Object... arg)
Spring JDBC中目前有两个主要的RowMapper实现,使用它们应该能解决大部分的场景了:SingleColumnRowMapper和BeanPropertyRowMapper。
SingleColumnRowMapper:返回单列数据
BeanPropertyRowMapper:当查询数据库返回的是多列数据,且需要将这些多列数据映射到某个具体的实体类上。
//示例:
String sql = "select name from test_student where id = ?";
jdbcTemplate.queryForObject(sql, new Object[]{id}, new SingleColumnRowMapper<>(String.class)); String sql = "select name, gender from test_student where name = ?";
jdbcTemplate.queryForObject(sql, new Object[]{name},new BeanPropertyRowMapper<>(Student.class));
定义自己的RowMapper
如果你SQL查询出来的数据列名就是和实体类的属性名不一样,或者想按照自己的规则来装配实体类,那么就可以定义并使用自己的Row Mapper。
//自定义
public class StudentRowMapper implements RowMapper<Student> { @Override
public Student mapRow(ResultSet rs, int i) throws SQLException {
Student student = new Student();
student.setName(rs.getString("name"));
student.setGender(rs.getString("gender"));
student.setEmail(rs.getString("email"));
return student;
}
} //使用
String sql = "select name, gender, email from test_student where name = ?";
jdbcTemplate.queryForObject(sql, new Object[]{name}, new StudentRowMapper());
三、JdbcTemplate支持的回调类
1. 预编译语句及存储过程创建回调:用于根据JdbcTemplate提供的连接创建相应的语句
PreparedStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的PreparedStatement;
CallableStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementCallback;
import org.springframework.jdbc.core.PreparedStatementCreator;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) // 关联Spring与Junit
@ContextConfiguration(locations = { "classpath:applicationContext.xml" }) // 加载配置spring配置文件
public class AppTest { @Autowired
private JdbcTemplate jdbcTemplate; @Test
public void testPpreparedStatement1() {
int count = jdbcTemplate.execute(new PreparedStatementCreator() {
public java.sql.PreparedStatement createPreparedStatement(Connection conn) throws SQLException {
return conn.prepareStatement("select count(*) from user");
}
}, new PreparedStatementCallback<Integer>() {
public Integer doInPreparedStatement(java.sql.PreparedStatement pstmt)
throws SQLException, DataAccessException {
pstmt.execute();
ResultSet rs = pstmt.getResultSet();
rs.next();
return rs.getInt(1);
}
});
System.out.println(count);
}
}
首先使用PreparedStatementCreator创建一个预编译语句,其次由JdbcTemplate通过PreparedStatementCallback回调传回,由用户决定如何执行该PreparedStatement。此处我们使用的是execute方法。
2. 预编译语句设值回调:用于给预编译语句相应参数设值
PreparedStatementSetter:通过回调获取JdbcTemplate提供的PreparedStatement,由用户来对相应的预编译语句相应参数设值;
BatchPreparedStatementSetter:;类似于PreparedStatementSetter,但用于批处理,需要指定批处理大小;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) // 关联Spring与Junit
@ContextConfiguration(locations = { "classpath:applicationContext.xml" }) // 加载配置spring配置文件
public class AppTest { @Autowired
private JdbcTemplate jdbcTemplate; @Test
public void testPreparedStatement2() {
String insertSql = "insert into user(user_name) values (?)";
int count = jdbcTemplate.update(insertSql, new PreparedStatementSetter() {
public void setValues(PreparedStatement pstmt) throws SQLException {
pstmt.setObject(1, "mmNN");
}
});
Assert.assertEquals(1, count);
String deleteSql = "delete from user where user_name=?";
count = jdbcTemplate.update(deleteSql, new Object[] { "mmNN" });
Assert.assertEquals(1, count);
}
}
通过JdbcTemplate的int update(String sql, PreparedStatementSetter pss)执行预编译sql,其中sql参数为“insert into user(user_name) values (?) ”,该sql有一个占位符需要在执行前设值,PreparedStatementSetter实现就是为了设值,使用setValues(PreparedStatement pstmt)回调方法设值相应的占位符位置的值。JdbcTemplate也提供一种更简单的方式“update(String sql, Object... args)”来实现设值,所以只要当使用该种方式不满足需求时才应使用PreparedStatementSetter。
3. 自定义功能回调:提供给用户一个扩展点,用户可以在指定类型的扩展点执行任何数量需要的操作
ConnectionCallback:通过回调获取JdbcTemplate提供的Connection,用户可在该Connection执行任何数量的操作;
StatementCallback:通过回调获取JdbcTemplate提供的Statement,用户可以在该Statement执行任何数量的操作;
PreparedStatementCallback:通过回调获取JdbcTemplate提供的PreparedStatement,用户可以在该PreparedStatement执行任何数量的操作;
CallableStatementCallback:通过回调获取JdbcTemplate提供的CallableStatement,用户可以在该CallableStatement执行任何数量的操作;
4. 结果集处理回调:通过回调处理ResultSet或将ResultSet转换为需要的形式
RowMapper:用于将结果集每行数据转换为需要的类型,用户需实现方法mapRow(ResultSet rs, int rowNum)来完成将每行数据转换为相应的类型。
RowCallbackHandler:用于处理ResultSet的每一行结果,用户需实现方法processRow(ResultSet rs)来完成处理,在该回调方法中无需执行rs.next(),该操作由JdbcTemplate来执行,用户只需按行获取数据然后处理即可。
ResultSetExtractor:用于结果集数据提取,用户需实现方法extractData(ResultSet rs)来处理结果集,用户必须处理整个结果集;
@Test
public void testResultSet1() {
jdbcTemplate.update("insert into user(user_name) values('name7')");
String listSql = "select * from user where user_name=?";
List result = jdbcTemplate.query(listSql,new Object[]{"name7"}, new RowMapper<Map>() {
public Map mapRow(ResultSet rs, int rowNum) throws SQLException {
Map row = new HashMap();
row.put(rs.getInt("user_id"), rs.getString("user_name"));
return row;
}
});
Assert.assertEquals(1, result.size());//查询结果数量为1才向下执行
jdbcTemplate.update("delete from user where user_name='name7'");
}
RowMapper接口提供mapRow(ResultSet rs, int rowNum)方法将结果集的每一行转换为一个Map,当然可以转换为其他类。
@Test
public void testResultSet2() {
jdbcTemplate.update("insert into user(user_name) values('name5')");
String listSql = "select * from user";
final List result = new ArrayList();
jdbcTemplate.query(listSql, new RowCallbackHandler() {
public void processRow(ResultSet rs) throws SQLException {
Map row = new HashMap();
row.put(rs.getInt("user_id"), rs.getString("user_name"));
result.add(row);
}
});
Assert.assertEquals(1, result.size());
jdbcTemplate.update("delete from user where user_name='name5'");
}
RowCallbackHandler接口也提供方法processRow(ResultSet rs),能将结果集的行转换为需要的形式。
@Test
public void testResultSet3() {
jdbcTemplate.update("insert into test(name) values('name5')");
String listSql = "select * from test";
List result = jdbcTemplate.query(listSql, new ResultSetExtractor<List>() {
public List extractData(ResultSet rs) throws SQLException, DataAccessException {
List result = new ArrayList();
while (rs.next()) {
Map row = new HashMap();
row.put(rs.getInt("id"), rs.getString("name"));
result.add(row);
}
return result;
}
});
Assert.assertEquals(0, result.size());
jdbcTemplate.update("delete from test where name='name5'");
}
ResultSetExtractor使用回调方法extractData(ResultSet rs)提供给用户整个结果集,让用户决定如何处理该结果集。
当然JdbcTemplate提供更简单的queryForXXX方法,来简化开发:
//1.查询一行数据并返回int型结果
jdbcTemplate.queryForInt("select count(*) from test");
//2. 查询一行数据并将该行数据转换为Map返回
jdbcTemplate.queryForMap("select * from test where name='name5'");
//3.查询一行任何类型的数据,最后一个参数指定返回结果类型
jdbcTemplate.queryForObject("select count(*) from test", Integer.class);
//4.查询一批数据,默认将每行数据转换为Map
jdbcTemplate.queryForList("select * from test");
//5.只查询一列数据列表,列类型是String类型,列名字是name
jdbcTemplate.queryForList("
select name from test where name=?", new Object[]{"name5"}, String.class);
//6.查询一批数据,返回为SqlRowSet,类似于ResultSet,但不再绑定到连接上
SqlRowSet rs = jdbcTemplate.queryForRowSet("select * from test");
四、存储过程及函数回调
待续......
附:Spring提供的JDBC模板
- JdbcTemplate:Spring里最基本的JDBC模板,利用JDBC和简单的索引参数查询提供对数据库的简单访问。
- NamedParameterJdbcTemplate:能够在执行查询时把值绑定到SQL里的命名参数,而不是使用索引参数。
- SimpleJdbcTemplate:利用Java 5的特性,比如自动装箱、通用(generic)和可变参数列表来简化JDBC模板的使用。
【Spring JDBC】JdbcTemplate(三)的更多相关文章
- Spring JDBC JdbcTemplate类示例
org.springframework.jdbc.core.JdbcTemplate类是JDBC核心包中的中心类.它简化了JDBC的使用,并有助于避免常见的错误. 它执行核心JDBC工作流,留下应用程 ...
- JDBC(三)----Spring JDBC(JDBCTemplate)
## Spring JDBC * Spring框架对JDBC的简单封装.提供了一个JDBCTemplate对象简化JDBC的开发 1.步骤 1.导入jar包 2.创建JDBCTemplate对象 ...
- 三种数据库访问——Spring JDBC
本篇随笔是上两篇的延续:三种数据库访问——原生JDBC:数据库连接池:Druid Spring的JDBC框架 Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要 ...
- 【Spring】Spring的数据库开发 - 1、Spring JDBC的配置和Spring JdbcTemplate的解析
Spring JDBC 文章目录 Spring JDBC Spring JdbcTemplate的解析 Spring JDBC的配置 简单记录-Java EE企业级应用开发教程(Spring+Spri ...
- Spring JDBC(一)jdbcTemplate
前言 最近工作中经常使用Spring JDBC操作数据库,也断断续续的看了一些源码,便有了写一些总结的想法,希望在能帮助别人的同时,也加深一下自己对Spring JDBC的理解. Spring JDB ...
- Spring的jdbcTemplate 与原始jdbc 整合c3p0的DBUtils 及Hibernate 对比 Spring配置文件生成约束的菜单方法
以User为操作对象 package com.swift.jdbc; public class User { private Long user_id; private String user_cod ...
- Spring笔记05(Spring JDBC三种数据源和ORM框架的映射)
1.ORM框架的映射 01.JDBC连接数据库以前的方式代码,并给对象赋值 @Test /** * 以前的方式jdbc */ public void TestJdbc(){ /** * 连接数据库的四 ...
- Spring JDBC模板类—org.springframework.jdbc.core.JdbcTemplate(转)
今天看了下Spring的源码——关于JDBC的"薄"封装,Spring 用一个Spring JDBC模板类来封装了繁琐的JDBC操作.下面仔细讲解一下Spring JDBC框架. ...
- Spring JDBC 框架使用JdbcTemplate 类的一个实例
JDBC 框架概述 在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等.但 Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQ ...
随机推荐
- Acwing40. 顺时针打印矩阵
地址 https://www.acwing.com/solution/acwing/content/3623/ 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字. 样例 输入: [ [, ...
- LeetCode 1245 树的直径
地址 https://leetcode-cn.com/contest/biweekly-contest-12/problems/tree-diameter/ 给你这棵「无向树」,请你测算并返回它的「直 ...
- 基础知识 Asp.Net MVC EF各版本区别
原文:https://www.cnblogs.com/liangxiaofeng/p/5840754.html 2009年發行ASP.NET MVC 1.0版 2010年發行ASP.NET MVC 2 ...
- Docker安装MySQL 8.0并挂载数据及配置文件
安装部署环境 Ubuntu 18.04.3 LTS Docker 19.03.2 MySQL latest(8.0.17) 下载镜像 # docker从仓库中拉取最新版的mysql镜像,如果没加标签的 ...
- word文档操作-doc转docx、合并多个docx
前言: 临时来了一条新的需求:多个doc文档进行合并. 在网上苦苦搜罗了很久才找到可用的文件(原文出处到不到了 所以暂时不能加链接地址了),现在记录下留给有需要的人. 一:doc转docx 所需jar ...
- 【2016NOI十连赛2-2】黑暗
[2016NOI十连赛2-2]黑暗 题目大意:定义一个无向图的权值为连通块个数的\(m\)次方.求\(n\)个点的所有无向图的权值和.多次询问. 数据范围:\(T\leq 1000,n\leq 300 ...
- 前端笔记之Vue(三)生命周期&CSS预处理&全局组件&自定义指令
一.Vue的生命周期 生命周期就是指一个对象的生老病死的过程. 用Vue框架,熟悉它的生命周期可以让开发更好的进行. 所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和 ...
- jQuery 源码分析(十九) DOM遍历模块详解
jQuery的DOM遍历模块对DOM模型的原生属性parentNode.childNodes.firstChild.lastChild.previousSibling.nextSibling进行了封装 ...
- 使用DataV制作的一个数据报表
之前接到一个做数据报表的需求,当时准备使用echarts自己画.后来考虑时间来不及,着急要,再加上一直在使用阿里云的产品,就在阿里云上个找了找数据大屏的服务.于是很快做出了一款. 然后看到 https ...
- Vant ui
轻量.可靠的移动端 Vue 组件库 https://youzan.github.io/vant/#/zh-CN/intro postcss-pxtorem vue:将px转化为rem,适配移动端van ...