Spring中的JdbcTemplate的使用
在最近的一个工作中,为了简单方便我就是用了Spring自带的JdbcTemplate来访问数据库,我以为之前自己很熟练的掌握,后来才发现我太天真了,踩了很多坑。
基本方法
JdbcTemplate自带很多方法可以执行SQL语句,以下我主要列举,比较常用的方法
//执行SQL,返回一个对象
@Override
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args)throws DataAccessException {List<T> results = query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));return DataAccessUtils.requiredSingleResult(results);
}//同上,不过多要传入返回值的对象的Class
@Override
public <T> T queryForObject(String sql, Class<T> requiredType)throws DataAccessException {return queryForObject(sql, getSingleColumnRowMapper(requiredType));
}//执行SQL,返回一个Map对象
@Override
public Map<String, Object> queryForMap(String sql, Object... args)throws DataAccessException {return queryForObject(sql, args, getColumnMapRowMapper());
}//执行SQL,返回一个List对象
@Override
public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {return query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper));
}//执行SQL,返回一个List对象
@Override
@Override
public <T> List<T> queryForList(String sql, Class<T> elementType, Object... args)throws DataAccessException {return query(sql, args, getSingleColumnRowMapper(elementType));
}//执行一条SQL,主要用于更新、新增数据
@Override
public int update(String sql, Object... args) throws DataAccessException {return update(sql, newArgPreparedStatementSetter(args));
}//执行SQL,返回一个List对象,List里是Map对象
@Override
public List<Map<String, Object>> queryForList(String sql, Object... args) throws DataAccessException {return query(sql, args, getColumnMapRowMapper());
}
注意点
至少返回一个对象
@Override
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args)throws DataAccessException {List<T> results = query(sql, args, new RowMapperResultSetExtractor<T>(rowMapper, 1));return DataAccessUtils.requiredSingleResult(results);
}public RowMapperResultSetExtractor(RowMapper<T> rowMapper, int rowsExpected) {Assert.notNull(rowMapper, "RowMapper is required");this.rowMapper = rowMapper;this.rowsExpected = rowsExpected;
}
以上代码就是可以知道,必须返回一个对象,不能返回null,如果从数据库查找发现没有一条信息吻合就会报错,报以下的错误
org.springframework.dao.IncorrectResultSizeDataAccessException: Incorrect result size: expected 1, actual 0
所以如果不确定是否有信息,就使用query、queryForList来避免错误。返回单对象一般会有这样的限制,如果自己不确定可以使用该方法的时候看一下源码,设置了1就代表必须要有一个值。
返回指定对象
JdbcTemplate里面这样的方法,就是可以传入了一个对象的Class值,就可以返回该对象的值,但是需要注意,它只支持基础类型
//例如,它支持以下的写法
public Integer getCourseCount(String sql){return (Integer) jdbcTemplate.queryForObject(sql,java.lang.Integer.class);
}
通过源代码发现Class<T> requiredType这个参数支持以下类型,源代码就是从primitiveWrapperTypeMap查找是否是一下类型:
primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
primitiveWrapperTypeMap.put(Byte.class, byte.class);
primitiveWrapperTypeMap.put(Character.class, char.class);
primitiveWrapperTypeMap.put(Double.class, double.class);
primitiveWrapperTypeMap.put(Float.class, float.class);
primitiveWrapperTypeMap.put(Integer.class, int.class);
primitiveWrapperTypeMap.put(Long.class, long.class);
primitiveWrapperTypeMap.put(Short.class, short.class);
如果需要返回自定义对象就需要另外的方法:
如果返回List<T>,就如以下的案例
public List<Course> getCourseList(String sql){return jdbcTemplate.query(sql,new RowMapper<Course>(){@Overridepublic Course mapRow(ResultSet rs, int rowNum) throws SQLException {Integer id=rs.getInt("id");String coursename=rs.getString("coursename");//把数据封装到对象里Course course=new Course();course.setId(id);course.setCoursename(coursename.trim());return course;}});
}
或者使用List<Map<String,Object>>
@Override
public List<MyScoreDto> listMyScore(Integer studentId) {String sql = "select g.score,c.className from grade g"+ " left join teacher t on t.id=g.teacherId"+ " left join student s on s.id=g.studentId"+ " left join classname c on c.id=t.classNameId"+ " where s.id="+studentId;List<Map<String,Object>> list = jdbcTemplate.queryForList(sql);if(list!=null && list.size()>0){List<MyScoreDto> ls = new ArrayList<MyScoreDto>();for(int i=0;i<list.size();i++){MyScoreDto c = new MyScoreDto();try {BeanUtils.populate(c, list.get(i));} catch (IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}ls.add(c);}return ls;}return null;
}
使用了org.apache.commons.beanutils.BeanUtils把Map对象转换为自定义对象。
后来为了方便起见我还自己写了一个RowMapper,来简化操作
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;import org.springframework.jdbc.core.RowMapper;import com.lsb.exam.utils.StringUtils;public class MyRowMapper<T> implements RowMapper<T> {Class<T> cls;public MyRowMapper(Class<T> cls) {this.cls = cls;}@Overridepublic T mapRow(ResultSet rs, int rowNum) {try {Field[] fields = cls.getDeclaredFields();T obj = cls.newInstance();// 获取所有的属性for (Field field : fields) {field.setAccessible(true);if (field.getGenericType().toString().equals("class java.lang.Integer")) {Method m = obj.getClass().getDeclaredMethod("set" + StringUtils.firstChar2UpperCase(field.getName()), java.lang.Integer.class);m.invoke(obj, rs.getInt(field.getName()));}if (field.getGenericType().toString().equals("class java.lang.String")) {Method m = obj.getClass().getDeclaredMethod("set" + StringUtils.firstChar2UpperCase(field.getName()), java.lang.String.class);m.invoke(obj, rs.getString(field.getName()));}if (field.getGenericType().toString().equals("class java.util.Date")) {Method m = obj.getClass().getDeclaredMethod("set" + StringUtils.firstChar2UpperCase(field.getName()), java.util.Date.class);m.invoke(obj, rs.getDate(field.getName()));}}return obj;} catch (Exception e) {e.printStackTrace();return null;}}
}
上面有一个错误,就是如果对象继承了父类,就无法将值注入到父类的的属性中,因为cls.getDeclaredFields()无法获取父类的属性,所以我又改了一种方法
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import org.springframework.jdbc.core.RowMapper;import com.lsb.exam.utils.StringUtils;public class MyRowMapper<T> implements RowMapper<T> {Class<T> cls;public MyRowMapper(Class<T> cls) {this.cls = cls;}@Overridepublic T mapRow(ResultSet rs, int rowNum) {try {T obj = cls.newInstance();//这个只能获取当前类的共有私有字段//Field[] fields = cls.getDeclaredFields();List<Field> list = new ArrayList<>();Class<?> c = cls;//循环获取while(c != null){list.addAll(Arrays.asList(c.getDeclaredFields()));c = c.getSuperclass();}// 获取所有的属性for (Field field : list) {field.setAccessible(true);if (field.getGenericType().toString().equals("class java.lang.Integer")) {Method m = obj.getClass().getMethod("set" + StringUtils.firstChar2UpperCase(field.getName()), java.lang.Integer.class);m.invoke(obj, rs.getInt(field.getName()));}if (field.getGenericType().toString().equals("class java.lang.String")) {Method m = obj.getClass().getMethod("set" + StringUtils.firstChar2UpperCase(field.getName()), java.lang.String.class);m.invoke(obj, rs.getString(field.getName()));}if (field.getGenericType().toString().equals("class java.util.Date")) {Method m = obj.getClass().getMethod("set" + StringUtils.firstChar2UpperCase(field.getName()), java.util.Date.class);m.invoke(obj, rs.getDate(field.getName()));}}return obj;} catch (Exception e) {e.printStackTrace();return null;}}
}
其实过程中,有一个反射的知识很重要,关于方法的介绍:
1、获取class
| 方法 | 描述 |
|---|---|
| object.getClass() | 获取这个实例所属的class对象 |
| T.class | 通过类型获取所属class对象 |
| Class.forName() | 通过类路径获取class对象 |
| Class.getSuperclass() | 获取父类的class对象 |
| Class.getClasses() | 获取类内所有的公开的类,接口,枚举成员,以及它继承的成员(特指类) |
| Class.getDeclaredClasses() | 通过类内显示声明的类,接口 |
| Class.getEnclosingClass() | 获取闭包类 |
2、获取属性
| 方法 | 描述 |
|---|---|
| getDeclaredField(String name) | 获取指定字段(公有,私有),不包括父类字段 |
| getField(String name) | 获取指定字段(公有),包括父类字段 |
| getDelaredFields() | 获取所有类内显示声明的字段(公有,私有),不包括父类字段 |
| getFields() | 获取所有字段(公有),包括父类字段 |
3、获取方法
| 方法 | 描述 |
|---|---|
| getDeclaredMethod(String name, Class<?> … paramType) | 获取指定方法(公有,私有),不包括父类方法 |
| getMethod(String name, Class<?> … paramType) | 获取指定方法(公有),包括父类方法 |
| getDeclaredMethods() | 获取所有声明方法(公有,私有),不包括父类方法 |
| getMethods() | 获取所有方法(公有),包括父类方法 |
上面的信息可以访问Oracle网站的反射信息。
相关文章:
Spring中的JdbcTemplate的使用
在最近的一个工作中,为了简单方便我就是用了Spring自带的JdbcTemplate来访问数据库,我以为之前自己很熟练的掌握,后来才发现我太天真了,踩了很多坑。 基本方法 JdbcTemplate自带很多方法可以执行SQL语句,以下我主要列举…...
机器学习——boosting之GBDT
现在要开始重点关注名字了,名字透漏了很多信息!名字暗藏线索! GBDT,Gradient Boosting Decision Tree: 梯度提升决策树 果然信息很丰富 梯度:意味着计算有迭代递进关系,但还不明确是怎么迭代递进的 提升&…...
如何选择报修管理系统?报修工单管理系统有哪些功能和优势?
报修管理系统是一种能够帮助企业快速反应设备故障和异常情况,并将问题及时通知到相关人员,并对问题进行统计和分析的系统。它能够有效提高企业的工作效率,并减少人员成本的支出。那么,报修工单管理系统有哪些功能和优势呢?下面以“…...
Matlab图像处理-
有些时候,直接利用图像的灰度直方图选择阈值不是非常直观,这时,可以利用图像三个通道的直方图来进行图像分割,操作步骤如上文所示,下图为原始图片。 下图为三通道直方图。 下图将三个通道的直方图会绘制到一个图表上&a…...
数据接口工程对接BI可视化大屏(二)创建BI空间
第2章 创建BI空间 2.1 SugarBI介绍 网站地址:https://cloud.baidu.com/product/sugar.html SugarBI是百度推出的自助BI报表分析和制作可视化数据大屏的强大工具。 基于百度Echarts提供丰富的图表组件,开箱即用、零代码操作、无需SQL,5分钟即可完成数…...
Struts.xml 配置文件说明
<?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <!--…...
阿里巴巴API接口解析,实现获得商品详情
要解析阿里巴巴API接口并实现获取商品详情,你需要按照以下步骤进行操作: 了解阿里巴巴开放平台:访问阿里巴巴开放平台,并了解相关的API文档、开发者指南和规定。注册开发者账号:在阿里巴巴开放平台上注册一个开发者账…...
9.(Python数模)(分类模型一)K-means聚类
Python实现K-means聚类 K-means原理 K-means均值聚类算法作为最经典也是最基础的无标签分类学习算法。其实质就是根据两个数据点的距离去判断他们是否属于一类,对于一群点,就是类似用几个圆去框定这些点(簇),然后圆心…...
MinIO集群模式信息泄露漏洞(CVE-2023-28432)
前言:MinIO是一个用Golang开发的基于Apache License v2.0开源协议的对象存储服务。虽然轻量,却拥有着不错的性能。它兼容亚马逊S3云存储服务接口,非常适合于存储大容量非结构化的数据。该漏洞会在前台泄露用户的账户和密码。 0x00 环境配置 …...
【从零单排Golang】第十五话:用sync.Once实现懒加载的用法和坑点
在使用Golang做后端开发的工程中,我们通常需要声明一些一些配置类或服务单例等在业务逻辑层面较为底层的实例。为了节省内存或是冷启动开销,我们通常采用lazy-load懒加载的方式去初始化这些实例。初始化单例这个行为是一个非常经典的并发处理的案例&…...
常见注意力机制
注意力机制 (具有自适应性) 18年提出的一种新的 卷积注意力模块 ;对前馈卷积神经网络 是一个 简单而有效的 注意力模块 ; 因为它的 轻量级和通用性 ,可以 无缝集成到任何CNN网络 当中, 对我们来讲&…...
解决报错之org.aspectj.lang不存在
一、IDEA在使用时,可能会遇到maven依赖包明明存在,但是build或者启动时,报找不存在。 解决办法:第一时间检查Setting->Maven-Runner红圈中的√有没有选上。 二、有时候,明明依赖包存在,但是Maven页签中…...
java之SpringBoot基础篇、前后端项目、MyBatisPlus、MySQL、vue、elementUi
文章目录 前言JC-1.快速上手SpringBootJC-1-1.SpringBoot入门程序制作(一)JC-1-2.SpringBoot入门程序制作(二)JC-1-3.SpringBoot入门程序制作(三)JC-1-4.SpringBoot入门程序制作(四)…...
golang中如何判断字符串是否包含另一字符串
golang中如何判断字符串是否包含另一字符串 在Go语言中,可以使用strings.Contains()函数来判断一个字符串是否包含另一个字符串。该函数接受两个参数:要搜索的字符串和要查找的子字符串,如果子字符串存在于要搜索的字符串中,则返…...
ONNX OpenVino TensorRT MediaPipe NCNN Diffusers ComfyUI
框架 和Java生成的中间文件可以在JVM上运行一样,AI技术在具体落地应用方面,和其他软件技术一样,也需要具体的部署和实施的。既然要做部署,那就会有不同平台设备上的各种不同的部署方法和相关的部署架构工具 onnx 在训练模型时可以…...
java中使用 Integer 和 int 的 含义、使用方法 及之间的区别
学习目标: 学习目标如下: 明确 Integer 和 int 的 含义、使用方法 及之间的区别 学习内容: 一、区别: 1.Integer是int的包装类,int则是java的一种基本的数据类型; 2.Integer变量必须实例化之后才能使用&a…...
点云从入门到精通技术详解100篇-点云的特征检测
目录 前言 点云配准的研究背景 多元时间序列的相似性分析研究背景及意义 国内外研究现状...
DOM破坏绕过XSSfilter例题
目录 一、什么是DOM破坏 二、例题1 编辑 三、多层关系 1.Collection集合方式 2.标签关系 四、例题2 一、什么是DOM破坏 DOM破坏(DOM Clobbering)指的是对网页上的DOM结构进行不当的修改,导致页面行为异常、性能问题、安全风险或其他不…...
代码随想录Day_56打卡
①、两个字符串的删除操作 给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 事例: 输入: word1 "sea", word2 "eat" 输出: 2 解释: 第一步将 "sea&…...
高忆管理:六连板捷荣技术或难扛“华为概念股”大旗
在本钱商场上名不见经传的捷荣技术(002855.SZ)正扛起“华为概念股”大旗。 9月6日,捷荣技术已拿下第六个连续涨停板,短短七个生意日,股价累积涨幅逾越90%。公司已连发两份股票生意异动公告。 是炒作,还是…...
告别电量焦虑:用STM32+IP2366打造你的140W双向快充移动电源方案
告别电量焦虑:用STM32IP2366打造140W双向快充移动电源方案 1. 为什么需要高性能移动电源方案 当代智能设备对电力的需求呈现爆发式增长。从智能手机到笔记本电脑,从无人机到便携式医疗设备,快速充电和大容量储能已成为刚需。传统移动电源方…...
PDB文件管理实战:用符号服务器加速团队协作调试(含VS2022配置示例)
PDB文件管理实战:构建企业级符号服务器加速团队协作调试 当开发团队规模超过10人时,调试符号管理就会从技术问题升级为协作难题。想象这样的场景:周五下午5点,QA报告生产环境出现崩溃转储,开发团队需要立即分析。但当工…...
r5:天气预测
- **🍨 本文为[🔗365天深度学习训练营](https://mp.weixin.qq.com/s/o-DaK6aQQLkJ8uE4YX1p3Q) 中的学习记录博客** - **🍖 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)** 文章目录 概要整体架构流程代码运行技术名词解释小…...
突破音乐加密限制:Unlock Music实现跨平台音频自由解决方案
突破音乐加密限制:Unlock Music实现跨平台音频自由解决方案 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址: …...
GDBFrontend表达式求值器深度解析:多窗口实时变量监控技巧
GDBFrontend表达式求值器深度解析:多窗口实时变量监控技巧 【免费下载链接】gdb-frontend ☕ GDBFrontend is an easy, flexible and extensible gui debugger. Try it on https://debugme.dev 项目地址: https://gitcode.com/gh_mirrors/gd/gdb-frontend GD…...
如何高效使用猫抓cat-catch:5个关键技巧完全指南
如何高效使用猫抓cat-catch:5个关键技巧完全指南 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你是否经常遇到这样的情况:…...
STC89C52抢答器DIY避坑指南:从万能板焊接调试到常见故障排查(蜂鸣器不响、按键失灵)
STC89C52抢答器DIY避坑指南:从万能板焊接调试到常见故障排查 在电子制作领域,抢答器是一个经典的单片机实践项目。不同于市面上现成的模块化套件,使用万能板手工焊接STC89C52抢答器不仅能深入理解电路原理,更能锻炼实际动手能力。…...
3分钟找回丢失文件!FSearch让Linux搜索体验飞起来
3分钟找回丢失文件!FSearch让Linux搜索体验飞起来 【免费下载链接】fsearch A fast file search utility for Unix-like systems based on GTK3 项目地址: https://gitcode.com/gh_mirrors/fs/fsearch 你是否曾在Linux系统中花费数分钟甚至数小时寻找一个文件…...
human-pose-estimation.pytorch:简单而强大的人体姿态估计终极指南
human-pose-estimation.pytorch:简单而强大的人体姿态估计终极指南 【免费下载链接】human-pose-estimation.pytorch The project is an official implement of our ECCV2018 paper "Simple Baselines for Human Pose Estimation and Tracking(https://arxiv.o…...
告别Node版本混乱!用NVM管理多项目环境(Mac保姆级指南+Zsh配置)
告别Node版本混乱!用NVM管理多项目环境(Mac保姆级指南Zsh配置) 在开发过程中,你是否遇到过这样的场景:接手一个老项目时,发现它依赖Node.js 12.x版本,而新项目却要求使用18.x甚至更高版本&#…...
