手写Spring:第19章-JDBC功能整合

文章目录

  • 一、目标:JDBC功能整合
  • 二、设计:JDBC功能整合
  • 三、实现:JDBC功能整合
    • 3.1 工程结构
    • 3.2 整合JDBC功能核心类图
    • 3.3 数据源操作
      • 3.3.1 数据源操作抽象类
      • 3.3.2 JDBC 工具类
    • 3.4 数据库执行
      • 3.4.1 语句处理器接口
      • 3.4.2 结果处理器接口
      • 3.4.3 行转列结果处理器实现类
      • 3.4.4 行映射器接口
      • 3.4.5 行列Map映射器实现类
      • 3.3.6 数据库执行接口
    • 3.5 数据库操作模板
      • 3.5.1 SQL提供者
      • 3.5.2 JDBC操作抽象类
      • 3.5.3 JDBC操作模板
  • 四、测试:JDBC功能整合
    • 4.1 添加测试配置
      • 4.1.1 sql数据库表
      • 4.1.2 Spring属性配置文件
      • 4.1.3 初始化 Spring和JdbcTemplate对象
    • 4.2 单元测试
      • 4.2.1 插入测试
      • 4.2.2 查询测试
  • 五、总结:JDBC功能整合

一、目标:JDBC功能整合

💡 如何结合 Spring 框架,封装 JDBC 并对外提供统一的数据操作模板?

  • JDBC 的封装主要实现的是 JdbcTemplate 的功能。Spring 对数据库的操作在 JDBC 上做了深层次的封装。使用 Spring 的注入功能,可以将 DataSource 注册到 JdbcTemplate 中使用。
  • JdbcTemplate 主要提供的方法。
    • execute 方法:用于执行任何 SQL 语句,一般用于执行 DDL 语句。
    • update 方法及 batchUpdate 方法:
      • update 方法用于执行新增、修改、删除等语句。
      • batchUpdate 方法用于执行与批处理相关的语句。
    • query 方法及 queryForXXX 方法:用于执行与查询相关的语句。
    • call 方法:用于执行与存储过程、函数相关的语句。

二、设计:JDBC功能整合

💡 设计:整合 JDBC 服务

  • Spring 框架将与 JDBC 的相关操作封装在 spring-jdbc 模块下的 JdbcTemplate 类中调用,并结合 Spring 提供的 InitializingBean 接口,在 BeanFactory 设置属性后进行相应的自定义初始化处理,将 JDBC 整合到 Spring 框架中。

在这里插入图片描述

  • DB 连接池提供数据源服务,这里将 DruidDataSource 作为连接池使用。
  • 在引入连接池后,基于 JdbcTemplate 完成对数据库的操作处理,包括执行 SQL 语句(如查询、更新和删除数据库表等操作,以及开发对应的数据库表语句)。将执行后的结果进行封装,使用 ResultSetExtractor 接口、RowMapper 接口转换数据类型。

三、实现:JDBC功能整合

3.1 工程结构

