如何使用spring-jdbc template和spring-transaction实现两模块共享DAO类
最优解决方案
不要在共享module2中定义数据源、事务管理器这类和业务运行环境强绑定的配置,最优方案是共享module2只提供DAO、实体类的公共实现,由两个业务模块(module1、module3)各自编写自己的数据源、JDBC模板、事务相关配置。
方案核心原因
- 公共模块职责单一原则:module2作为公共依赖,核心作用是提供可复用的数据库访问能力,不应该绑定上层业务的数据源地址、事务策略等环境配置,否则会大幅提高耦合度,后续新增业务模块需要适配不同数据库时完全无法扩展。
- 避免配置冲突:如果在module2中硬编码两个数据源配置,上层模块引入依赖时会默认加载所有配置,很容易和业务模块自己的配置产生冲突,也会引入不必要的冗余Bean。
- 灵活适配不同业务需求:两个业务模块的事务需求完全不同,各自配置可以独立控制开关,不需要事务能力的module3不用引入额外的事务相关组件,减少不必要的性能开销。
具体实现步骤
第一步:改造module2的DAO实现,完全解耦配置
module2中的DAO不要硬编码JdbcTemplate实例,通过构造方法注入JdbcTemplate即可,不需要加任何Spring相关的配置类:
// module2中的DAO示例 public class OrderDao { private final JdbcTemplate jdbcTemplate; // 构造方法注入JdbcTemplate,完全不关心JdbcTemplate的来源和配置策略 public OrderDao(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // 下方编写你的增删改查方法即可 public Order getById(Long id) { return jdbcTemplate.queryForObject("select * from order where id = ?", (rs, rowNum) -> new Order(rs.getLong("id"), rs.getString("order_no")), id); } }
第二步:编写module3的配置(无事务、自动提交)
module3所有操作都是自动提交,不需要配置事务管理器,只需要配置数据源和JdbcTemplate,注入到共享DAO中即可,Spring JdbcTemplate默认就是自动提交模式,完全符合需求:
@Configuration @ComponentScan(basePackages = "com.yourdomain.module3.service") public class Module3Config { // 配置当前模块的数据源 @Bean public DataSource module3DataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://你的数据库地址/库名"); dataSource.setUsername("账号"); dataSource.setPassword("密码"); return dataSource; } // 配置JdbcTemplate @Bean public JdbcTemplate module3JdbcTemplate() { return new JdbcTemplate(module3DataSource()); } // 实例化共享DAO,传入当前模块的JdbcTemplate @Bean public OrderDao orderDao() { return new OrderDao(module3JdbcTemplate()); } }
第三步:编写module1的配置(支持事务)
module1需要事务支持,除了基础的数据源、JdbcTemplate配置外,额外添加事务管理器、开启事务注解支持即可,共享DAO完全不用修改:
@Configuration @ComponentScan(basePackages = "com.yourdomain.module1.service") @EnableTransactionManagement // 开启Spring声明式事务支持 public class Module1Config { // 配置当前模块的数据源,也可以和module3用同一个数据库,自行修改配置即可 @Bean public DataSource module1DataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://你的数据库地址/库名"); dataSource.setUsername("账号"); dataSource.setPassword("密码"); return dataSource; } // 配置JdbcTemplate @Bean public JdbcTemplate module1JdbcTemplate() { return new JdbcTemplate(module1DataSource()); } // 配置事务管理器 @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(module1DataSource()); } // 实例化共享DAO,传入当前模块的JdbcTemplate @Bean public OrderDao orderDao() { return new OrderDao(module1JdbcTemplate()); } }
需要事务的业务方法直接添加@Transactional注解即可,方法内所有调用共享DAO的操作都会自动纳入同一个事务:
@Service public class TransactionService { private final OrderDao orderDao; // 构造注入共享DAO public TransactionService(OrderDao orderDao) { this.orderDao = orderDao; } // 该方法内所有DAO操作在同一个事务中,异常会自动回滚 @Transactional(rollbackFor = Exception.class) public void batchOperate() { orderDao.insert(new Order(1, "xxx1")); orderDao.updateStatus(2, "已支付"); orderDao.deleteById(3); } }
额外优化建议
如果两个业务模块使用同一个数据库,数据源配置完全一致,可以把数据源配置抽成一个单独的公共配置模块,避免重复代码,事务相关配置仍然由各业务模块自己控制即可。
内容的提问来源于stack exchange,提问作者jimmayhem
相关产品推荐
相关产品推荐

