User-Profile-Image
hankin
  • 5
  • Java
  • Kotlin
  • Spring
  • Web
  • SQL
  • MegaData
  • More
  • Experience
  • Enamiĝu al vi
  • 分类
    • Zuul
    • Zookeeper
    • XML
    • WebSocket
    • Web Notes
    • Web
    • Vue
    • Thymeleaf
    • SQL Server
    • SQL Notes
    • SQL
    • SpringSecurity
    • SpringMVC
    • SpringJPA
    • SpringCloud
    • SpringBoot
    • Spring Notes
    • Spring
    • Servlet
    • Ribbon
    • Redis
    • RabbitMQ
    • Python
    • PostgreSQL
    • OAuth2
    • NOSQL
    • Netty
    • MySQL
    • MyBatis
    • More
    • MinIO
    • MegaData
    • Maven
    • LoadBalancer
    • Kotlin Notes
    • Kotlin
    • Kafka
    • jQuery
    • JavaScript
    • Java Notes
    • Java
    • Hystrix
    • Git
    • Gateway
    • Freemarker
    • Feign
    • Eureka
    • ElasticSearch
    • Docker
    • Consul
    • Ajax
    • ActiveMQ
  • 页面
    • 归档
    • 摘要
    • 杂图
    • 问题随笔
  • 友链
    • Spring Cloud Alibaba
    • Spring Cloud Alibaba - 指南
    • Spring Cloud
    • Nacos
    • Docker
    • ElasticSearch
    • Kotlin中文版
    • Kotlin易百
    • KotlinWeb3
    • KotlinNhooo
    • 前端开源搜索
    • Ktorm ORM
    • Ktorm-KSP
    • Ebean ORM
    • Maven
    • 江南一点雨
    • 江南国际站
    • 设计模式
    • 熊猫大佬
    • java学习
    • kotlin函数查询
    • Istio 服务网格
    • istio
    • Ktor 异步 Web 框架
    • PostGis
    • kuangstudy
    • 源码地图
    • it教程吧
    • Arthas-JVM调优
    • Electron
    • bugstack虫洞栈
    • github大佬宝典
    • Sa-Token
    • 前端技术胖
    • bennyhuo-Kt大佬
    • Rickiyang博客
    • 李大辉大佬博客
    • KOIN
    • SQLDelight
    • Exposed-Kt-ORM
    • Javalin—Web 框架
    • http4k—HTTP包
    • 爱威尔大佬
    • 小土豆
    • 小胖哥安全框架
    • 负雪明烛刷题
    • Kotlin-FP-Arrow
    • Lua参考手册
    • 美团文章
    • Java 全栈知识体系
    • 尼恩架构师学习
    • 现代 JavaScript 教程
    • GO相关文档
    • Go学习导航
    • GoCN社区
    • GO极客兔兔-案例
    • 讯飞星火GPT
    • Hollis博客
    • PostgreSQL德哥
    • 优质博客推荐
    • 半兽人大佬
    • 系列教程
    • PostgreSQL文章
    • 云原生资料库
    • 并发博客大佬
Help?

Please contact us on our email for need any support

Support
    首页   ›   Spring   ›   Spring Notes   ›   正文
Spring Notes

Spring—JdbcTemplate模板类的使用(补充)

2020-03-24 23:46:16
1082  0 0
参考目录 隐藏
1) JdbcTemplate类支持的回调类:
2) 预编译语句及存储过程创建回调
3) 预编译语句设值回调
4) 自定义功能回调
5) 结果集处理回调
6) 常用:
7) queryForObject() # 必须且只能返回一条记录,且只能查询一个字段
8) queryForList() #可以返回0条或多条记录,普通类型的List只能查询一个字段,Map类型的List可以查询多个字段
9) queryForMap() #可以查询多个字段,但只能装一条记录
10) queryForRowSet() #返回结果集
11) query() #将结果集的记录映射为bean类型的List

阅读完需:约 14 分钟

Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDBC模板类是第一种工作模式。 

JdbcTemplate类通过模板设计模式帮助我们消除了冗长的代码,只做需要做的事情(即可变部分),并且帮我们做哪些固定部分,如连接的创建及关闭。

JdbcTemplate类对可变部分采用回调接口方式实现,如ConnectionCallback通过回调接口返回给用户一个连接,从而可以使用该连接做任何事情、StatementCallback通过回调接口返回给用户一个Statement,从而可以使用该Statement做任何事情等等,还有其他一些回调接口

在此之前要先了解基础:

Spring笔记13—JdbcTemplate(数据库)

JdbcTemplate类支持的回调类:

预编译语句及存储过程创建回调

  • 预编译语句及存储过程创建回调:用于根据JdbcTemplate提供的连接创建相应的语句;
    1. PreparedStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的PreparedStatement;
    2. CallableStatementCreator:通过回调获取JdbcTemplate提供的Connection,由用户使用该Conncetion创建相关的CallableStatement;
