您好,登錄后才能下訂單哦!
springboot 基于mybatis如何實現配置多數據源?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
在實際開發中,我們一個項目可能會用到多個數據庫,通常一個數據庫對應一個數據源。
代碼結構:
簡要原理:
1)DatabaseType列出所有的數據源的key---key
2)DatabaseContextHolder是一個線程安全的DatabaseType容器,并提供了向其中設置和獲取DatabaseType的方法
3)DynamicDataSource繼承AbstractRoutingDataSource并重寫其中的方法determineCurrentLookupKey(),在該方法中使用DatabaseContextHolder獲取當前線程的DatabaseType
4)MyBatisConfig中生成2個數據源DataSource的bean---value
5)MyBatisConfig中將1)和4)組成的key-value對寫入到DynamicDataSource動態數據源的targetDataSources屬性(當然,同時也會設置2個數據源其中的一個為DynamicDataSource的defaultTargetDataSource屬性中)
6)將DynamicDataSource作為primary數據源注入到SqlSessionFactory的dataSource屬性中去,并且該dataSource作為transactionManager的入參來構造DataSourceTransactionManager
7)使用的時候,在dao層或service層先使用DatabaseContextHolder設置將要使用的數據源key,然后再調用mapper層進行相應的操作,建議放在dao層去做(當然也可以使用spring aop+自定注解去做)
注意:在mapper層進行操作的時候,會先調用determineCurrentLookupKey()方法獲取一個數據源(獲取數據源:先根據設置去targetDataSources中去找,若沒有,則選擇defaultTargetDataSource),之后在進行數據庫操作。
1、假設有兩個數據庫,配置如下
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
說明:在之前的配置的基礎上,只增加了上述的第二個數據源。
2、DatabaseType
package com.xxx.firstboot.common.datasource; /** * 列出所有的數據源key(常用數據庫名稱來命名) * 注意: * 1)這里數據源與數據庫是一對一的 * 2)DatabaseType中的變量名稱就是數據庫的名稱 */ public enum DatabaseType { mytestdb,mytestdb2 }
作用:列舉數據源的key。
3、DatabaseContextHolder
package com.xxx.firstboot.common.datasource; /** * 作用: * 1、保存一個線程安全的DatabaseType容器 */ public class DatabaseContextHolder { private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>(); public static void setDatabaseType(DatabaseType type){ contextHolder.set(type); } public static DatabaseType getDatabaseType(){ return contextHolder.get(); } }
作用:構建一個DatabaseType容器,并提供了向其中設置和獲取DatabaseType的方法
4、DynamicDataSource
package com.xxx.firstboot.common.datasource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 動態數據源(需要繼承AbstractRoutingDataSource) */ public class DynamicDataSource extends AbstractRoutingDataSource { protected Object determineCurrentLookupKey() { return DatabaseContextHolder.getDatabaseType(); } }
作用:使用DatabaseContextHolder獲取當前線程的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)創建數據源(如果采用的是默認的tomcat-jdbc數據源,則不需要) * 2)創建SqlSessionFactory 3)配置事務管理器,除非需要使用事務,否則不用配置 */ @Configuration // 該注解類似于spring配置文件 @MapperScan(basePackages = "com.xxx.firstboot.mapper") public class MyBatisConfig { @Autowired private Environment env; /** * 創建數據源(數據源的名稱:方法名可以取為XXXDataSource(),XXX為數據庫名稱,該名稱也就是數據源的名稱) */ @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 該注解表示在同一個接口有多個實現類可以注入的時候,默認選擇哪一個,而不是讓@autowire注解報錯 * @Qualifier 根據名稱進行注入,通常是在具有相同的多個類型的實例的一個注入(例如有多個DataSource類型的實例) */ @Bean @Primary public DynamicDataSource dataSource(@Qualifier("myTestDbDataSource") DataSource myTestDbDataSource, @Qualifier("myTestDb2DataSource") DataSource myTestDb2DataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DatabaseType.mytestdb, myTestDbDataSource); targetDataSources.put(DatabaseType.mytestdb2, myTestDb2DataSource); DynamicDataSource dataSource = new DynamicDataSource(); dataSource.setTargetDataSources(targetDataSources);// 該方法是AbstractRoutingDataSource的方法 dataSource.setDefaultTargetDataSource(myTestDbDataSource);// 默認的datasource設置為myTestDbDataSource return dataSource; } /** * 根據數據源創建SqlSessionFactory */ @Bean public SqlSessionFactory sqlSessionFactory(DynamicDataSource ds) throws Exception { SqlSessionFactoryBean fb = new SqlSessionFactoryBean(); fb.setDataSource(ds);// 指定數據源(這個必須有,否則報錯) // 下邊兩句僅僅用于*.xml文件,如果整個持久層操作不需要使用到xml文件的話(只用注解就可以搞定),則不加 fb.setTypeAliasesPackage(env.getProperty("mybatis.typeAliasesPackage"));// 指定基包 fb.setMapperLocations( new PathMatchingResourcePatternResolver().getResources(env.getProperty("mybatis.mapperLocations")));// return fb.getObject(); } /** * 配置事務管理器 */ @Bean public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception { return new DataSourceTransactionManager(dataSource); } }
作用:
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); } }
注意:首先設置了數據源的key,然后調用mapper(在mapper中會首先根據該key從動態數據源中查詢出相應的數據源,之后取出連接進行數據庫操作)
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相關api") public class ShopController { @Autowired private ShopService service; @ApiOperation("獲取shop信息,測試多數據源") @RequestMapping(value = "/getShop", method = RequestMethod.GET) public Shop getShop(@RequestParam("id") int id) { return service.getShop(id); } }
補:其實DatabaseContextHolder和DynamicDataSource完全可以合為一個類
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。