最近的一个项目需要使用多数据源,而且不整合Mybatis使用。以下为详细配置。

环境:SpringBoot:2.2.6.RELEASE

入口程序

禁用自动配置数据源:

@SpringBootApplication(exclude = {
        DataSourceAutoConfiguration.class
})
因为它会读取application.properties文件的spring.datasource.*属性并自动配置单数据源

配置文件

spring.datasource下自定义数据源,名称可自定义。共用的连接参数配置可提取成公共配置。

spring:
  datasource:
    dw:
      jdbc-url: jdbc:mysql://xxxxxx:3306/xxx?${db.conn.str}
      driver-class-name: com.mysql.cj.jdbc.Driver
      type: com.zaxxer.hikari.HikariDataSource
      username: xxx
      password: xxx
    ods:
      jdbc-url: jdbc:mysql://xxxxxx:3306/xxx?${db.conn.str}
      driver-class-name: com.mysql.cj.jdbc.Driver
      type: com.zaxxer.hikari.HikariDataSource
      username: xxx
      password: xxx
      
---
db:
  conn:
    str: characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&allowPublicKeyRetrieval=true
---

配置多数据源为何使用jdbc-url而不是url

在 Spring Boot 2.x 中配置多数据源和 Spring Boot 1.5.x 之前,一些配置及用法会有些不同,如果使用url会出现jdbcUrl is required with driverClassName异常。

官方文档解释:因为连接池的实际类型没有被公开,所以在您的自定义数据源的元数据中没有生成密钥,而且在IDE中没有完成(因为DataSource接口没有暴露属性)。另外,如果您碰巧在类路径上有Hikari,那么这个基本设置就不起作用了,因为Hikari没有url属性(但是确实有一个jdbcUrl属性)。在这种情况下,您必须重写您的配置。

配置类

/**
 * <p>
 * 多数据源配置
 * </p>
 *
 * @author zs
 * @since 2020/4/1
 */
@Configuration
public class DataSourceConfig {

    @Bean(name = "dw")
    @ConfigurationProperties(prefix = "spring.datasource.dw")
    public DataSource dwDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "ods")
    @ConfigurationProperties(prefix = "spring.datasource.ods")
    public DataSource odsDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dwJdbcTemplate")
    public JdbcTemplate dwJdbcTemplate(
            @Qualifier("dw") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "odsJdbcTemplate")
    public JdbcTemplate odsJdbcTemplate(
            @Qualifier("ods") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean(name = "dwNamedParameterJdbcTemplate")
    public NamedParameterJdbcTemplate dwNamedParameterJdbcTemplate(
            @Qualifier("dwJdbcTemplate") JdbcTemplate jdbcTemplate) {
        return new NamedParameterJdbcTemplate(jdbcTemplate);
    }

    @Bean(name = "odsNamedParameterJdbcTemplate")
    public NamedParameterJdbcTemplate odsNamedParameterJdbcTemplate(
            @Qualifier("odsJdbcTemplate") JdbcTemplate jdbcTemplate) {
        return new NamedParameterJdbcTemplate(jdbcTemplate);
    }
}

在经典的 JDBC 用法中, SQL 参数是用占位符?表示,并且受到位置的限制.。定位参数的问题在于,一旦参数的顺序发生变化,就必须改变参数绑定。在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择是使用具名参数(named parameter)。

具名参数: SQL 按名称(以冒号开头)而不是按位置进行指定。具名参数更易于维护, 也提升了可读性。具名参数由框架类在运行时用占位符取代。具名参数只在 NamedParameterJdbcTemplate 中得到支持。

例如:

// 新增例子
String sql = "insert into user (username,password) values (:username,:password)";
User u = new User();
u.setUsername("555");
SqlParameterSource sqlParameterSource = new BeanPropertySqlParameterSource(u);
namedParameterJdbcTemplate.update(sql, sqlParameterSource);
// ids查询例子 
List<String> Ids = ...
String sql = "select * from user where id in (:ids)";
Map<String, Object> param = new HashMap<>(1);
param.put("ids", Ids);
namedParameterJdbcTemplate.queryForList(sql, param);
// 获取新增的主键
KeyHolder keyHolder = new GeneratedKeyHolder();
namedParameterJdbcTemplate.update(sql, sqlParameterSource, keyHolder);
int k = keyHolder.getKey().intValue();

依赖注入使用

@Lazy
@Autowired
@Qualifier("dwJdbcTemplate")
private JdbcTemplate dwJdbcTemplate;

@Lazy
@Autowired
@Qualifier("odsJdbcTemplate")
private JdbcTemplate odsJdbcTemplate;

@Lazy
@Autowired
@Qualifier("dwNamedParameterJdbcTemplate")
private NamedParameterJdbcTemplate dwNamedParameterJdbcTemplate;

@Lazy
@Autowired
@Qualifier("odsNamedParameterJdbcTemplate")
private NamedParameterJdbcTemplate odsNamedParameterJdbcTemplate;

多数据源下的事务管理器配置

/**
 * <p>
 * 事务控制器
 * </p>
 *
 * @author zs
 * @since 2020/4/1
 */
@Configuration
@EnableTransactionManagement
public class TransactionManagerConfig {

    @Bean(name = "dwTxManager")
    public PlatformTransactionManager DWTxManager(@Qualifier("dw") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean(name = "odsTxManager")
    public PlatformTransactionManager ODSTxManager(@Qualifier("ods") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

使用时指定事务管理器即可:@Transactional(value = "odsTxManager", rollbackFor = Exception.class)

注意:@Transactional存在几种生效必要条件,否则不会生效。


参考