使用jdbcTemplate查询数据库

springboot2版本项目中已经整合了mybatis框架,yml文件中配置好了数据源, 现在想再使用jdbcTemplate查询另外一个数据库,需要怎么配置

image

 

# 这是你现有的MyBatis数据源配置(假设使用默认前缀)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/main_db
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver

  # 新增的第二个数据源配置
  datasource:
    secondary:
      jdbc-url: jdbc:mysql://localhost:3306/another_db # 注意这里使用jdbc-url而非url:cite[5]:cite[10]
      username: root
      password: password
      driver-class-name: com.mysql.cj.jdbc.Driver
      # 可以根据需要配置连接池参数,例如HikariCP:
      hikari:
        maximum-pool-size: 10
        minimum-idle: 2

注意:第二个数据源的URL配置,建议使用 jdbc-url 而不是 url。这是因为Spring Boot在自动配置多个数据源时可能会产生冲突,明确指定 jdbc-url 可以避免 "jdbcUrl is required with driverClassName" 的错误

编写Java配置类

新建一个Java配置类(例如 JdbcTemplateConfig),用于创建第二个数据源的 DataSource Bean 和 JdbcTemplate Bean。

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
public class JdbcTemplateConfig {

    /**
     * 配置第二个数据源
     * 使用@ConfigurationProperties注解绑定配置文件中"spring.datasource.secondary"开头的属性
     */
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    /**
     * 创建第二个JdbcTemplate,并注入名为"secondaryDataSource"的数据源。
     * 使用@Qualifier注解明确指定要注入的Bean名称。
     */
    @Bean(name = "secondaryJdbcTemplate")
    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

关键点说明:

  • @Bean(name = "secondaryDataSource"): 为Bean定义一个名称,便于后续注入时区分。

  • @ConfigurationProperties(prefix = "spring.datasource.secondary"): 告诉Spring将配置文件中以 spring.datasource.secondary 为前缀的属性映射到这个 DataSource 的所有属性上。

  • @Qualifier("secondaryDataSource"): 当注入 DataSource 时,通过名称明确指定要注入的是我们刚刚定义的第二个数据源Bean,而不是MyBatis使用的那个默认数据源

 

在Service中使用第二个JdbcTemplate

在你的Service类中,使用 @Autowired 和 @Qualifier 注解注入指定的 JdbcTemplate Bean。

 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service
public class YourService {

    // 注入第二个JdbcTemplate
    @Autowired
    @Qualifier("secondaryJdbcTemplate") // 指定注入名为"secondaryJdbcTemplate"的Bean
    private JdbcTemplate secondaryJdbcTemplate;

    public List<Map<String, Object>> queryFromOtherDatabase() {
        String sql = "SELECT * FROM some_table";
        // 使用secondaryJdbcTemplate执行查询,操作的就是另一个数据库
        return secondaryJdbcTemplate.queryForList(sql);
    }
}

重要的注意事项

  1. 事务管理:需要特别注意事务问题。如果你在使用了 @Transactional 注解的方法中操作多个数据源,默认的事务管理器可能只管理其中一个数据源的事务。你需要为每个数据源配置独立的 PlatformTransactionManager Bean,并在 @Transactional 注解中通过 transactionManager 属性指定使用哪个事务管理器。例如:

