真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

springboot基于mybatis如何實(shí)現(xiàn)配置多數(shù)據(jù)源

springboot 基于mybatis如何實(shí)現(xiàn)配置多數(shù)據(jù)源?很多新手對此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

創(chuàng)新互聯(lián)公司長期為近1000家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為新邵企業(yè)提供專業(yè)的成都網(wǎng)站建設(shè)、網(wǎng)站建設(shè),新邵網(wǎng)站改版等技術(shù)服務(wù)。擁有十載豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開發(fā)。

在實(shí)際開發(fā)中,我們一個(gè)項(xiàng)目可能會用到多個(gè)數(shù)據(jù)庫,通常一個(gè)數(shù)據(jù)庫對應(yīng)一個(gè)數(shù)據(jù)源。

代碼結(jié)構(gòu):

springboot 基于mybatis如何實(shí)現(xiàn)配置多數(shù)據(jù)源

簡要原理:

1)DatabaseType列出所有的數(shù)據(jù)源的key---key

2)DatabaseContextHolder是一個(gè)線程安全的DatabaseType容器,并提供了向其中設(shè)置和獲取DatabaseType的方法

3)DynamicDataSource繼承AbstractRoutingDataSource并重寫其中的方法determineCurrentLookupKey(),在該方法中使用DatabaseContextHolder獲取當(dāng)前線程的DatabaseType

4)MyBatisConfig中生成2個(gè)數(shù)據(jù)源DataSource的bean---value

5)MyBatisConfig中將1)和4)組成的key-value對寫入到DynamicDataSource動態(tài)數(shù)據(jù)源的targetDataSources屬性(當(dāng)然,同時(shí)也會設(shè)置2個(gè)數(shù)據(jù)源其中的一個(gè)為DynamicDataSource的defaultTargetDataSource屬性中)

6)將DynamicDataSource作為primary數(shù)據(jù)源注入到SqlSessionFactory的dataSource屬性中去,并且該dataSource作為transactionManager的入?yún)順?gòu)造DataSourceTransactionManager

7)使用的時(shí)候,在dao層或service層先使用DatabaseContextHolder設(shè)置將要使用的數(shù)據(jù)源key,然后再調(diào)用mapper層進(jìn)行相應(yīng)的操作,建議放在dao層去做(當(dāng)然也可以使用spring aop+自定注解去做)

注意:在mapper層進(jìn)行操作的時(shí)候,會先調(diào)用determineCurrentLookupKey()方法獲取一個(gè)數(shù)據(jù)源(獲取數(shù)據(jù)源:先根據(jù)設(shè)置去targetDataSources中去找,若沒有,則選擇defaultTargetDataSource),之后在進(jìn)行數(shù)據(jù)庫操作。

 1、假設(shè)有兩個(gè)數(shù)據(jù)庫,配置如下

application.properties

#the first datasource
jdbc.driverClassName = com.MySQL.jdbc.Driver
jdbc.url = jdbc:mysql://xxx:3306/mytestdb?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
jdbc.username = root
jdbc.password = 123

#the second datasource
jdbc2.driverClassName = com.mysql.jdbc.Driver
jdbc2.url = jdbc:mysql://xxx:3306/mytestdb2?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8
jdbc2.username = root
jdbc2.password = 123

說明:在之前的配置的基礎(chǔ)上,只增加了上述的第二個(gè)數(shù)據(jù)源。 

2、DatabaseType

package com.xxx.firstboot.common.datasource;

/**
 * 列出所有的數(shù)據(jù)源key(常用數(shù)據(jù)庫名稱來命名)
 * 注意:
 * 1)這里數(shù)據(jù)源與數(shù)據(jù)庫是一對一的
 * 2)DatabaseType中的變量名稱就是數(shù)據(jù)庫的名稱
 */
public enum DatabaseType {
  mytestdb,mytestdb2
}

作用:列舉數(shù)據(jù)源的key。

3、DatabaseContextHolder

package com.xxx.firstboot.common.datasource;

/**
 * 作用:
 * 1、保存一個(gè)線程安全的DatabaseType容器
 */
public class DatabaseContextHolder {
  private static final ThreadLocal contextHolder = new ThreadLocal<>();
  