@Test    
public void testPpreparedStatement1() {    
  int count = jdbcTemplate.execute(new PreparedStatementCreator() {    
     @Override    
     public PreparedStatement createPreparedStatement(Connection conn)    
         throws SQLException {    
         return conn.prepareStatement("select count(*) from test");    
     }}, new PreparedStatementCallback<Integer>() {    
     @Override    
     public Integer doInPreparedStatement(PreparedStatement pstmt)    
         throws SQLException, DataAccessException {    
         pstmt.execute();    
         ResultSet rs = pstmt.getResultSet();    
         rs.next();    
         return rs.getInt(1);    
      }});        
   Assert.assertEquals(0, count);    
}   

首先使用PreparedStatementCreator创建一个预编译语句,其次由JdbcTemplate通过PreparedStatementCallback回调传回,由用户决定如何执行该PreparedStatement。此处我们使用的是execute方法。

预编译语句设值回调

  • 预编译语句设值回调:用于给预编译语句相应参数设值;
    • PreparedStatementSetter:通过回调获取JdbcTemplate提供的PreparedStatement,由用户来对相应的预编译语句相应参数设值;
    • BatchPreparedStatementSetter:;类似于PreparedStatementSetter,但用于批处理,需要指定批处理大小;
@Test    
public void testPreparedStatement2() {    
  String insertSql = "insert into test(name) values (?)";    
  int count = jdbcTemplate.update(insertSql, new PreparedStatementSetter() {    
      @Override    
      public void setValues(PreparedStatement pstmt) throws SQLException {    
          pstmt.setObject(1, "name4");    
  }});    
  Assert.assertEquals(1, count);        
  String deleteSql = "delete from test where name=?";    
  count = jdbcTemplate.update(deleteSql, new Object[] {"name4"});    
  Assert.assertEquals(1, count);    
}  

通过JdbcTemplate的int update(String sql, PreparedStatementSetter pss)执行预编译sql,其中sql参数为“insert into test(name) values (?) ”,该sql有一个占位符需要在执行前设值,PreparedStatementSetter实现就是为了设值,使用setValues(PreparedStatement pstmt)回调方法设值相应的占位符位置的值。

JdbcTemplate也提供一种更简单的方式“update(String sql, Object… args)”来实现设值,所以只要当使用该种方式不满足需求时才应使用PreparedStatementSetter。

自定义功能回调

  • 自定义功能回调:提供给用户一个扩展点,用户可以在指定类型的扩展点执行任何数量需要的操作;
    • ConnectionCallback:通过回调获取JdbcTemplate提供的Connection,用户可在该Connection执行任何数量的操作;
    • StatementCallback:通过回调获取JdbcTemplate提供的Statement,用户可以在该Statement执行任何数量的操作;
    • PreparedStatementCallback:通过回调获取JdbcTemplate提供的PreparedStatement,用户可以在该PreparedStatement执行任何数量的操作;
    • CallableStatementCallback:通过回调获取JdbcTemplate提供的CallableStatement,用户可以在该CallableStatement执行任何数量的操作;

结果集处理回调

  • 结果集处理回调:通过回调处理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 test(name) values('name5')");    
  String listSql = "select * from test";    
  List result = jdbcTemplate.query(listSql, new RowMapper<Map>() {    
      @Override    
      public Map mapRow(ResultSet rs, int rowNum) throws SQLException {    
          Map row = new HashMap();    
          row.put(rs.getInt("id"), rs.getString("name"));    
          return row;    
  }});    
  Assert.assertEquals(1, result.size());    
  jdbcTemplate.update("delete from test where name='name5'");         
}   

RowMapper接口提供mapRow(ResultSet rs, int rowNum)方法将结果集的每一行转换为一个Map,当然可以转换为其他类,如表的对象画形式。