    @Bean(name = "secondaryTransactionManager")
    public PlatformTransactionManager secondaryTransactionManager(@Qualifier("secondaryDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
    }

然后在使用时:

@Transactional(transactionManager = "secondaryTransactionManager") // 指定事务管理器
public void updateInSecondaryDatabase() {
// ... 使用secondaryJdbcTemplate执行更新操作
}

 

对于需要跨数据源的真正分布式事务,需要考虑使用JTA解决方案,但这会复杂得多

 
<!-- MyBatis Spring Boot Starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

 

 如果遇到数据源错乱问题,参考👇🏻

🧩 原因分析与解决方案

1. 数据源(DataSource)Bean的注入问题

Spring Boot的自动配置在遇到多个DataSource Bean时,如果未明确指定,可能会注入错误的Bean。

  • 原因:你可能配置了多个DataSource Bean(例如一个给MyBatis,一个给JdbcTemplate),但没有明确地通过@Primary注解指定哪个是默认数据源,或者没有在注入时通过@Qualifier注解按名称(Bean Name)进行区分。这会导致Spring自动注入时发生混乱。

  • 解决方案:确保每个DataSource Bean都有唯一的名称,并且为MyBatis使用的数据源设置@Primary注解(如果你的MyBatis期望使用主数据源)。同时,在注入时使用@Qualifier明确指定。

@Configuration
public class DataSourceConfig {

    // 为MyBatis配置主数据源(primary)
    @Bean(name = "mybatisDataSource")
    @Primary // 关键:标记为默认数据源,MyBatis通常会使用默认的DataSource
    @ConfigurationProperties(prefix = "spring.datasource.mybatis")
    public DataSource mybatisDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 为JdbcTemplate配置另一个数据源
    @Bean(name = "jdbcTemplateDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.jdbctemplate")
    public DataSource jdbcTemplateDataSource() {
        return DataSourceBuilder.create().build();
    }
}

然后在配置JdbcTemplate时,明确指定使用哪个数据源:

@Bean
public JdbcTemplate jdbcTemplate(@Qualifier("jdbcTemplateDataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
}

MyBatis(尤其是通过mybatis-spring-boot-starter自动配置时)通常会自动使用标记了@PrimaryDataSource

2. MyBatis配置未正确关联指定数据源

如果你为MyBatis自定义了配置,需要确保其使用的SqlSessionFactoryBean关联到了正确的DataSource Bean。

  • 原因:自定义的SqlSessionFactoryBean可能没有注入你希望它使用的DataSource

  • 解决方案:在创建SqlSessionFactoryBean时,通过@Qualifier注入为MyBatis准备的特定数据源。

@Configuration
@MapperScan(basePackages = "com.example.mapper", sqlSessionFactoryRef = "mybatisSqlSessionFactory")
public class MyBatisConfig {

    @Bean(name = "mybatisSqlSessionFactory")
    public SqlSessionFactoryBean sqlSessionFactory(@Qualifier("mybatisDataSource") DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource); // 关联MyBatis专用的数据源
        // 其他MyBatis配置(如mapper.xml位置等)
        return sessionFactory;
    }
}

3. 事务管理器(TransactionManager)冲突

Spring的事务管理也需要知道操作哪个数据源。

  • 原因:如果只配置了一个全局的PlatformTransactionManager,它可能绑定到了错误的数据源上。

  • 解决方案:为不同的数据源配置各自的事务管理器,并在使用@Transactional注解时根据需要指定事务管理器(但通常查询操作不涉及事务,此问题影响较小)。

@Bean(name = "mybatisTransactionManager")
@Primary
public PlatformTransactionManager mybatisTransactionManager(@Qualifier("mybatisDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

@Bean(name = "jdbcTemplateTransactionManager")
public PlatformTransactionManager jdbcTemplateTransactionManager(@Qualifier("jdbcTemplateDataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

4. 配置文件(application.yml)问题

确保你的配置文件中的多数据源配置前缀正确,并且没有相互覆盖。

spring:
  datasource:
    # MyBatis 使用的数据源配置
    mybatis:
      jdbc-url: jdbc:mysql://localhost:3306/db_mybatis
      username: user_mybatis
      password: pass_mybatis
      driver-class-name: com.mysql.cj.jdbc.Driver
    # JdbcTemplate 使用的数据源配置
    jdbctemplate:
      jdbc-url: jdbc:mysql://localhost:3306/db_jtemplate # 注意此处使用 jdbc-url 而非 url:cite[1]
      username: user_jtemplate
      password: pass_jtemplate
      driver-class-name: com.mysql.cj.jdbc.Driver

核心检查点

  1. Bean名称与限定:检查是否为每个DataSourceJdbcTemplateSqlSessionFactoryBean等定义了清晰的Bean名称,并在注入时使用@Qualifier

  2. @Primary注解:通常将MyBatis使用的数据源设为@Primary,因为许多Spring Boot自动配置默认期望存在一个主数据源。

  3. 配置隔离:在application.yml中使用不同的前缀(如spring.datasource.mybatisspring.datasource.jdbctemplate)清晰隔离两个数据源的配置。

  4. URL属性:在多数据源配置中,使用jdbc-url而非url来避免潜在的配置解析问题

 

posted @ 2025-09-21 21:53  iTao0128  阅读(23)  评论(0)    收藏  举报