The springboot framework mybatis integrates multiple data source configurations

background:

     Recently, during my study, I learned the configuration of multiple data sources. I found a lot of information on the Internet while configuring, stepping on pits, and learning at the same time. Let’s record it.

reference:

 This article refers to several articles, but there are more or less problems, so I integrated it myself. link released

https://blog.csdn.net/maoyeqiu/article/details/74011626

https://blog.csdn.net/mxw2552261/article/details/78640062

The problem that arises:

https://my.oschina.net/chinesedragon/blog/1647846

Early preparation:

 springboot 2.0, mybatis, tools: SqlSessionFactory and SqlSessionTemplate

 

Multiple data sources:

 First, post my configuration (declare, the yml format I use here)

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

 I have configured two data sources here. If there are more than one, you can configure them in the same way. I use mysql.

Pit 1

   Here is a little bit to say, if the data source of the configuration sheet should be spring.datasource.name, here because multiple configurations should follow spring.yourname.datasource.name, the difference is that a custom name is added in front of the datasource, so as to distinguish multiple data sources, and if not added, an error will be reported during compilation. Duplicate datasource in the configuration file.

Pit 2

   Here, when configuring the database connection, the single-source or springboot1.x version generally uses url: xxxxxxxx, but in this case, there are multiple sources and my version is 2.0, so it should be written as jdbc-url: xxxxx. The reason is that the version or multiple data sources can only be asked by the master.

 After the data source is configured, the configuration of the data source will be automatically loaded when starting in springboot, and an error will occur at this time, so we add a property to the annotation in your startup class application.java.

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableTransactionManagement
public class JisusearchApplication {


   public static void main(String[] args) {
      SpringApplication.run(JisusearchApplication.class, args);
   }
}

  It is in the startup annotation that SpringBootApplication adds the exclude attribute. Here is to prevent springboot from automatically creating datasource and ignoring our configuration.

 

New datasource:

  We disabled the datasource created by springboot by default, and then we will create the multiple datasources we need.

  1. Create a new class to configure 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();
    }


}

First, @Configuration specifies that this class is the configuration class of spring, which is equivalent to xml.

Then configure the data source information you configured in your properties or yml file

@ConfigurationProperties(prefix = "spring.secondary.datasource")

This annotation will go to the properties file to find the configuration you specified with the prefix spring.secondary.datasource, so this value should be consistent with what is in your configuration file.

Of course you can customize the name, mine may be a bit long.

   Note :

It should be noted here that the annotation @Qulifier I commented out is to specify the name for this class. Because I used the annotation bean, I cannot specify it repeatedly, otherwise an error will be reported. In addition, a default data source @Primary (specify the default data source) can be specified here. Some people on the Internet say that it is not necessary, but if I do not specify it here, an error will be reported.

Please give me some pointers from those who know this pit.

2. Next, use the tool class SqlSessionFactory and SqlSessionTemplate to improve your configuration

Mine are created separately, that is, if you have several data sources, you can create several configuration classes. Of course, if you create more first, you can also integrate this step and the previous step into one class, depending on your personal needs.

Above code:

@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;
    }
}

Introduce the datasource configured in the previous step here, and specify which data source your current SqlSessionFactory is using by annotating @Qualifier, and add the annotation @Configuration to the class to declare the class as a configuration class;

@MapperScan(basePackages = {"com.example.jisusearch.primarydao"}, sqlSessionFactoryRef = "primarySqlSessionFactory")

This annotation specifies which package you want to use this data source, and you must write the full path, otherwise an error will be reported. The latter attribute is the name of the bean of your SqlSessionFactory.

Here is the configuration of a data source, and then configure another one, similar to the code directly.

@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;
    }
}

Because I want to separate them, I built two daos, and you can also specify these two in one dao, but @MapperScan(basePackages = {"com.example.jisusearch.secondarydao"}) cannot write packages here, and the path should be written to the mapper you specified, xml or java class, for example: com.example.jisusearch.secondarydao.UserDao, if there are multiple, just separate them with commas.

3. Create a new 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);

}

   

To expand: I used @Results and @Result for the field mapping here, because these two are method-level annotations, so in order to share the id attribute I added to @Results, other places use @ResultMap("yourResultId"). Some people say that this is not possible, but I personally tested it.

Another method under the dao package

@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);


}

  Here I write the sql statements in java, and the annotation @SelectProvider is used in the dao layer, because I really don’t like to write xml -_-!!!.

4. Write your test class or use three layers, inject dao into your service or controller normally, and then it can be used normally.

    @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;
    }

  There is a pitfall here, that is, you cannot use autowired when injecting your dao, because an error will be reported, and you now have multiple data sources instead of a single one .

Well, my configuration is over here, and the code can be copied directly.

Guess you like

Origin blog.csdn.net/Mars_wen/article/details/81116430