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

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。

一、核心设计理念

1、痛点在哪

  • 应用离不开数据(数据库、NoSQL、文件等)。但直接写 JDBC/Nosql Client 代码太原始了(码友要优雅):

    • 样板代码多: 开连接、关连接、异常处理… 写吐了,还容易漏。
    • 资源管理难: 连接池怎么管理?线程安全怎么保证?全靠开发者手动,容易出错。
    • SQL/命令与Java代码耦合: SQL 硬编码在 Java 里,改个 SQL 得重新编译,不方便维护和优化。
    • 结果集映射繁琐: 把数据库查出来的一行行数据 (ResultSet/Document/Row) 手动转成 Java 对象 (User, Order),又累又容易出错。
    • 事务管理复杂: 手动控制事务的开始、提交、回滚,尤其是在跨多个操作时,代码会变得非常混乱且容易出错。
    • 缺乏抽象: 不同数据库(MySQL, PostgreSQL)或数据源(DB, Redis)的访问方式有差异,业务代码最好不关心底层细节。
  • 已有模块的支撑: 你已经有了强大的 IoC 容器!它能管理对象生命周期和依赖关系。数据访问对象 (DAO/Repository`) 本身就是对象,非常适合由 IoC 容器托管。Web 模块处理请求,最终往往需要访问数据,两者需要无缝集成

2、解决方案(设计目标)

  • 消灭样板代码: 连接管理、资源释放、异常转换这些通用的、繁琐的事情,模块帮你搞定。

  • 职责分离:

    • 业务逻辑 (Service) 关注做什么 (比如:下单)。
    • 数据访问逻辑 (DAO/Repository) 关注怎么做 (比如:保存订单数据到 DB)。
    • SQL/命令 最好与 Java 代码分离(虽然不一定强制 XML,但提供灵活配置)。
  • 面向接口编程: 业务代码 (Service) 只依赖 UserRepository 接口,不关心具体实现是 JDBC、MyBatis 还是 JPA。模块负责在运行时提供具体实现(动态代理是秘密武器!)。

  • 模板方法模式: 定义一个操作(执行 SQL/命令)的骨架,将某些步骤(如获取连接、设置参数、处理结果)延迟到子类或回调中。核心执行流程固化,可变部分开放扩展。

  • 异常体系统一化: 把五花八门的底层数据访问异常(SQLException, RedisException)转换成模块定义的一套清晰的、非检查型(RuntimeException)异常。业务层无需处理大量底层异常细节。

  • 无缝集成 IoC: 数据访问对象 (DAO/Repository) 本身就是 Bean,由 IoC 容器创建、注入依赖、管理生命周期。

  • 非侵入性: 尽量减少对业务代码的污染。通过注解、接口、少量配置来定义数据访问行为。

二、核心组件与职责划分

组件核心职责数据流中的角色
DataSource连接的工厂 (含连接池)。 提供物理数据库连接。起点Executor 执行操作时向其索取 Connection
PlatformTransactionManager抽象事务管理 (开始、提交、回滚、状态)。 实现事务ACID。事务协调者。为 @Transactional 方法管理连接 (绑定到线程) 和事务边界。协调 Executor 使用正确连接。
Repository (接口)定义数据操作契约 (如 findById,** save)。** 业务层入口。触发点。业务层 (Service) 调用其方法 → 触发动态代理 → 委托给 Executor
Mapper / @SQL承载 SQL/命令 和 映射规则。 定义要执行的语句及参数/结果如何与Java交互。执行蓝图Executor 根据调用的 Repository 方法找到对应的 Mapper,作为执行的“指令手册”。
Executor (核心)执行引擎!应用模板方法模式。核心枢纽 & 苦力: 1. 拿连接 (DataSource / 事务绑定) 2. 根据 Mapper 创建语句 3. 绑定参数 (调用 TypeHandler) 4. 执行 (查询/更新) 5. 处理结果 (映射,调用 TypeHandler/RowMapper) 6. 清理资源 (关语句/结果集,还连接) 7. 返回结果/行数。 处理所有异常转换!
TypeHandlerJava类型 <-> 数据库类型 转换器。 (如 Date<->TIMESTAMP, Enum<->String)转换小助手。在 Executor 绑定参数映射结果时被调用。
SqlSession / Template提供编程式API,管理一次“数据访问会话”。内部使用 Executor替代或辅助 Repository 接口,提供更集中控制。

三、关键设计模式应用

1、模板方法模式:JdbcTemplate 执行流程

核心思想:固定数据库操作流程(获取连接→执行 SQL→处理结果→释放资源),可变部分(SQL 执行、结果映射)通过回调接口扩展。
Spring 源码参考org.springframework.jdbc.core.JdbcTemplate

public class SimpleJdbcTemplate {private DataSource dataSource;// 模板方法:定义执行骨架public <T> T execute(ConnectionCallback<T> action) {Connection conn = DataSourceUtils.getConnection(dataSource);try {return action.doInConnection(conn); // 回调可变逻辑} catch (SQLException ex) {throw translateException("Connection callback failed", ex);} finally {DataSourceUtils.releaseConnection(conn, dataSource);}}// 查询模板public <T> T query(String sql, ResultSetExtractor<T> rse) {return execute(conn -> {try (PreparedStatement ps = conn.prepareStatement(sql)) {try (ResultSet rs = ps.executeQuery()) {return rse.extractData(rs); // 结果集映射回调}}});}
}// 回调接口(策略模式结合点)
@FunctionalInterface
public interface ResultSetExtractor<T> {T extractData(ResultSet rs) throws SQLException;
}

2、策略模式:事务管理

核心思想PlatformTransactionManager 抽象事务操作(begin/commit/rollback),不同数据源通过具体策略实现(如 DataSourceTransactionManager)。
Spring 源码参考org.springframework.transaction.PlatformTransactionManager

// 事务管理器接口(策略抽象)
public interface PlatformTransactionManager {TransactionStatus getTransaction(TransactionDefinition definition);void commit(TransactionStatus status);void rollback(TransactionStatus status);
}// JDBC 事务策略实现
public class DataSourceTransactionManager implements PlatformTransactionManager {private DataSource dataSource;@Overridepublic TransactionStatus getTransaction(TransactionDefinition definition) {Connection conn = DataSourceUtils.getConnection(dataSource);conn.setAutoCommit(false); // 开启事务return new DefaultTransactionStatus(conn, true);}@Overridepublic void commit(TransactionStatus status) {Connection conn = status.getConnection();conn.commit(); // 提交策略}
}

3、动态代理:声明式事务(AOP 代理)

AOP我们还没有设计,此处就把AOP当成一个“黑盒”就好,

Spring AOP 是用于通过运行时动态代理技术实现模块化横切关注点(如日志、事务管理)的核心模块,它通过在方法执行前后插入增强逻辑(Advice)来实现功能。

核心思想:通过代理对象在方法调用前后注入事务逻辑(begin/commit)。Spring 优先用 JDK 动态代理(基于接口),缺接口时用 CGLIB。
Spring 源码参考org.springframework.aop.framework.DefaultAopProxyFactory

// 事务代理创建工厂
public class TransactionProxyFactory {public Object createProxy(Object target, PlatformTransactionManager txManager) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),(proxy, method, args) -> {TransactionStatus status = txManager.getTransaction(null);try {Object result = method.invoke(target, args); // 执行业务方法txManager.commit(status); // 提交事务return result;} catch (Exception ex) {txManager.rollback(status); // 回滚策略throw ex;}});}
}// 使用示例
UserService proxy = (UserService) new TransactionProxyFactory().createProxy(userService, transactionManager);
proxy.saveUser(); // 代理方法调用

4、工厂模式:Repository 实例创建

核心思想:通过 BeanFactory 动态创建 Repository 代理对象,解耦业务层与数据访问层。
Spring 源码参考org.springframework.beans.factory.FactoryBean

public class RepositoryFactoryBean<T> implements FactoryBean<T> {private Class<T> repositoryInterface;@Overridepublic T getObject() {// 动态生成 Repository 代理(结合模板方法+策略)return (T) Proxy.newProxyInstance(repositoryInterface.getClassLoader(),new Class[]{repositoryInterface},(proxy, method, args) -> {JdbcTemplate template = new JdbcTemplate(dataSource);String sql = parseSqlFromAnnotation(method); // 解析 @Select 等注解return template.query(sql, new BeanPropertyRowMapper<>(method.getReturnType()));});}
}// 配置声明
@Bean
public RepositoryFactoryBean<UserRepository> userRepository() {return new RepositoryFactoryBean<>(UserRepository.class);
}

5、结果集映射:RowMapper 策略

Spring 源码实现BeanPropertyRowMapper 通过反射将 ResultSet 列名映射到 JavaBean 属性

public class UserRowMapper implements RowMapper<User> {@Overridepublic User mapRow(ResultSet rs, int rowNum) throws SQLException {User user = new User();user.setId(rs.getLong("id")); // 列名→属性user.setName(rs.getString("name"));return user;}
}// 在模板方法中使用
List<User> users = jdbcTemplate.query("SELECT * FROM users", new UserRowMapper());

四、高级特性及扩展机制设计

1. 声明式事务管理

  • 实现: 依赖 IoC 的 AOP 能力(即使你还没做 AOP 模块,事务管理器也可以看作一种特殊代理)。在 RepositoryService 方法上添加 @Transactional 注解。

  • 流程:

    • 代理拦截被 @Transactional 标记的方法调用。
    • 获取 PlatformTransactionManager
    • 开启事务(获取连接,设置 autoCommit=false,绑定连接到当前线程)。
    • 执行业务方法(其中包含的数据库操作会使用当前线程绑定的连接)。
    • 业务方法成功执行完 -> 提交事务。
    • 业务方法抛出异常 -> 回滚事务。
    • 最终清理线程绑定资源。
  • 好处: 事务控制与业务代码完全分离,配置化。

2. 多数据源支持

  • 实现: 在 IoC 容器中配置多个 DataSource Bean (如 primaryDataSource, secondaryDataSource)。需要实现:

    • AbstractRoutingDataSource:** 一个动态 DataSource 实现,根据某种“键”(Lookup Key)路由到真正的目标 DataSource
    • 确定“键”的策略: 通常基于注解(@DataSource("slave"))或线程上下文变量。Repository 方法执行前设置“键”,AbstractRoutingDataSource 据此选择 DataSource
  • 挑战: 需要与事务管理器配合,确保同一事务内的操作使用同一个数据源。

3. 注解支持

  • @Repository:** 标记一个接口是数据访问仓库,由 IoC 管理并需要生成代理。
  • @Select / @Insert / @Update / @Delete:** 直接在 Repository 接口方法上声明 SQL。
  • @Param:** 为方法参数命名,用于在 SQL 中引用 (#{userId})。
  • @Transactional:** 声明事务属性 (传播行为、隔离级别、超时、只读等)。

4. 结果映射扩展

  • 自定义 RowMapper / ResultHandler:** 允许用户编写代码精细控制如何将一行数据映射到一个对象。
  • 嵌套结果映射: 处理复杂的“一对一”、“一对多”关联关系(需要递归映射)。
  • 自动驼峰命名映射: user_name 列自动映射到 userName 属性。

5. 插件机制 (Interceptor)

  • 实现:Executor 执行流程的关键点(执行前、执行后、处理参数、处理结果)插入拦截逻辑。类似责任链模式。
  • 用途: SQL 日志记录、性能监控、分页逻辑自动添加、权限过滤、数据加解密等。极大增强灵活性。

6. 简单缓存集成

  • 实现:Repository 代理层或 Executor 层,对方法调用结果进行缓存(例如基于方法名和参数生成缓存 Key)。下次相同查询直接返回缓存结果。
  • 注意: 需要处理缓存一致性(更新操作需清除相关缓存)。

五、核心流程解析

以下是 Spring Framework 数据访问模块的核心数据流程图及详细说明:

在这里插入图片描述

六、设计总结

1. 效率飙升 (开发体验)

  • 消灭样板: 连接、语句、资源释放、基础异常处理全自动化。
  • 专注核心: 开发者只需写 SQL/命令 和定义 对象映射 (Mapper / 注解)。
  • 接口清爽: Repository 接口明确职责,业务代码 (Service) 依赖清晰。

2. 健壮可靠 (运行质量)

  • 资源无忧: 严格的连接池管理、资源释放,杜绝泄漏。
  • 异常清晰: 统一转换底层异常为可读的 RuntimeException,业务层少踩坑。
  • 事务优雅: @Transactional 声明式事务,复杂提交回滚一行注解搞定,与业务解耦。

3. 灵活扩展 (设计优势)

  • 接口抽象: Repository 接口隔离技术细节,轻松切换实现 (JDBC, JPA等)。
  • 插件友好: 拦截器 (Interceptor) 机制方便扩展 (SQL日志、分页、监控)。
  • IoC 融合: 作为一等公民 Bean,依赖注入无缝衔接,生命周期受控。

一句话精髓: “通过动态代理声明意图 (Repository),模板方法固化流程 (Executor),让开发者只关注数据本身 (Mapper),框架搞定一切繁琐。”

相关文章:

  • Linux入门(十五)安装java安装tomcat安装dotnet安装mysql
  • 软件功能测试有哪些类型?软件测评机构
  • 从数据报表到决策大脑:AI重构电商决策链条
  • Python爬虫实战:从零构建高性能分布式爬虫系统
  • 医疗器械的三大记录文件:DHF、DMR和DHR
  • 激光隐形切割(Stealth Dicing)技术
  • linux磁盘无法清理问题
  • 时间复杂度和算法选择
  • 2025年八大员(标准员)考试题库及答案
  • 在 Word中生成目录(Table of Contents, TOC)
  • 华为云CAE部署spring cloud服务
  • ESP32-S3 IDF V5.4.1 LVGL 9.2.0 fatfs
  • Jinja2核心应用场景及示例
  • NumPy 与 OpenCV 版本兼容性深度解析:底层机制与解决方案
  • Linux基础开发工具——vim工具
  • 前端Vue框架页面自适应问题:挑战与系统化解决方案
  • 【工具】Configurable-HTTP-Proxy 使用指南
  • Linux与量子计算:面向未来的架构演进
  • 五.建造者模式
  • 【python异步多线程】异步多线程爬虫代码示例
  • 帝国cms如何做电影网站/安卓优化大师下载安装到手机
  • 网站开发的推荐/怎么样引流加微信
  • 怎样做淘宝联盟网站/深圳关键词优化怎么样
  • java做网站电话注册/网络推广宣传方式
  • 邢台做网站流程/如何设计推广方案
  • 美国做按摩广告的网站/百度关键词搜索排名多少钱