传统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(三)的更多相关文章

  1. Spring JDBC JdbcTemplate类示例

    org.springframework.jdbc.core.JdbcTemplate类是JDBC核心包中的中心类.它简化了JDBC的使用,并有助于避免常见的错误. 它执行核心JDBC工作流,留下应用程 ...

  2. JDBC(三)----Spring JDBC(JDBCTemplate)

    ##  Spring  JDBC *  Spring框架对JDBC的简单封装.提供了一个JDBCTemplate对象简化JDBC的开发 1.步骤 1.导入jar包 2.创建JDBCTemplate对象 ...

  3. 三种数据库访问——Spring JDBC

    本篇随笔是上两篇的延续:三种数据库访问——原生JDBC:数据库连接池:Druid Spring的JDBC框架 Spring JDBC提供了一套JDBC抽象框架,用于简化JDBC开发. Spring主要 ...

  4. 【Spring】Spring的数据库开发 - 1、Spring JDBC的配置和Spring JdbcTemplate的解析

    Spring JDBC 文章目录 Spring JDBC Spring JdbcTemplate的解析 Spring JDBC的配置 简单记录-Java EE企业级应用开发教程(Spring+Spri ...

  5. Spring JDBC(一)jdbcTemplate

    前言 最近工作中经常使用Spring JDBC操作数据库,也断断续续的看了一些源码,便有了写一些总结的想法,希望在能帮助别人的同时,也加深一下自己对Spring JDBC的理解. Spring JDB ...

  6. Spring的jdbcTemplate 与原始jdbc 整合c3p0的DBUtils 及Hibernate 对比 Spring配置文件生成约束的菜单方法

    以User为操作对象 package com.swift.jdbc; public class User { private Long user_id; private String user_cod ...

  7. Spring笔记05(Spring JDBC三种数据源和ORM框架的映射)

    1.ORM框架的映射 01.JDBC连接数据库以前的方式代码,并给对象赋值 @Test /** * 以前的方式jdbc */ public void TestJdbc(){ /** * 连接数据库的四 ...

  8. Spring JDBC模板类—org.springframework.jdbc.core.JdbcTemplate(转)

    今天看了下Spring的源码——关于JDBC的"薄"封装,Spring 用一个Spring JDBC模板类来封装了繁琐的JDBC操作.下面仔细讲解一下Spring JDBC框架. ...

  9. Spring JDBC 框架使用JdbcTemplate 类的一个实例

    JDBC 框架概述 在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等.但 Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQ ...

随机推荐

  1. 什么是uWSGI、WSGI、uwsgi、wsgiref、werkzeug

    我不是代码的生产者,我只是知识的搬运工 uWSGI.WSGI.uwsgi.wsgiref.werkzeug

  2. LG1345 「USACO5.4」Telecowmunication 最小割

    问题描述 LG1345 题解 点边转化,最小割,完事. \(\mathrm{Code}\) #include<bits/stdc++.h> using namespace std; tem ...

  3. <Math> 29 365

    29. Divide Two Integers class Solution { public int divide(int dividend, int divisor) { if(dividend ...

  4. 配置SQL Server维护计划-定时备份

    目录 创建维护计划 创建任务 配置维护计划的依赖环境 还原数据库 创建维护计划 打开SQL Server 2014 Management Studio,用SQL Server管理员账户登录. 展开Ma ...

  5. event.stopPropagation()和event.preventDefault()

    1.event.stopPropagation()方法 这是阻止事件的冒泡方法,不让事件向documen上蔓延,但是默认事件任然会执行,当你掉用这个方法的时候,如果点击一个连接,这个连接仍然会被打开, ...

  6. 【Linux命令】nohup命令用法

    nohup命令用法 当我们想将某个脚本或程序运行在后台的时候.我们一般会在程序或脚本后面添加 & 字符来表示在后台运行,但使用& 运行在后台,当我们将shell窗口关闭时,该脚本或程序 ...

  7. rpmbuild打包

    安装: yum  install -y rpm-build 目录介绍: 默认目录在  /root/rpmbuild BUILD :你要打包的文件将会在这里编译(编译rpm包的临时目录) BUILDRO ...

  8. [IDA]系统注释给改掉

    IDA系统自动注释的,如果按 ';',则不会修改成功. 应该按 Shift + ;  这样才可以修改.

  9. 两种查看EFCore生成Sql语句的方法

    一.利用反射生成查询语句 该方法转载自:https://jhrs.com/2019/28488.html (略有修改) using Microsoft.EntityFrameworkCore.Quer ...

  10. qt 界面去掉系统边框

    该代码在Qt5框架编辑,使用该类时, 直接继承这个类就可以了. 实现了拖拽功能和关闭功能,如果需要放大缩小功能, 需自己实现. 1 #ifndef CUSTOMIZE_QWIDGET_H #defin ...