  public static void setDatabaseType(DatabaseType type){
    contextHolder.set(type);
  }
  
  public static DatabaseType getDatabaseType(){
    return contextHolder.get();
  }
}

作用:構(gòu)建一個(gè)DatabaseType容器,并提供了向其中設(shè)置和獲取DatabaseType的方法

4、DynamicDataSource

package com.xxx.firstboot.common.datasource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 動態(tài)數(shù)據(jù)源(需要繼承AbstractRoutingDataSource)
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
  protected Object determineCurrentLookupKey() {
    return DatabaseContextHolder.getDatabaseType();
  }
}

作用:使用DatabaseContextHolder獲取當(dāng)前線程的DatabaseType 

5、MyBatisConfig

package com.xxx.firstboot.common;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.xxx.firstboot.common.datasource.DatabaseType;
import com.xxx.firstboot.common.datasource.DynamicDataSource;

/**
 * springboot集成mybatis的基本入口 1)創(chuàng)建數(shù)據(jù)源(如果采用的是默認(rèn)的tomcat-jdbc數(shù)據(jù)源,則不需要)
 * 2)創(chuàng)建SqlSessionFactory 3)配置事務(wù)管理器,除非需要使用事務(wù),否則不用配置
 */
@Configuration // 該注解類似于spring配置文件
@MapperScan(basePackages = "com.xxx.firstboot.mapper")
public class MyBatisConfig {

  @Autowired
  private Environment env;

  /**
   * 創(chuàng)建數(shù)據(jù)源(數(shù)據(jù)源的名稱:方法名可以取為XXXDataSource(),XXX為數(shù)據(jù)庫名稱,該名稱也就是數(shù)據(jù)源的名稱)
   */
  @Bean
  public DataSource myTestDbDataSource() throws Exception {
    Properties props = new Properties();
    props.put("driverClassName", env.getProperty("jdbc.driverClassName"));
    props.put("url", env.getProperty("jdbc.url"));
    props.put("username", env.getProperty("jdbc.username"));
    props.put("password", env.getProperty("jdbc.password"));
    return DruidDataSourceFactory.createDataSource(props);
  }

  @Bean
  public DataSource myTestDb2DataSource() throws Exception {
    Properties props = new Properties();
    props.put("driverClassName", env.getProperty("jdbc2.driverClassName"));
    props.put("url", env.getProperty("jdbc2.url"));
    props.put("username", env.getProperty("jdbc2.username"));
    props.put("password", env.getProperty("jdbc2.password"));
    return DruidDataSourceFactory.createDataSource(props);
  }

  /**
   * @Primary 該注解表示在同一個(gè)接口有多個(gè)實(shí)現(xiàn)類可以注入的時(shí)候,默認(rèn)選擇哪一個(gè),而不是讓@autowire注解報(bào)錯(cuò)
   * @Qualifier 根據(jù)名稱進(jìn)行注入,通常是在具有相同的多個(gè)類型的實(shí)例的一個(gè)注入(例如有多個(gè)DataSource類型的實(shí)例)
   */
  @Bean
  @Primary
  public DynamicDataSource dataSource(@Qualifier("myTestDbDataSource") DataSource myTestDbDataSource,
      @Qualifier("myTestDb2DataSource") DataSource myTestDb2DataSource) {
    Map targetDataSources = new HashMap<>();
    targetDataSources.put(DatabaseType.mytestdb, myTestDbDataSource);
    targetDataSources.put(DatabaseType.mytestdb2, myTestDb2DataSource);

    DynamicDataSource dataSource = new DynamicDataSource();
    dataSource.setTargetDataSources(targetDataSources);// 該方法是AbstractRoutingDataSource的方法
    dataSource.setDefaultTargetDataSource(myTestDbDataSource);// 默認(rèn)的datasource設(shè)置為myTestDbDataSource

    return dataSource;
  }