spring-step-18
|-src|-main|	|-java|		|-com.lino.springframework|			|-aop|			|	|-aspectj|			|	|	|-AspectJExpressionPointcut.java|			|	|	|-AspectJExpressionPointcutAdvisor.java|			|	|-framework|			|	|	|-adapter|			|	|	|	|-MethodBeforeAdviceInterceptor.java|			|	|	|-autoproxy|			|	|	|	|-DefaultAdvisorAutoProxyCreator.java|			|	|	|-AopProxy.java|			|	|	|-Cglib2AopProxy.java|			|	|	|-JdkDynamicAopProxy.java|			|	|	|-ProxyFactory.java|			|	|	|-ReflectiveMethodInvocation.java|			|	|-AdvisedSupport.java|			|	|-Advisor.java|			|	|-BeforeAdvice.java|			|	|-ClassFilter.java|			|	|-MethodBeforeAdvice.java|			|	|-MethodMatcher.java|			|	|-Pointcut.java|			|	|-PointcutAdvisor.java|			|	|-TargetSource.java|			|-beans|			|	|-factory|			|	|	|-annotation|			|	|	|	|-Autowired.java|			|	|	|	|-AutowiredAnnotationBeanPostProcessor.java|			|	|	|	|-Qualifier.java|			|	|	|	|-Value.java|			|	|	|-config|			|	|	|	|-AutowireCapableBeanFactory.java|			|	|	|	|-BeanDefinition.java|			|	|	|	|-BeanFactoryPostProcessor.java|			|	|	|	|-BeanPostProcessor.java|			|	|	|	|-BeanReference.java|			|	|	|	|-ConfigurableBeanFactory.java|			|	|	|	|-InstantiationAwareBeanPostProcessor.java|			|	|	|	|-SingletonBeanRegistry.java|			|	|	|-support|			|	|	|	|-AbstractAutowireCapableBeanFactory.java|			|	|	|	|-AbstractBeabDefinitionReader.java|			|	|	|	|-AbstractBeabFactory.java|			|	|	|	|-BeabDefinitionReader.java|			|	|	|	|-BeanDefinitionRegistry.java|			|	|	|	|-CglibSubclassingInstantiationStrategy.java|			|	|	|	|-DefaultListableBeanFactory.java|			|	|	|	|-DefaultSingletonBeanRegistry.java|			|	|	|	|-DisposableBeanAdapter.java|			|	|	|	|-FactoryBeanRegistrySupport.java|			|	|	|	|-InstantiationStrategy.java|			|	|	|	|-SimpleInstantiationStrategy.java|			|	|	|-xml|			|	|	|	|-XmlBeanDefinitionReader.java|			|	|	|-Aware.java|			|	|	|-BeanClassLoaderAware.java|			|	|	|-BeanFactory.java|			|	|	|-BeanFactoryAware.java|			|	|	|-BeanNameAware.java|			|	|	|-ConfigurableListableBeanFactory.java|			|	|	|-DisposableBean.java|			|	|	|-FactoryBean.java|			|	|	|-HierarcgicalBeanFactory.java|			|	|	|-InitializingBean.java|			|	|	|-ListableBeanFactory.java|			|	|	|-ObjectFactory.java|			|	|	|-PropertyPlaceholderConfigurer.java|			|	|-BeansException.java|			|	|-PropertyValue.java|			|	|-PropertyValues.java|			|-context|			|	|-annotation|			|	|	|-ClassPathBeanDefinitionScanner.java|			|	|	|-ClassPathScanningCandidateComponentProvider.java|			|	|	|-Scope.java|			|	|-event|			|	|	|-AbstractApplicationEventMulticaster.java|			|	|	|-ApplicationContextEvent.java|			|	|	|-ApplicationEventMulticaster.java|			|	|	|-ContextclosedEvent.java|			|	|	|-ContextRefreshedEvent.java|			|	|	|-SimpleApplicationEventMulticaster.java|			|	|-support|			|	|	|-AbstractApplicationContext.java|			|	|	|-AbstractRefreshableApplicationContext.java|			|	|	|-AbstractXmlApplicationContext.java|			|	|	|-ApplicationContextAwareProcessor.java|			|	|	|-ClassPathXmlApplicationContext.java|			|	|	|-ConversionServiceFactoryBean.java|			|	|-ApplicationContext.java|			|	|-ApplicationContextAware.java|			|	|-ApplicationEvent.java|			|	|-ApplicationEventPublisher.java|			|	|-ApplicationListener.java|			|	|-ConfigurableApplicationContext.java|			|-core|			|	|-convert|			|	|	|-converter|			|	|	|	|-Converter.java|			|	|	|	|-ConverterFactory.java|			|	|	|	|-ConverterRegistry.java|			|	|	|	|-GenericConverter.java|			|	|	|-support|			|	|	|	|-DefaultConversionService.java|			|	|	|	|-GenericConversionService.java|			|	|	|	|-StringToNumberConverterFactory.java|			|	|	|-ConversionService|			|	|-io|			|	|	|-ClassPathResource.java|			|	|	|-DefaultResourceLoader.java|			|	|	|-FileSystemResource.java|			|	|	|-Resource.java|			|	|	|-ResourceLoader.java|			|	|	|-UrlResource.java|			|-jdbc|			|	|-core|			|	|	|-ColumnMapRowMapper.java|			|	|	|-JdbcOperations.java|			|	|	|-JdbcTemplate.java|			|	|	|-ResultSetExtractor.java|			|	|	|-RowMapper.java|			|	|	|-RowMapperResultSetExtractor.java|			|	|	|-SqlProvider.java|			|	|	|-StatementCallback.java|			|	|-datasource|			|	|	|-DataSourceUtils.java|			|	|-support|			|	|	|-JdbcAccessor.java|			|	|	|-JdbcUtils.java|			|-stereotype|			|	|-Component.java|			|-util|			|	|-ClassUtils.java|			|	|-NumberUtils.java|			|	|-StringValueResolver.java|-test|-java|-com.lino.springframework.test|-ApiTest.java|-resources|-spring.xml

