Spring(三) spring对jdbc的封装

Spring源码——JDBC 前言 内容主要参考自《Spring源码深度解析》一书,算是读书笔记或是原书的补充。进入正文后可能会引来各种不适,毕竟阅读源码是件极其痛苦的事情。 本文主要涉及书中第八章的部分,依照书中内容以及个人理解对Spring源码进行了注释,详见Github仓库:https://github.com/MrSorrow/spring-framework 本章内容基于之前所说的Spring IOC 和 AOP功能... 阅读详情
spring的JdbcTemplate封装了jdbc的实现,下面通过源代码看一下其实现

1,一个执行Statement回调的接口
public interface StatementCallback {
Object doInStatement(Statement stmt) throws SQLException, DataAccessException;
}

public Object execute(StatementCallback action) throws DataAccessException {
//获取线程的同一个连接
Connection con = DataSourceUtils.getConnection(getDataSource());
Statement stmt = null;
try {
Connection conToUse = con;

if (this.nativeJdbcExtractor != null &&
this.nativeJdbcExtractor.
isNativeConnectionNecessaryForNativeStatements()) {
//通过特定厂商的特定方法,获取特定厂商的连接
conToUse = this.nativeJdbcExtractor.getNativeConnection(con);
}

stmt = conToUse.createStatement();
//计算并调用stmt.setQueryTimeout(..)
DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
Statement stmtToUse = stmt;
if (this.nativeJdbcExtractor != null) {
stmtToUse = this.nativeJdbcExtractor.getNativeStatement(stmt);
}

//执行回调
Object result = action.doInStatement(stmtToUse);
SQLWarning warning = stmt.getWarnings();
throwExceptionOnWarningIfNotIgnoringWarnings(warning);
return result;
}
catch (SQLException ex) {
//对异常进行转译,所有抛出异常都继承DataAccessException这个非受控异常
throw getExceptionTranslator().translate(
"executing StatementCallback", getSql(action), ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}

}

2,一个StatementCallback预定义实现,提供query接口
public Object query(final String sql, final ResultSetExtractor rse) throws DataAccessException {
if (sql == null) {
throw new InvalidDataAccessApiUsageException("SQL must not be null");
}

if (JdbcUtils.countParameterPlaceholders(sql, '?', "'\"") > 0) {
throw new InvalidDataAccessApiUsageException(
"Cannot execute [" + sql +
"] as a static query: it contains bind variables");
}

if (logger.isDebugEnabled()) {
logger.debug("Executing SQL query [" + sql + "]");
}

//执行回调的内部类
class QueryStatementCallback implements StatementCallback, SqlProvider {
public Object doInStatement(Statement stmt) throws SQLException {
ResultSet rs = null;
try {
if (getFetchSize() > 0) {
stmt.setFetchSize(getFetchSize());
}

if (getMaxRows() > 0) {
stmt.setMaxRows(getMaxRows());
}

rs = stmt.executeQuery(sql);
ResultSet rsToUse = rs;
if (nativeJdbcExtractor != null) {
rsToUse = nativeJdbcExtractor.getNativeResultSet(rs);
}

//又一个回调
return rse.extractData(rsToUse);
}
finally {
JdbcUtils.closeResultSet(rs);
}

}


public String getSql() {
return sql;
}

}

return execute(new QueryStatementCallback());
}
3,看一下一个预定义的ResultSetExtractor实现
private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor {

private final RowCallbackHandler rch;

public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) {
this.rch = rch;
}


public Object extractData(ResultSet rs) throws SQLException {
//利用RowCallbackHandler处理resultset,返回处理结果List
while (rs.next()) {
this.rch.processRow(rs);
}

if (this.rch instanceof ResultReader) {
return ((ResultReader) this.rch).getResults();
}

else {
return null;
}

}

}


public interface ResultReader extends RowCallbackHandler {

/** *//**
* Return all results, disconnected from the JDBC ResultSet.
* Never returns null; returns the empty collection if there
* were no results.
*/

List getResults();

}



