背景:
最近在学习当中,学到了多数据源的配置,在网上找了很多的资料一边配置,一边踩坑,也一边在学习,以此记录一下吧。
参考:
本文参考了几个文章,但是或多多少都有些问题,所以我自己整合了下。链接放出
https://blog.csdn.net/maoyeqiu/article/details/74011626
https://blog.csdn.net/mxw2552261/article/details/78640062
出现的问题:
https://my.oschina.net/chinesedragon/blog/1647846
前期准备:
springboot 2.0, mybatis,工具类:SqlSessionFactory 和 SqlSessionTemplate
多数据源:
首先将我的配置贴出来(声明一下,我这里用的yml格式)
spring:
###主数据源
primary:
datasource:
name: test1
jdbc-url: jdbc:mysql://localhost:3306/test1?characterEncoding=utf8&useSSL=true
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
###第二数据源
secondary:
datasource:
name: test2
jdbc-url: jdbc:mysql://localhost:3306/test2?characterEncoding=utf8&useSSL=true
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
我在这里配置了两个数据源,如果有多个,以此类推往下配置即可,我用的是mysql。
坑1
这里有一点说一下,如果配置单数据源应该是 spring.datasource.name,这里因为配置多个应该按照spring.yourname.datasource.name,差别是在datasource前边加了一个自定义的名字,这样来区分多个数据源,而且如果不加的话会在编译的时候报错 配置文件内duplicate datasource。
坑2
这里在配置数据库连接的时候一般单源或者springboot1.x版本都用的是 url:xxxxxxxx,而现在这种情况,多个源而且我的版本是2.0的所以应该写成jdbc-url: xxxxx,具体是因为版本还是多个数据源的原因只能去问大神了。
数据源配置好了以后,在springboot内启动时会自动加载数据源的配置,这时候会出错,所以我们在你的启动类application.java内的注解添加一个属性。
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableTransactionManagement
public class JisusearchApplication {
public static void main(String[] args) {
SpringApplication.run(JisusearchApplication.class, args);
}
}
就是在 启动注解这里SpringBootApplication 添加了exclude属性。这里是防止springboot自动创建datasource,而忽略我们的配置。
新建datasource:
我们禁掉了springboot默认创建的datasource,接下来我们就自己来创建我们需要的多个datasource。
1、新建一个类,来配置datasource
@Configuration
public class DataSourceConfig {
/**
* 主数据源
* @return
*/
@Bean(name = "primaryDataSource")
// @Qualifier("primaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.primary.datasource")
public DataSource primary() {
return DataSourceBuilder.create().build();
}
/**
* 从数据源
* @return
*/
@Bean(name = "secondaryDataSource")
// @Qualifier("secondaryDataSource")
@ConfigurationProperties(prefix = "spring.secondary.datasource")
public DataSource secondary() {
return DataSourceBuilder.create().build();
}
}
首先 @Configuration 指定该类为spring的配置类相当于xml,
然后配置你在你的properties或yml文件内配置的数据源信息
@ConfigurationProperties(prefix = "spring.secondary.datasource")
这个注解会去properties文件内找你指定的前缀为spring.secondary.datasource的配置,因此这个值要跟你配置文件内些的一致。
名字你当然可以自定义了,我这个可能会有些长。
注意:
这里需要注意的是 我注释掉的注解@Qulifier 就是为该类指定名字的,因为我用了注解bean所以不能重复指定,不然会报错,还有就是这里可以指定一个默认的数据源 @Primary(指定默认数据源),网上也有人说没有必要,但是我这里不指定会报错。
这个坑请知道的大神 指点一下。
2、接下来使用工具类SqlSessionFactory和 SqlSessionTemplate 来完善你的配置
我的是分开创建的,即你有几个数据源就创建几个配置类,当然你先创建的多,也可以将这一步与上一步整合到一个类当中,看个人需要了。
上代码:
@Configuration
@MapperScan(basePackages = {"com.example.jisusearch.primarydao"}, sqlSessionFactoryRef = "primarySqlSessionFactory")
public class MybatisPrimaryConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Bean
public SqlSessionFactory primarySqlSessionFactory () throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(primaryDataSource);
return bean.getObject();
}
@Bean
public SqlSessionTemplate primarySqlSessionTemplate() throws Exception {
SqlSessionTemplate template = new SqlSessionTemplate(primarySqlSessionFactory());
return template;
}
}
这里引入上一步配置的datasource,并通过注解@Qualifier 来指定你目前这个SqlSessionFactory使用的是哪个数据源,类上加上注解@Configuration 声明该类为配置类;
@MapperScan(basePackages = {"com.example.jisusearch.primarydao"}, sqlSessionFactoryRef = "primarySqlSessionFactory")
该注解来指定你哪个包要使用这个数据源,要写全路径,不然会报错,后边这个属性则是你SqlSessionFactory的bean的名字。
这里是一个数据源的配置,接下来配置另外一个,类似就直接上代码了。
@Configuration
@MapperScan(basePackages = {"com.example.jisusearch.secondarydao"}, sqlSessionFactoryRef = "secondarySqlSessionFactory")
public class MybatisSecondaryConfig {
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;
@Bean
public SqlSessionFactory secondarySqlSessionFactory() throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(secondaryDataSource);
return bean.getObject();
}
@Bean
public SqlSessionTemplate secondarySqlSessionTemplate() throws Exception {
SqlSessionTemplate template = new SqlSessionTemplate(secondarySqlSessionFactory());
return template;
}
}
因为我想要分开所以我建了两个dao,你也可以在一个dao内指定这两个,但是@MapperScan(basePackages = {"com.example.jisusearch.secondarydao"}) 这里就不能写到包了,路径应该写到你指定的mapper上,xml或者java类,例如:com.example.jisusearch.secondarydao.UserDao,多个的话用逗号分开就可以了。
3、新建dao
@Mapper
public interface PrimaryDao {
@SelectProvider(type = PrimaryProviders.class, method = "getUserSql")
@Results(id = "systemUser", value = {
@Result(property = "userId", column = "user_id"),
@Result(property = "username", column = "username"),
@Result(property = "createUserId", column = "create_user_id"),
@Result(property = "createTime", column = "create_time"),
})
UserModule getUser (String id);
@ResultMap("systemUser")
@SelectProvider(type = PrimaryProviders.class, method = "getUserByParamsSql")
UserModule getUserByParams (String id);
}
扩展一下:我这里做了字段的映射使用的是 @Results和@Result,因为这两个都是方法级的注解,所以为了能共用我为@Results加了id的属性,其他的地方引用使用@ResultMap("yourResultId"),有人说这样不可以,但是本人亲测可用。
另外一个dao包下的方法
@Mapper
public interface SecondaryDao {
@SelectProvider(type = SecondaryProviders.class, method = "getUserSql")
@Results(id = "systemUser", value = {
@Result(property = "userId", column = "user_id"),
@Result(property = "username", column = "username"),
@Result(property = "createUserId", column = "create_user_id"),
@Result(property = "createTime", column = "create_time"),
})
UserModule getUser(@Param("id") String id);
}
这里sql语句我都是用java写的,dao层用的注解@SelectProvider,因为本人实在不喜欢写xml -_-!!!。
4、写你的test类或者使用三层,将到dao正常的注入到你的service或controller内,就可以正常使用了。
@Resource
private PrimaryDao primaryDao;
@Resource
private SecondaryDao secondaryDao;
@RequestMapping("/primary/user")
public Result findUser(String id) {
Result re = new Result();
Map<String, Object> map = new HashMap<>();
UserModule userModule = primaryDao.getUser(id);
UserModule userModule1 = secondaryDao.getUser(id);
UserModule userModule2 = primaryDao.getUserByParams(id);
map.put("first", userModule);
map.put("second", userModule1);
map.put("third", userModule2);
re.setData(map);
return re;
}
这里有个坑,就是注入你的dao时不能使用autowired,因为会报错,你现在多个数据源而不是单个了。
好了, 我的配置到此就结束了,代码直接copy可用。