当前位置: 首页 > news >正文

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

所以如果不确定是否有信息,就使用queryqueryForList来避免错误。返回单对象一般会有这样的限制,如果自己不确定可以使用该方法的时候看一下源码,设置了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的使用

在最近的一个工作中&#xff0c;为了简单方便我就是用了Spring自带的JdbcTemplate来访问数据库&#xff0c;我以为之前自己很熟练的掌握&#xff0c;后来才发现我太天真了&#xff0c;踩了很多坑。 基本方法 JdbcTemplate自带很多方法可以执行SQL语句,以下我主要列举&#xf…...

机器学习——boosting之GBDT

现在要开始重点关注名字了&#xff0c;名字透漏了很多信息&#xff01;名字暗藏线索&#xff01; GBDT&#xff0c;Gradient Boosting Decision Tree: 梯度提升决策树 果然信息很丰富 梯度&#xff1a;意味着计算有迭代递进关系&#xff0c;但还不明确是怎么迭代递进的 提升&…...

如何选择报修管理系统?报修工单管理系统有哪些功能和优势?

报修管理系统是一种能够帮助企业快速反应设备故障和异常情况&#xff0c;并将问题及时通知到相关人员&#xff0c;并对问题进行统计和分析的系统。它能够有效提高企业的工作效率&#xff0c;并减少人员成本的支出。那么,报修工单管理系统有哪些功能和优势呢&#xff1f;下面以“…...

Matlab图像处理-

有些时候&#xff0c;直接利用图像的灰度直方图选择阈值不是非常直观&#xff0c;这时&#xff0c;可以利用图像三个通道的直方图来进行图像分割&#xff0c;操作步骤如上文所示&#xff0c;下图为原始图片。 下图为三通道直方图。 下图将三个通道的直方图会绘制到一个图表上&a…...

数据接口工程对接BI可视化大屏(二)创建BI空间

第2章 创建BI空间 2.1 SugarBI介绍 网站地址:https://cloud.baidu.com/product/sugar.html SugarBI是百度推出的自助BI报表分析和制作可视化数据大屏的强大工具。 基于百度Echarts提供丰富的图表组件&#xff0c;开箱即用、零代码操作、无需SQL&#xff0c;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接口并实现获取商品详情&#xff0c;你需要按照以下步骤进行操作&#xff1a; 了解阿里巴巴开放平台&#xff1a;访问阿里巴巴开放平台&#xff0c;并了解相关的API文档、开发者指南和规定。注册开发者账号&#xff1a;在阿里巴巴开放平台上注册一个开发者账…...

9.(Python数模)(分类模型一)K-means聚类

Python实现K-means聚类 K-means原理 K-means均值聚类算法作为最经典也是最基础的无标签分类学习算法。其实质就是根据两个数据点的距离去判断他们是否属于一类&#xff0c;对于一群点&#xff0c;就是类似用几个圆去框定这些点&#xff08;簇&#xff09;&#xff0c;然后圆心…...

MinIO集群模式信息泄露漏洞(CVE-2023-28432)

前言&#xff1a;MinIO是一个用Golang开发的基于Apache License v2.0开源协议的对象存储服务。虽然轻量&#xff0c;却拥有着不错的性能。它兼容亚马逊S3云存储服务接口&#xff0c;非常适合于存储大容量非结构化的数据。该漏洞会在前台泄露用户的账户和密码。 0x00 环境配置 …...

【从零单排Golang】第十五话:用sync.Once实现懒加载的用法和坑点

在使用Golang做后端开发的工程中&#xff0c;我们通常需要声明一些一些配置类或服务单例等在业务逻辑层面较为底层的实例。为了节省内存或是冷启动开销&#xff0c;我们通常采用lazy-load懒加载的方式去初始化这些实例。初始化单例这个行为是一个非常经典的并发处理的案例&…...

常见注意力机制

注意力机制 &#xff08;具有自适应性&#xff09; 18年提出的一种新的 卷积注意力模块 &#xff1b;对前馈卷积神经网络 是一个 简单而有效的 注意力模块 &#xff1b; 因为它的 轻量级和通用性 &#xff0c;可以 无缝集成到任何CNN网络 当中&#xff0c; 对我们来讲&…...

解决报错之org.aspectj.lang不存在