public class RowMapperResultReader implements ResultReader {

/** *//** List to save results in */
private final List results;

/** *//** The RowMapper implementation that will be used to map rows */
private final RowMapper rowMapper;

/** *//** The counter used to count rows */
private int rowNum = 0;

/** *//**
* Create a new RowMapperResultReader.
*
@param rowMapper the RowMapper which creates an object for each row
*/

public RowMapperResultReader(RowMapper rowMapper) {
this(rowMapper, 0);
}


/** *//**
* Create a new RowMapperResultReader.
*
@param rowMapper the RowMapper which creates an object for each row
*
@param rowsExpected the number of expected rows
* (just used for optimized collection handling)
*/

public RowMapperResultReader(RowMapper rowMapper, int rowsExpected) {
// Use the more efficient collection if we know how many rows to expect:
// ArrayList in case of a known row count, LinkedList if unknown
this.results = (rowsExpected > 0) ? (List) new ArrayList(rowsExpected) : (List) new LinkedList();
this.rowMapper = rowMapper;
}


public void processRow(ResultSet rs) throws SQLException {
this.results.add(this.rowMapper.mapRow(rs, this.rowNum++));
}


public List getResults() {
return this.results;
}


}
4,连接是如何获取的
public abstract class DataSourceUtils {

//..

public static Connection doGetConnection(DataSource dataSource) throws SQLException {
Assert.notNull(dataSource, "No DataSource specified");
//利用ThreadLocal,获取当前线程对应dataSource的connection封装---ConnectionHolder
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null) {
conHolder.requested();
return conHolder.getConnection();
}

//如果conHolder为空,为当前线程获取一个新连接,并设置ThreadLocal
logger.debug("Opening JDBC Connection");
Connection con = dataSource.getConnection();

if (TransactionSynchronizationManager.isSynchronizationActive()) {
logger.debug("Registering transaction synchronization for JDBC Connection");
// Use same Connection for further JDBC actions within the transaction.
// Thread-bound object will get removed by synchronization at transaction completion.
conHolder = new ConnectionHolder(con);
conHolder.setSynchronizedWithTransaction(true);
conHolder.requested();
TransactionSynchronizationManager.registerSynchronization(
new ConnectionSynchronization(conHolder, dataSource));
TransactionSynchronizationManager.bindResource(dataSource, conHolder);
}


return con;
}

//注意异常的改变
public static Connection getConnection(DataSource dataSource) throws CannotGetJdbcConnectionException {
try {
return doGetConnection(dataSource);
}

catch (SQLException ex) {
throw new CannotGetJdbcConnectionException("Could not get JDBC Connection", ex);
}

}

}
5,getResource和bindResource实现
public abstract class TransactionSynchronizationManager {

//..

private static final ThreadLocal resources = new ThreadLocal();

private static final ThreadLocal synchronizations = new ThreadLocal();

public static Object getResource(Object key) {
Map map = (Map) resources.get();
if (map == null) {
return null;
}

Object value = map.get(key);
if (value != null && logger.isDebugEnabled()) {
logger.debug("Retrieved value [" + value + "] for key [" + key + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}

return value;
}

public static void bindResource(Object key, Object value) throws IllegalStateException {
Map map = (Map) resources.get();
// set ThreadLocal Map if none found
if (map == null) {
map = new HashMap();
resources.set(map);
}

if (map.containsKey(key)) {
throw new IllegalStateException("Already value [" + map.get(key) + "] for key [" + key +
"] bound to thread [" + Thread.currentThread().getName() + "]");
}

map.put(key, value);
if (logger.isDebugEnabled()) {
logger.debug("Bound value [" + value + "] for key [" + key + "] to thread [" +
Thread.currentThread().getName() + "]");
}

}

}

6,ConnectionHolder 类

public class ConnectionHolder extends ResourceHolderSupport {

private final ConnectionHandle connectionHandle;

private Connection currentConnection;

/** *//**
* Create a new ConnectionHolder for the given ConnectionHandle.
*
@param connectionHandle the ConnectionHandle to hold
*/

public ConnectionHolder(ConnectionHandle connectionHandle) {
this.connectionHandle = connectionHandle;
}


/** *//**
* Create a new ConnectionHolder for the given JDBC Connection,
* wrapping it with a SimpleConnectionHandle.
*
@param connection the JDBC Connection to hold
*
@see SimpleConnectionHandle
*/

public ConnectionHolder(Connection connection) {
this.connectionHandle = new SimpleConnectionHandle(connection);
}


/** *//**
* Return the ConnectionHandle held by this ConnectionHolder.
*/

public ConnectionHandle getConnectionHandle() {
return connectionHandle;
}


/** *//**
* Return the current Connection held by this ConnectionHolder.
* <p>This will be the same Connection until <code>released</code>
* gets called on the ConnectionHolder, which will reset the
* held Connection, fetching a new Connection on demand.
*
@see ConnectionHandle#getConnection()
*
@see #released()
*/

public Connection getConnection() {
if (this.currentConnection == null) {
this.currentConnection = this.connectionHandle.getConnection();
}

return this.currentConnection;
}


/** *//**
* Releases the current Connection held by this ConnectionHolder.
* <p>This is necessary for ConnectionHandles that expect "Connection borrowing",
* where each returned Connection is only temporarily leased and needs to be
* returned once the data operation is done, to make the Connection available
* for other operations within the same transaction. This is the case with
* JDO 2.0 DataStoreConnections, for example.
*
@see org.springframework.orm.jdo.DefaultJdoDialect#getJdbcConnection
*/

public void released() {
super.released();
if (this.currentConnection != null) {
this.connectionHandle.releaseConnection(this.currentConnection);
this.currentConnection = null;
}

}


}

public class SimpleConnectionHandle implements ConnectionHandle {

private final Connection connection;

/** *//**
* Create a new SimpleConnectionHandle for the given Connection.
*
@param connection the JDBC Connection
*/

public SimpleConnectionHandle(Connection connection) {
this.connection = connection;
}


public Connection getConnection() {
return connection;
}


public void releaseConnection(Connection con) {
}


public String toString() {
return "SimpleConnectionHandle: " + this.connection;
}


}
Spring JDBC的优雅设计 - 异常封装(下) Spring JDBC 中的异常封装 在 org.springframework.jdbc.support包下面 AbstractFallbackSQLExceptionTranslator 抽象类,提供兜底策略,这就是备胎机制。如果是蘑菇君的话,每次都会在方法后面加上一段兜底,比如: if () { } else { beitai } SQLStateSQLExceptionTrans... 阅读详情

相关推荐

Spring JDBC的优雅设计 - 异常封装(上)

JDBC里的异常之痛 在上一篇文章 Spring JDBC的优雅设计 (1) - 数据转换 的开头,蘑菇君提到过,用原生JDBC操作数据库,需要自己处理各种异常,很让人头秃。(啥玩意儿?不了解JDBC里的异常?还不快去看Java JDBC的优雅设计) 蘑菇君翻车时刻 Spring JDBC 中的异常封装 在 org.springframework.jdbc.support包下面 AbstractF...

蘑菇君的学习之路 931

Spring2.0的的新特性