@Test    
public void testResultSet2() {    
  jdbcTemplate.update("insert into test(name) values('name5')");    
  String listSql = "select * from test";    
  final List result = new ArrayList();    
  jdbcTemplate.query(listSql, new RowCallbackHandler() {    
      @Override    
      public void processRow(ResultSet rs) throws SQLException {    
          Map row = new HashMap();    
          row.put(rs.getInt("id"), rs.getString("name"));    
          result.add(row);    
  }});    
  Assert.assertEquals(1, result.size());    
  jdbcTemplate.update("delete from test where 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>() {    
      @Override    
      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");   

常用:

queryForObject()      # 必须且只能返回一条记录,且只能查询一个字段

  • <T>  queryForObject(String sql, T.class)    //不需向sql语句传递参数
  • <T>  queryForObject(String sql, Object[]  args, T.class)    //args是sql语句中?对应的值
  • <T>  queryForObject(String sql, T.class, Object… args)
     String sql="select id from student_tb where name = ? and gender = ?"
     Object[] args=new Object[]{"张三",1};
     int id=jdbcTemplate.queryForObject(sql,args,int.class);

ForObject,顾名思义,必须且只能返回一条记录,如果返回多条记录或没有记录匹配,都会报错;且只能查询一个字段。 

queryForList()      #可以返回0条或多条记录,普通类型的List只能查询一个字段,Map类型的List可以查询多个字段

  • List<T>  queryForList(String sql, T.class)
  • List<T>  queryForList(String sql, Object[]  args, T.class)    //args是sql语句中?的对应值(实参)
  • List<T>  queryForList(String sql, T.class, Object…args)
 String sql="select name from student_tb";
        List<String> list=jdbcTemplate.queryForList(sql,String.class);
        for (String name:list){
            System.out.println(name);
        } 

基本数据类型的List,只能选中数据表的一列。

  • List<Map<String,Object>>   queryForList(String sql)
  • List<Map<String,Object>>   queryForList(String sql, Object…args)
 String sql="select * from student_tb";
        List<Map<String,Object>> list=jdbcTemplate.queryForList(sql);
        //list装的是结果集中所有的记录,一个map装一条记录
        for (Map<String,Object> map:list){
            //map的key是字段名,value是该字段的值。get()的返回值是Object。
            Object id = map.get("id");
            Object name = map.get("name");
            Object age = map.get("age");
            System.out.println("id:"+id+"\tname:"+name+"\tage:"+age);
        }

Map类型的List,可以选择多列。字段名都是String,值可能是各种类型,所以使用Map<String, Obejct>。

queryForMap()     #可以查询多个字段,但只能装一条记录

  • Map<String, Obejct>   queryForMap(String sql)
  • Map<String, Object>   queryForMap(String sql, Object…args)
     String sql="select * from student_tb where id = 1";
        Map<String,Object> map=jdbcTemplate.queryForMap(sql);
        Object name = map.get("name");
        Object age = map.get("age");
        System.out.println("name:"+name+"\tage:"+age);

因为是Map,可以装多个字段,但只能装一条记录。

如果返回多条记录,则只取第一条来装;如果没有匹配的记录,会报错。

queryForRowSet()     #返回结果集

  • SqlRowSet  queryForRowSet(String sql)     
  • SqlRowSet  queryForRowSet(String sql, Object…args)    //args是sql语句中的?对应的值。
     String sql="select * from student_tb";
        SqlRowSet rowSet=jdbcTemplate.queryForRowSet(sql);
        //遍历结果集
        while (rowSet.next()){
            // 参数指定列名,可以用String类型的字段名,也可以用int型的值(该字段在结果集中的第几列,从1开始)
            // int id = rowSet.getInt(1);
            int id = rowSet.getInt("id");
            String name = rowSet.getString("name");
            //......
        }

query()      #将结果集的记录映射为bean类型的List

  • List<T>   query(String sql, RowMapper<T>  rowMapper)
  • List<T>   query(String sql, Object[]  args, RowMapper<T>  rowMapper)
  • List<T>   query(String sql, RowMapper<T>  rowMapper, Object…args)
public class Student {
    private int id;
    private String name;
    private int age;
    ………………………………………………
}
 String sql="select * from student_tb";
        RowMapper<Student> rowMapper=new BeanPropertyRowMapper<>(Student.class);
        List<Student> list=jdbcTemplate.query(sql,rowMapper);
        System.out.println(list);

RowMapper是接口,BeanPropertyRowMapper是spring提供的唯一的实现类。

query()只能将结果集的记录映射为Bean类型的List,不能映射为基本类型的List。

映射时会自动将结果集中的字段赋给同名的成员变量,所以要求Bean的成员变量名要与结果集的字段名相同,很死板。

如果结果集中没有同名的字段,该成员变量就不会被映射(值是JVM赋的初始值)。 映射时是调用setter方法给Bean的成员变量赋值,所以Bean要提供setter方法。

在Spring中尽量不要使用new来创建Bean的实例,上面的RowMapper实例可以这样创建:

<bean name="beanPropertyRowMapper" class="org.springframework.jdbc.core.BeanPropertyRowMapper">
      <!-- value指定目标类型 -->
        <property name="mappedClass" value="com.chy.model.Student" />
</bean>
RowMapper<Student> rowMapper = applicationContext.getBean("beanPropertyRowMapper",BeanPropertyRowMapper.class);

如本文“对您有用”,欢迎随意打赏作者,让我们坚持创作!

0 打赏
Enamiĝu al vi
不要为明天忧虑.因为明天自有明天的忧虑.一天的难处一天当就够了。
543文章 68评论 294点赞 594077浏览

随机文章
Kotlin-内置类型—函数(六)
4年前
Docker—安装与基本组成(一)
5年前
SpringMVC笔记1—简介
5年前
SpringSecurity—中如何快速查看登录用户 IP 地址等信息
4年前
Kotlin-类型进阶—数据类(二十四)
4年前
博客统计
  • 日志总数:543 篇
  • 评论数目:68 条
  • 建站日期:2020-03-06
  • 运行天数:1927 天
  • 标签总数:23 个
  • 最后更新:2024-12-20
Copyright © 2025 网站备案号: 浙ICP备20017730号 身体没有灵魂是死的,信心没有行为也是死的。
主页
页面
  • 归档
  • 摘要
  • 杂图
  • 问题随笔
博主
Enamiĝu al vi
Enamiĝu al vi 管理员
To be, or not to be
543 文章 68 评论 594077 浏览
测试
测试
看板娘
赞赏作者

请通过微信、支付宝 APP 扫一扫

感谢您对作者的支持!

 支付宝 微信支付