3.2 整合JDBC功能核心类图

在这里插入图片描述

  • DataSource 用于提供 Connection 链接操作,后续还会扩展辅助类(ConnectionHandlerConnectionHolder)与数据库事务结合。
  • JdbcTemplate 是执行数据库操作的入口类,提供 T execute(StatementCallback<T> action, boolean closeResources) 对数据库操作的实现。
  • JdbcOperations 用于定义很多数据库操作,包括各类的查询处理。这些操作也会调用 execute 方法进行处理,再对数据进行封装。
    • 封装操作就是使用 ResultSetExtractor 接口、RowMapper 接口进行数据类型转换的。

3.3 数据源操作

3.3.1 数据源操作抽象类

DataSourceUtils.java

package com.lino.springframework.jdbc.datasource;import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;/*** @description: 数据源操作抽象类*/
public abstract class DataSourceUtils {/*** 获取数据库连接** @param dataSource 数据库对象* @return 数据库连接*/public static Connection getConnection(DataSource dataSource) {try {return dataSource.getConnection();} catch (SQLException e) {throw new RuntimeException("Failed to obtain JDBC Connection", e);}}
}
  • DataSourceUtils 数据源的操作工具类提供了连接池的链接、关闭、释放等功能。这也是对 Spring 源码的简化。

3.3.2 JDBC 工具类

JdbcUtils.java