  Spring框架发展实在迅速,1.x系列还火到不行的时候,2.x系列立马来了,大有一统J2EE轻量级开发标准之势。现在市面上介绍Spring2.0的书籍,已经铺天盖地地袭来,显然写这篇文章稍微有些晚,不过应某些网友的的要求,加上本文高度归纳前瞻的观点还是颇有价值的,以下便稍微谈一下Spring2.0的一些新特性好了。  1.引入基于Xml-Schema的配置语法,简化了Xml的配置  2.引入

cyangmiao的专栏 961

java连接Access数据库驱动

java连接Access数据库操做数据库驱动连接方法:public static Connection getNativeConnection(){try { if(nativeConnection!=null && !nativeConnection.isClosed()){ return nativeConnection; }else{ Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); String dburl = "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ="+SysPath.getAccessPath();// 此为NO-DSN方式 Connection conn = DriverManager.getConnection(dburl,"Administrator","123"); nativeConnection = conn; return nativeConnection; } } catch (Exception e) { com.hzfy.util.log.Log4jApp.getLogger().error("得到本地ACCESS数据库的连接异常"+e.getLocalizedMessage()); return null; } }

Spring系列文章:Spring使用JdbcTemplate

JdbcTemplate是Spring提供的⼀个JDBC模板类,是对JDBC的封装,简化JDBC代码。当然,你也可以不⽤,可以让Spring集成其它的ORM框架,例如:MyBatis、Hibernate等。第一步:引入依赖。

程序员一博 2296

手把手教你用Ubuntu Base 20.04打造轻量级ARM开发板根文件系统(附常见问题解决)

本文详细介绍了如何基于Ubuntu Base 20.04 LTS构建轻量级ARM开发板根文件系统,涵盖环境准备、镜像制作、跨架构配置、软件包定制及常见问题解决。通过实战指南,开发者可快速掌握ARM架构下的根文件系统构建技巧,优化系统性能并解决部署中的典型问题。

gin88的博客 210

MoveIt控制睿尔曼RM65机械臂:从仿真到实机的3种控制模式对比

本文详细解析了使用MoveIt框架控制睿尔曼RM65机械臂的三种核心模式:拖动规划、目标姿态规划和Python API控制,从Gazebo仿真到实机部署的完整实现路径。通过ROS环境配置、控制参数优化及实机过渡技术,为工业自动化和机器人研究提供实用指南。

727

Spring JDBC--JDBCTemplate对象

Spring框架对JDBC的简单封装,提供了一个JDBCTemplate对象简化JDBC的开发 步骤: 导入jar包 创建JdbcTemplate对象,依赖数据源DataSource JdbcTemplate template = new JdbcTemplate(datasource); 调用JdbcTemplate的方法来完成CRUD的操作 * update():执行DML语句。增、删、改语...

qq_44083614的博客 401

【速通版!语义通信基础与前沿学习计划】

🧠语义通信基础与前沿学习计划

dally2的博客 1412

Spring5笔记5之使用JdbcTemplate操作数据库

什么是 JdbcTemplate?Spring 框架对JDBC 进行封装,使用 JdbcTemplate方便实现对数据库操作。

xk1835217729的博客 648

1、STVD和STVP的使用及串口烧写程序教程

文章目录一、前述二、STVD的使用三、STVP的使用1、STVP的作用:2、STVP的使用四、串口烧录程序 一、前述 STVD是意法半导体推出的,可以支持STM8和STM32 而IAR不尽如此,还支持51,MSP430等芯片 软件开发环境:编写程序,调试软件功能,下载固件到单片机中 硬件开发环境:连接外围电路,驱动功能外设,实现电气功能 最终构成一个以STM8系列单片机作为控制核心的应用系统。 MCS-51 一般的开发环境是 IAR 和 Keil STM8 一般的开发环境是 IAR 和 ST

Clichong 1万+

华北理工大学以升实验班蓝桥杯选拔赛题解

文章目录华北理工大学以升实验班蓝桥杯选拔赛题解A:期末考试题目描述题目讲解代码B:月份题目描述题目讲解代码C:打饭题目描述题目讲解代码D : 正弦波信号题目描述题目讲解代码E : 亲爱的长方形题目描述题目讲解代码F:挖金子题目描述题目讲解代码G : 金金的游戏题目描述题目讲解代码H : 区间和题目描述题目讲解代码详细视频讲解请关注华北理工大学b站账号。 华北理工大学以升实验班蓝桥杯选拔赛题解 A:期末考试 题目描述 Description 期末考试过去许多天了,如今成绩都出来了,那么现在让我们对成绩我分个类

Qq1739206233的博客 1127

9.Spring对JDBC的封装

Spring框架对JDBC的简单封装。提供了一个JDBCTemplat对象简化JDBC的开发 * 步骤: 1. 导入jar包 2. 创建JdbcTemplate对象。依赖于数据源DataSource * JdbcTemplate template = new JdbcTemplate(ds); 3. 调用JdbcTemplate的方法来完成CRUD的操作 * update():执行DML语句。增、删、改语句 * queryForMap():查询结果将结果集封装为map集合,将列名作为key,将值作

Lolita1997的博客 373

基于Ultralytics RT-DETR的工业缺陷检测实战:从NEU-DET数据集准备到模型部署

本文详细介绍了基于Ultralytics框架和RT-DETR模型进行工业缺陷检测的完整实战流程。内容涵盖从NEU-DET数据集准备、YOLO格式转换、环境配置,到模型训练、关键参数调优、性能验证与可视化分析,最后提供了ONNX等格式的模型部署方案,为工业质检场景提供了一套高效、可落地的AI解决方案。

weixin_29168393的博客 339

java三大框架struts+hibernate+spring学习总结

Struts  1. struts是一个按MVC模式设计的Web层框架,其实它就是一个大大的servlet,这个Servlet名为ActionServlet,或是 ActionServlet的子类。我们可以在web.xml文件中将符合某种特征的所有请求交给这个Servlet处理,这个Servlet再参照一个配置文件(通常为/WEB-INF/struts-config.xml)将各个请求分别分

java4Fun 9493

Python爬虫教程:抓取社交媒体内容(以Facebook和Instagram为例)

为什么抓取社交媒体内容?品牌分析与监测:通过抓取品牌、产品或服务相关的社交媒体数据,可以获得公众对其的评价,识别市场趋势,制定营销策略。情感分析:分析用户在社交平台上的情感倾向,如对某事件、产品、服务的正面或负面情绪。舆情监控:通过抓取大量社交媒体内容,监测公众对热点事件的反应,发现潜在的社会问题。用户行为分析社交媒体的数据类型:帖子和内容:包括用户发布的文本、图片、视频等。用户互动用户信息:包括用户名、粉丝数、关注数等社交信息。社交媒体的反爬虫机制:API限制。

2201_76125261的博客 1338

三相五柱式消弧线圈自动测控装置设计与实现

本文设计了一种基于STM32的三相五柱式消弧线圈自动测控装置。该装置采用信号注入法检测系统对地电容电流,通过PID自适应算法调节消弧线圈电感值,实现单相接地故障时的快速补偿。硬件系统包含信号采集、注入、控制执行等模块,软件采用Goertzel算法提取特征频率信号,结合增量式PID实现精确控制。实验结果表明,装置电容检测误差小于2%,调谐响应时间小于50ms,满足配电网对消弧线圈自动调谐的技术要求。

AI的内部世界的博客 239

Spring JDBC - Spring JDBC模版使用

Spring JDBC模版;Spring JDBC支持类

weixin_52937170的博客 1580

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Spring框架对JDBC的简单封装

Spring对数据库的操作使用JdbcTemplate来封装JDBC,结合Spring的注入特性可以很方便的实现对数据库的访问操作,简化JDBC的开发 步骤: 1. 导入jar包 2. 创建JdbcTemplate对象。依赖于数据源DataSource * JdbcTemplate template = new JdbcTemplate(d...

ZLX_508的博客 1241

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

8 spring对JDBC的封装

1.首先创建一个表,塞点数据 2.创建一个Bean去接受它 **public class User_name { private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public St

jiangjun_feng的博客 206

Spring框架——JdbcTemplate(Spring对Jdbc的封装)

1.JdbcTemplate简介Spring提供的一个操作数据库的技术JdbcTemplate,是对Jdbc的封装。语法风格非常接近DBUtils。 JdbcTemplate可以直接操作数据库,加快效率,而且学这个JdbcTemplate也是为声明式事务做准备,毕竟要对数据库中的数据进行操纵! JdbcTemplate中并没有提供一级缓存,以及类与类之间的关联关系!就像是spring提供

Mr_zhaoz的博客 1万+

JDBC之Spring封装JDBCTemplate

一,概述 Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发。 步骤: 1. 导入jar包 2. 创建JdbcTemplate对象。依赖于数据源DataSource * JdbcTemplate template = new JdbcTemplate(ds); 3. 调用JdbcTemplate的方法来完成CRUD的操作 * update():执行DML语句。增、删、改语句 * queryForMap():查询结果将结果集封装为map集合,将列名作为key,

weixin_43529573的博客 441

Java之JDBCTemplate——Spring对JDBC的封装

JDBCTemplate Spring-JDBCTemplate JDBCTemplate是Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发,我们只需定义sql语句和执行sql语句,不需要去申请连接,也不需要去释放资源,其内部已经帮我们做了资源的建立和释放。 (Template:模板) 步骤: 1、导入JDBCTemplate相关的jar包 2、创建JdbcTemplate对象。依赖于数据源DataSource 3、 调用JdbcTemplate的方法来完成CR

longool的博客 443

Spring框架学习【JdbcTemplate封装Jdbc】

1.Spring中使用JdbcTemplate封装对Jdbc的支持,使用Spring JdbcTeamplate的例子如下: (1).假设如下SQL表中有数据username=test1,passwd=test1,address=test1 : [java] view plaincopyprint? CREATE TABLE `login` (     `usern

zhixiang2010的专栏 2049

Spring学习(三)——在Spring中使用JDBC

写过 JDBC 代码的人都懂,当需要操作数据库的时候,我们需要写一堆模板式的代码,除了核心的一两句代码,其它代码一模一样。 Spring 简化了这些操作,它把那些模板式的代码都封装起来了。jdbcTemplate就是是属于dao层数据库操作一层提供的基于JDBC的解决方法 Spring 的JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码,让我们只需要编写从数据库读写数据的必须代码...

Alyson_jm的博客 742

Spring中使用MappingSQLQuery封装JDBC结果集实例

使用Spring提供的MappingSqlQuery的方法,可以很好的封装JDBC返回的结果集,创建相应的domain对象,MappingSqlQuery的子类必须要实现mapRow方法,mapRow方法从底层的ResultSet中获取数据,返回对应的domain对象 数据库脚本(MySQL) CREATE TABLE `test` (  `testid` varchar(10) 

我的世界我的梦 6553

Spring对JDBC封装JdbcTemplate的概述与查询功能

一、JdbcTemplate的概述 Spring框架经常在项目中处于“粘合剂”的作用,减少项目的硬代码。 Spring除了能整合持久层框架外,自身也提供了对数据库JDBC操作的封装类–JdbcTemplate。 JdbcTemplate是对JDBC很轻的封装,具有较高的执行效率,一般用于系统数据库并发操作压力大的项目中。 二、开发环境 系统:Windows10 开发软件:IDEA

hanziang1996的博客 3117
上一篇: Spring(二) @Autowired
下一篇: android数据库操作(一) SQLlite数据库帮助类
ufocode
博客等级 码龄23年 36粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值