  /**
   * 根據(jù)數(shù)據(jù)源創(chuàng)建SqlSessionFactory
   */
  @Bean
  public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception {
    SqlSessionFactoryBean fb = new SqlSessionFactoryBean();
    fb.setDataSource(ds);// 指定數(shù)據(jù)源(這個(gè)必須有,否則報(bào)錯(cuò))
    // 下邊兩句僅僅用于*.xml文件,如果整個(gè)持久層操作不需要使用到xml文件的話(只用注解就可以搞定),則不加
    fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));// 指定基包
    fb.setMapperLocations(
        new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));//

    return fb.getObject();
  }

  /**
   * 配置事務(wù)管理器
   */
  @Bean
  public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
    return new DataSourceTransactionManager(dataSource);
  }

}

作用:

  • 通過讀取application.properties文件生成兩個(gè)數(shù)據(jù)源(myTestDbDataSource、myTestDb2DataSource)
  • 使用以上生成的兩個(gè)數(shù)據(jù)源構(gòu)造動態(tài)數(shù)據(jù)源dataSource
    • @Primary:指定在同一個(gè)接口有多個(gè)實(shí)現(xiàn)類可以注入的時(shí)候,默認(rèn)選擇哪一個(gè),而不是讓@Autowire注解報(bào)錯(cuò)(一般用于多數(shù)據(jù)源的情況下)
    • @Qualifier:指定名稱的注入,當(dāng)一個(gè)接口有多個(gè)實(shí)現(xiàn)類的時(shí)候使用(在本例中,有兩個(gè)DataSource類型的實(shí)例,需要指定名稱注入)
    • @Bean:生成的bean實(shí)例的名稱是方法名(例如上邊的@Qualifier注解中使用的名稱是前邊兩個(gè)數(shù)據(jù)源的方法名,而這兩個(gè)數(shù)據(jù)源也是使用@Bean注解進(jìn)行注入的)
  • 通過動態(tài)數(shù)據(jù)源構(gòu)造SqlSessionFactory和事務(wù)管理器(如果不需要事務(wù),后者可以去掉)

 6、使用

ShopMapper:

package com.xxx.firstboot.mapper;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;

import com.xxx.firstboot.domain.Shop;

public interface ShopMapper {

  @Select("SELECT * FROM t_shop WHERE id = #{id}")
  @Results(value = { @Result(id = true, column = "id", property = "id"),
            @Result(column = "shop_name", property = "shopName") })
  public Shop getShop(@Param("id") int id);

}

ShopDao:

package com.xxx.firstboot.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.xxx.firstboot.common.datasource.DatabaseContextHolder;
import com.xxx.firstboot.common.datasource.DatabaseType;
import com.xxx.firstboot.domain.Shop;
import com.xxx.firstboot.mapper.ShopMapper;

@Repository
public class ShopDao {
  @Autowired
  private ShopMapper mapper;

  /**
   * 獲取shop
   */
  public Shop getShop(int id) {
    DatabaseContextHolder.setDatabaseType(DatabaseType.mytestdb2);
    return mapper.getShop(id);
  }
}

注意:首先設(shè)置了數(shù)據(jù)源的key,然后調(diào)用mapper(在mapper中會首先根據(jù)該key從動態(tài)數(shù)據(jù)源中查詢出相應(yīng)的數(shù)據(jù)源,之后取出連接進(jìn)行數(shù)據(jù)庫操作)

ShopService:

package com.xxx.firstboot.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xxx.firstboot.dao.ShopDao;
import com.xxx.firstboot.domain.Shop;

@Service
public class ShopService {

  @Autowired
  private ShopDao dao;

  public Shop getShop(int id) {
    return dao.getShop(id);
  }
}

ShopController:

package com.xxx.firstboot.web;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.xxx.firstboot.domain.Shop;
import com.xxx.firstboot.service.ShopService;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping("/shop")
@Api("shopController相關(guān)api")
public class ShopController {

  @Autowired
  private ShopService service;

  @ApiOperation("獲取shop信息,測試多數(shù)據(jù)源")
  @RequestMapping(value = "/getShop", method = RequestMethod.GET)
  public Shop getShop(@RequestParam("id") int id) {
    return service.getShop(id);
  }

}

補(bǔ):其實(shí)DatabaseContextHolder和DynamicDataSource完全可以合為一個(gè)類

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。


網(wǎng)站題目:springboot基于mybatis如何實(shí)現(xiàn)配置多數(shù)據(jù)源
路徑分享:http://weahome.cn/article/jshode.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部