package com.lino.springframework.jdbc.support;import cn.hutool.core.util.StrUtil;
import java.sql.*;/*** @description: JDBC工具类*/
public class JdbcUtils {/*** Determine the column name to use. The column name is determined based on a* lookup using ResultSetMetaData.* <p>This method implementation takes into account recent clarifications* expressed in the JDBC 4.0 specification:* <p><i>columnLabel - the label for the column specified with the SQL AS clause.* If the SQL AS clause was not specified, then the label is the name of the column</i>.** @param resultSetMetaData the current meta-data to use* @param columnIndex       the index of the column for the look up* @return the column name to use* @throws SQLException in case of lookup failure*/public static String lookupColumnName(ResultSetMetaData resultSetMetaData, int columnIndex) throws SQLException {String name = resultSetMetaData.getColumnLabel(columnIndex);if (StrUtil.isEmpty(name)) {name = resultSetMetaData.getColumnName(columnIndex);}return name;}/*** Retrieve a JDBC column value from a ResultSet, using the most appropriate* value type. The returned value should be a detached value object, not having* any ties to the active ResultSet: in particular, it should not be a Blob or* Clob object but rather a byte array or String representation, respectively.* <p>Uses the {@code getObject(index)} method, but includes additional "hacks"* to get around Oracle 10g returning a non-standard object for its TIMESTAMP* datatype and a {@code java.sql.Date} for DATE columns leaving out the* time portion: These columns will explicitly be extracted as standard* {@code java.sql.Timestamp} object.** @param rs    is the ResultSet holding the data* @param index is the column index* @return the value object* @throws SQLException if thrown by the JDBC API* @see java.sql.Blob* @see java.sql.Clob* @see java.sql.Timestamp*/public static Object getResultSetValue(ResultSet rs, int index) throws SQLException {Object obj = rs.getObject(index);String className = null;if (null != obj) {className = obj.getClass().getName();}if (obj instanceof Blob) {Blob blob = (Blob) obj;obj = blob.getBytes(1, (int) blob.length());} else if (obj instanceof Clob) {Clob clob = (Clob) obj;obj = clob.getSubString(1, (int) clob.length());} else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {obj = rs.getTimestamp(index);} else if (null != className && className.startsWith("oracle.sql.DATE")) {String metadataClassName = rs.getMetaData().getColumnClassName(index);if ("java.sql.Timestamp".equals(metadataClassName) || "oracle.sql.TIMESTAMP".equals(metadataClassName)) {obj = rs.getTimestamp(index);} else {obj = rs.getDate(index);}} else if (obj instanceof Date) {if ("java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {obj = rs.getDate(index);}}return obj;}
}

3.4 数据库执行

3.4.1 语句处理器接口

StatementCallback.java

package com.lino.springframework.jdbc.core;import java.sql.SQLException;
import java.sql.Statement;/*** @description: 语句处理器*/
public interface StatementCallback<T> {/*** 执行语句** @param statement 语句对象* @return 泛型结果* @throws SQLException SQL异常*/T doInStatement(Statement statement) throws SQLException;
}

3.4.2 结果处理器接口

ResultSetExtractor.java

package com.lino.springframework.jdbc.core;import java.sql.ResultSet;
import java.sql.SQLException;/*** @description: 结果返回器*/
public interface ResultSetExtractor<T> {/*** 返回数据** @param rs 结果集* @return 泛型结果* @throws SQLException SQL异常*/T extractData(ResultSet rs) throws SQLException;
}

3.4.3 行转列结果处理器实现类

RowMapperResultSetExtractor.java

package com.lino.springframework.jdbc.core;import cn.hutool.core.lang.Assert;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;/*** @description: 行转列*/
public class RowMapperResultSetExtractor<T> implements ResultSetExtractor<List<T>> {private final RowMapper<T> rowMapper;private final int rowsExpected;public RowMapperResultSetExtractor(RowMapper<T> rowMapper) {this(rowMapper, 0);}public RowMapperResultSetExtractor(RowMapper<T> rowMapper, int rowsExpected) {Assert.notNull(rowMapper, "RowMapper is required");this.rowMapper = rowMapper;this.rowsExpected = rowsExpected;}@Overridepublic List<T> extractData(ResultSet rs) throws SQLException {List<T> results = this.rowsExpected > 0 ? new ArrayList<>(this.rowsExpected) : new ArrayList<>();int rowNum = 0;while (rs.next()) {results.add(this.rowMapper.mapRow(rs, rowNum++));}return results;}
}

3.4.4 行映射器接口

RowMapper.java

package com.lino.springframework.jdbc.core;import java.sql.ResultSet;
import java.sql.SQLException;/*** @description: 行映射器接口*/
public interface RowMapper<T> {/*** 返回行记录** @param rs     结果集对象* @param rowNum 返回的行数* @return 泛型结果* @throws SQLException SQL异常*/T mapRow(ResultSet rs, int rowNum) throws SQLException;
}

3.4.5 行列Map映射器实现类

ColumnMapRowMapper.java

package com.lino.springframework.jdbc.core;import com.lino.springframework.jdbc.support.JdbcUtils;import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;/*** @description: 行列Map映射器*/
public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {@Overridepublic Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {ResultSetMetaData rsMetaData = rs.getMetaData();int columnCount = rsMetaData.getColumnCount();Map<String, Object> mapOfColumnValues = createColumnMap(columnCount);for (int i = 1; i <= columnCount; i++) {String columnName = JdbcUtils.lookupColumnName(rsMetaData, i);mapOfColumnValues.putIfAbsent(getColumnKey(columnName), getColumnValue(rs, i));}return mapOfColumnValues;}protected Map<String, Object> createColumnMap(int columnCount) {return new LinkedHashMap<>(columnCount);}protected String getColumnKey(String columnName) {return columnName;}protected Object getColumnValue(ResultSet rs, int index) throws SQLException {return JdbcUtils.getResultSetValue(rs, index);}
}

3.3.6 数据库执行接口

JdbcOperations.java

package com.lino.springframework.jdbc.core;import java.util.List;
import java.util.Map;/*** @description: 数据库执行接口*/
public interface JdbcOperations {/*** 执行语句处理器** @param action 语句处理器* @param <T>    泛型* @return 泛型结果* @throws Exception 异常*/<T> T execute(StatementCallback<T> action) throws Exception;/*** 执行SQL语句** @param sql SQL语句*/void execute(String sql);/*** 执行查询** @param sql SQL语句* @param res 结果返回器* @param <T> 泛型* @return 泛型结果*/<T> T query(String sql, ResultSetExtractor<T> res);/*** 执行查询** @param sql       SQL语句* @param rowMapper 行对象* @param <T>       泛型* @return 泛型集合结果*/<T> List<T> query(String sql, RowMapper<T> rowMapper);/*** 查询列表** @param sql SQL语句* @return Map集合*/List<Map<String, Object>> queryForList(String sql);
}
  • Spring JDBC 框架中,JdbcOperations 的功能很简单,就是定义了一组用于 JDBC 操作的接口。

3.5 数据库操作模板

3.5.1 SQL提供者

SqlProvider.java

package com.lino.springframework.jdbc.core;/*** @description: SQL提供者*/
public interface SqlProvider {/*** 获取SQL语句** @return SQL语句*/String getSql();
}

3.5.2 JDBC操作抽象类

JdbcAccessor.java

package com.lino.springframework.jdbc.support;import cn.hutool.core.lang.Assert;
import com.lino.springframework.beans.factory.InitializingBean;
import javax.sql.DataSource;/*** @description: JDBC操作接口*/
public abstract class JdbcAccessor implements InitializingBean {private DataSource dataSource;public DataSource getDataSource() {return dataSource;}public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}protected DataSource obtainDataSource() {DataSource dataSource = getDataSource();Assert.state(dataSource != null, "No DataSource set");return dataSource;}@Overridepublic void afterPropertiesSet() {if (getDataSource() == null) {throw new IllegalArgumentException("Property 'dataSource' is required");}}
}

3.5.3 JDBC操作模板

JdbcTemplate.java

package com.lino.springframework.jdbc.core;import cn.hutool.core.lang.Assert;
import com.lino.springframework.jdbc.datasource.DataSourceUtils;
import com.lino.springframework.jdbc.support.JdbcAccessor;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;/*** @description: JDBC 操作模板*/
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {/*** 查询大小*/private int fetchSize = -1;/*** 最大行数*/private int maxRows = -1;/*** 查询时间*/private int queryTimeout = -1;public JdbcTemplate() {}public JdbcTemplate(DataSource dataSource) {setDataSource(dataSource);afterPropertiesSet();}public int getFetchSize() {return fetchSize;}public void setFetchSize(int fetchSize) {this.fetchSize = fetchSize;}public int getMaxRows() {return maxRows;}public void setMaxRows(int maxRows) {this.maxRows = maxRows;}public int getQueryTimeout() {return queryTimeout;}public void setQueryTimeout(int queryTimeout) {this.queryTimeout = queryTimeout;}@Overridepublic <T> T execute(StatementCallback<T> action) {Connection con = DataSourceUtils.getConnection(obtainDataSource());try {Statement stmt = con.createStatement();applyStatementSettings(stmt);return action.doInStatement(stmt);} catch (SQLException ex) {throw new RuntimeException("StatementCallback", ex);}}@Overridepublic void execute(String sql) {class ExecuteStatementCallback implements StatementCallback<Object>, SqlProvider {@Overridepublic String getSql() {return sql;}@Overridepublic Object doInStatement(Statement statement) throws SQLException {statement.execute(sql);return null;}}execute(new ExecuteStatementCallback());}@Overridepublic <T> T query(String sql, ResultSetExtractor<T> res) {class QueryStatementCallback implements StatementCallback<T>, SqlProvider {@Overridepublic String getSql() {return sql;}@Overridepublic T doInStatement(Statement statement) throws SQLException {ResultSet rs = statement.executeQuery(sql);return res.extractData(rs);}}return execute(new QueryStatementCallback());}@Overridepublic <T> List<T> query(String sql, RowMapper<T> rowMapper) {return result(query(sql, new RowMapperResultSetExtractor<>(rowMapper)));}@Overridepublic List<Map<String, Object>> queryForList(String sql) {return query(sql, new ColumnMapRowMapper());}private static <T> T result(T result) {Assert.state(null != result, "No result");return result;}protected void applyStatementSettings(Statement stat) throws SQLException {int fetchSize = getFetchSize();if (fetchSize != -1) {stat.setFetchSize(fetchSize);}int maxRows = getMaxRows();if (maxRows != -1) {stat.setMaxRows(maxRows);}}
}
  • JdbcTemplate 是对数据库操作的封装,在启动时由外部传入 DataSource 数据源,这也是处理数据库操作最基本的方法。
    • 通过这样的封装,减少了用户操作的复杂性,也符合设计模式的原则。
  • execute 方法是整个数据库操作的核心方法,将同类的数据操作进行统一封装。一些个性化的操作需要进行回调处理。
    • 例如:在 JdbcTemplate#query 方法中,也是对 JdbcTemplate#execute 进行包装操作,并返回处理结果。

四、测试:JDBC功能整合

4.1 添加测试配置

4.1.1 sql数据库表

user.sql

CREATE TABLE `user` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增ID',`userId` varchar(9) DEFAULT NULL COMMENT '用户ID',`userHead` varchar(16) DEFAULT NULL COMMENT '用户头像',`createTime` datetime DEFAULT NULL COMMENT '创建时间',`updateTime` datetime DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

4.1.2 Spring属性配置文件

spring.xml

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClass" value="com.mysql.cj.jdbc.Driver"/><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/spring?useSSL=false&amp;serverTimezone=Asia/Shanghai"/><property name="username" value="root"/><property name="password" value="123456"/></bean><bean id="jdbcTemplate" class="com.lino.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/></bean></beans>
  • spring.xml 配置文件中,先配置数据库的链接信息及库表,再将 dataSource 注入 JdbcTemplate 中,由 JdbcTemplate 完成数据库的操作。

4.1.3 初始化 Spring和JdbcTemplate对象

ApiTest.java

package com.lino.springframework.test;import com.lino.springframework.context.support.ClassPathXmlApplicationContext;
import com.lino.springframework.jdbc.core.JdbcTemplate;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
import java.util.Map;/*** @description: 测试类*/
public class ApiTest {private JdbcTemplate jdbcTemplate;@Beforepublic void init() {ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");jdbcTemplate = applicationContext.getBean(JdbcTemplate.class);}
}

4.2 单元测试

4.2.1 插入测试

ApiTest.java

@Test
public void execute() {jdbcTemplate.execute("insert into user (id, userId, userHead, createTime, updateTime) values (1, '123456789', '01-50', now(), now())");
}

测试结果

信息: {dataSource-1} inited

4.2.2 查询测试

ApiTest.java

@Test
public void queryForList() {List<Map<String, Object>> allResult = jdbcTemplate.queryForList("select * from user");for (Map<String, Object> objectMap : allResult) {System.out.println("测试结果:" + objectMap);}
}

测试结果

信息: {dataSource-1} inited
测试结果:{id=1, userId=123456789, userHead=01-50, createTime=2022-12-08 14:39:15.0, updateTime=2022-12-08 14:39:15.0}
  • 从测试结果看,这里已经把操作数据库的 JdbcTemplate 交由 Spring Bean 容器管理,并验证其数据库操作。

五、总结:JDBC功能整合

