背景:
最近在學習當中,學到了多數據源的配置,在網上找了很多的資料一邊配置,一邊踩坑,也一邊在學習,以此記錄一下吧。
參考:
本文參考了幾個文章,但是或多多少都有些問題,所以我自己整合了下。鏈接放出
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可用。