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%。公司已连发两份股票生意异动公告。 是炒作,还是…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