一、IDEA在使用时&#xff0c;可能会遇到maven依赖包明明存在&#xff0c;但是build或者启动时&#xff0c;报找不存在。 解决办法&#xff1a;第一时间检查Setting->Maven-Runner红圈中的√有没有选上。 二、有时候&#xff0c;明明依赖包存在&#xff0c;但是Maven页签中…...

java之SpringBoot基础篇、前后端项目、MyBatisPlus、MySQL、vue、elementUi

文章目录 前言JC-1.快速上手SpringBootJC-1-1.SpringBoot入门程序制作&#xff08;一&#xff09;JC-1-2.SpringBoot入门程序制作&#xff08;二&#xff09;JC-1-3.SpringBoot入门程序制作&#xff08;三&#xff09;JC-1-4.SpringBoot入门程序制作&#xff08;四&#xff09;…...

golang中如何判断字符串是否包含另一字符串

golang中如何判断字符串是否包含另一字符串 在Go语言中&#xff0c;可以使用strings.Contains()函数来判断一个字符串是否包含另一个字符串。该函数接受两个参数&#xff1a;要搜索的字符串和要查找的子字符串&#xff0c;如果子字符串存在于要搜索的字符串中&#xff0c;则返…...

ONNX OpenVino TensorRT MediaPipe NCNN Diffusers ComfyUI

框架 和Java生成的中间文件可以在JVM上运行一样&#xff0c;AI技术在具体落地应用方面&#xff0c;和其他软件技术一样&#xff0c;也需要具体的部署和实施的。既然要做部署&#xff0c;那就会有不同平台设备上的各种不同的部署方法和相关的部署架构工具 onnx 在训练模型时可以…...

java中使用 Integer 和 int 的 含义、使用方法 及之间的区别

学习目标&#xff1a; 学习目标如下&#xff1a; 明确 Integer 和 int 的 含义、使用方法 及之间的区别 学习内容&#xff1a; 一、区别&#xff1a; 1.Integer是int的包装类&#xff0c;int则是java的一种基本的数据类型&#xff1b; 2.Integer变量必须实例化之后才能使用&a…...

点云从入门到精通技术详解100篇-点云的特征检测

目录 前言 点云配准的研究背景 多元时间序列的相似性分析研究背景及意义 国内外研究现状...

DOM破坏绕过XSSfilter例题

目录 一、什么是DOM破坏 二、例题1 ​编辑 三、多层关系 1.Collection集合方式 2.标签关系 四、例题2 一、什么是DOM破坏 DOM破坏&#xff08;DOM Clobbering&#xff09;指的是对网页上的DOM结构进行不当的修改&#xff0c;导致页面行为异常、性能问题、安全风险或其他不…...

代码随想录Day_56打卡

①、两个字符串的删除操作 给定两个单词 word1 和 word2 &#xff0c;返回使得 word1 和 word2 相同所需的最小步数。 每步 可以删除任意一个字符串中的一个字符。 事例&#xff1a; 输入: word1 "sea", word2 "eat" 输出: 2 解释: 第一步将 "sea&…...

高忆管理:六连板捷荣技术或难扛“华为概念股”大旗

在本钱商场上名不见经传的捷荣技术&#xff08;002855.SZ&#xff09;正扛起“华为概念股”大旗。 9月6日&#xff0c;捷荣技术已拿下第六个连续涨停板&#xff0c;短短七个生意日&#xff0c;股价累积涨幅逾越90%。公司已连发两份股票生意异动公告。 是炒作&#xff0c;还是…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

电脑插入多块移动硬盘后经常出现卡顿和蓝屏

当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时&#xff0c;可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案&#xff1a; 1. 检查电源供电问题 问题原因&#xff1a;多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf

FTP 客服管理系统 实现kefu123登录&#xff0c;不允许匿名访问&#xff0c;kefu只能访问/data/kefu目录&#xff0c;不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

Qemu arm操作系统开发环境

使用qemu虚拟arm硬件比较合适。 步骤如下&#xff1a; 安装qemu apt install qemu-system安装aarch64-none-elf-gcc 需要手动下载&#xff0c;下载地址&#xff1a;https://developer.arm.com/-/media/Files/downloads/gnu/13.2.rel1/binrel/arm-gnu-toolchain-13.2.rel1-x…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

【实施指南】Android客户端HTTPS双向认证实施指南

&#x1f510; 一、所需准备材料 证书文件&#xff08;6类核心文件&#xff09; 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...