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%。公司已连发两份股票生意异动公告。 是炒作,还是…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法
使用 ROS1-Noetic 和 mavros v1.20.1, 携带经纬度海拔的话题主要有三个: /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码,来分析他们的发布过程。发现前两个话题都对应了同一…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
Qt Quick Controls模块功能及架构
Qt Quick Controls是Qt Quick的一个附加模块,提供了一套用于构建完整用户界面的UI控件。在Qt 6.0中,这个模块经历了重大重构和改进。 一、主要功能和特点 1. 架构重构 完全重写了底层架构,与Qt Quick更紧密集成 移除了对Qt Widgets的依赖&…...