  • 本节主要介绍了 Spring Bean 容器的扩展功能,可以在指定的任何阶段把需要交给 Spring 管理的对象进行初始化。
    • 如:InitializingBean 可以在 BeanFactory 设置属性后进行相应的处理,整合其他对象。
  • 另外,需要熟悉 JDBC 的包装,使用支撑层 support 承接 Bean 对象的扩展。
    • DataSource 提供了操作数据源的功能,在 core 包中完成对数据库的操作并返回相应的结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/101410.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

你参与的APP开发项目安全吗?

Android将安全设计贯穿系统架构的各个层面&#xff0c;覆盖系统内核、虚拟机、应用程序框架层以及应用层各个环节&#xff0c;力求在开放的同时&#xff0c;也恰当保护用户的数据、应用程序和设备的安全。Android安全模型主要提供以下几种安全机制&#xff1a; 进程沙箱隔离机…

slog正式版来了:Go日志记录新选择!

在大约一年前&#xff0c;我就写下了《slog&#xff1a;Go官方版结构化日志包[1]》一文&#xff0c;文中介绍了Go团队正在设计并计划在下一个Go版本中落地的Go官方结构化日志包&#xff1a;slog[2]。但slog并未如预期在Go 1.20版本[3]中落地&#xff0c;而是在golang.org/x/exp…

复制粘贴是怎么实现的

在上面的代码中&#xff0c;command 和 select 是自定义的函数。它们的作用如下&#xff1a; 实现复制粘贴的思路&#xff1a; 创建一个 textarea 标签将 textarea 移出可视区域给这个 textarea 赋值将这个 textarea 标签添加到页面中调用 textarea 的 select 方法调用 docum…

曾国藩农民出身,弯道超车实现逆袭的大智慧

曾国藩从小就笨笨的&#xff0c;读书多了才开窍&#xff0c;实现人生逆袭。农民出身&#xff0c;弯道超车&#xff0c;贵在坚持。 约翰生说过&#xff1a;“成大事不在于力量的大小&#xff0c;而在于能坚持多久。” 很多家长认为“不让孩子输在起跑线上”&#xff0c;这是错…

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书杭州师范大学图书馆

2023开学礼《乡村振兴战略下传统村落文化旅游设计》许少辉八一新书杭州师范大学图书馆

壁炉在文学和艺术中的代表着什么呢,能给我们带来什么样的影响?

壁炉&#xff0c;不仅仅是家庭温暖的来源&#xff0c;也是文学和艺术中常见的重要元素。它的形象在文学作品、绘画和电影中频繁出现&#xff0c;不仅为故事情节提供了背景&#xff0c;还象征着情感、温馨和安全感。让我们一起深入探讨壁炉在文学和艺术中的形象&#xff0c;以及…

U-net网络学习记录

U-net网络 本质上是一个用于图像分割的神经网络 输入是一幅图&#xff0c;输出是目标的分割结果。继续简化就是&#xff0c;一幅图&#xff0c;编码&#xff0c;或者说降采样&#xff0c;然后解码&#xff0c;也就是升采样&#xff0c;然后输出一个分割结果。根据结果和真实分…

EG1164大功率同步整流升压模块开源,最高效率97%

EG1164大功率同步整流Boost升压电源模块&#xff0c;最高效率97%&#xff0c;输入电压8~50V&#xff0c;输出电压8~60V可调&#xff0c;最大功率300瓦以上&#xff0c;开关频率219kHz。 白嫖了张嘉立创的彩色丝印券就随便画了个板试试&#xff0c;第一次打彩色丝印。 因为我测…

【C++基础】类与对象(上):访问限定符、类作用域、类实例化、类对象模型、this指针

​&#x1f47b;内容专栏&#xff1a; C/C编程 &#x1f428;本文概括&#xff1a; C基础语法。访问限定符、类作用域、类实例化、类对象模型、this指针等。 &#x1f43c;本文作者&#xff1a; 阿四啊 &#x1f438;发布时间&#xff1a;2023.9.6 面向过程和面向对象初识 C语…

LeetCode 3. 无重复字符的最长子串

题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目解析 我们需要找的是含重复元素的最长子串&#xff0c;当然直接暴力求解固然简单。但是可能引发的情况是超时&#xff0c;而且面试官想看到的也不是让你去暴力解决这类问题。因此我们使…

jsp 新能源汽车论坛网Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 新能源汽车论坛网是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

企业电脑文件加密系统 / 防泄密软件——「天锐绿盾」

「天锐绿盾」是一种公司文件加密系统&#xff0c;旨在保护公司内网数据安全&#xff0c;防止信息泄露。该系统由硬件和软件组成&#xff0c;其中包括服务端程序、控制台程序和终端程序。 PC访问地址&#xff1a; isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c…