First, the configuration related to the introduction maven
mybatis; mysql drive; JDBC
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.18</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> <version>2.2.2.RELEASE</version> </dependency>
Second, write a configuration file
Configuring two data sources: here I configured a Tencent cloud database and a local database
Specify four fields: the database link, user name, password, driver
Third, write database type enumeration
public enum DataSourceEnum { TENCENT(0),LOCAL(1); private int value; private DataSourceEnum(int _value) { this.value=_value; } }
Fourth, write a configuration file to read helper
Note: I made this step here is to show more transparency in the process of configuring a data source, if you want to be lazy, this step can not do it, read the configuration files directly injected into the container through annotations
DataSourceElement database link entity
/ * Database link entity class * fields and profiles consistent * / public class DataSourceElement { Private String url; Private String userName; Private String password; Private String classDirver;
// ignore setter getter }
DataSourceItem class configuration read Help
@Component @ConfigurationProperties (prefix = "spring.datasource" ) public class DataSourceItem { // Tencent cloud configuration file corresponding to the link-DB Tencent Private DataSourceElement tencentDb; // local configuration file corresponding to the link-DB local Private DataSourceElement LocalDB; // Ignore getter serrer }
Fifth, get help writing class data sources in the current thread of execution
This class is required to specify the data sources used in our current thread
public class DynamicDataSourceManger { / * * Initialize the current thread database type * / Private static Final the ThreadLocal <DataSourceEnum> = threadLocalDbType new new the ThreadLocal <DataSourceEnum> () { @Override protected DataSourceEnum the initialValue () { return DataSourceEnum.TENCENT; } ; }; / * Get current thread database * / public static DataSourceEnum GET () { return threadLocalDbType.get (); } / * set the current thread database * / public static void SET (DataSourceEnum dataSourceEnum) { threadLocalDbType.set (dataSourceEnum); } / * clear the current thread database cache * / public static void RESET () { threadLocalDbType.remove (); } }
Six, inherited AbstractRoutingDataSource
AbstractRoutingDataSource is dynamically switch data sources to provide tools like spring, he can realize the data source routing switch during operation, please also check the official document, just write to me how to use
simple terms that he would come get us through our designated key set of different data sources, data source arranged below will be written.
Here the data source to get the current thread to be executed by DynamicDataSourceManger we write the above key
public class DynamicDataSource the extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey () { / * reads the current thread data source configured key value * / return DynamicDataSourceManger.get (); } }
Seven configure multiple data sources, and to achieve the AbstractRoutingDataSource
Note: The following code I used to write in our fourth class profiles help to get the contents of the configuration file to achieve the Bean injection, doing so for the convenience of the reader to understand the process of creating a DataSource
You may be directly used @ConfigurationProperties (prefix = "spring.datasource.tencent-db") directly mounted up, so only need to write one line
. DataSource dataSource = DataSourceBuilder.create () build (); to
note: 1 We need to specify unreasonable barrier for the data source Bean name to prevent conflicts.
2. The need to add @Primary on the acquisition Bean AbstractRoutingDataSource realized
3. after preparation of the spring need to turn off automatically configure the data source, otherwise it will lead to cyclic dependencies (write below)
the spring vessel injection category
/ * Data source implant * / @Configuration public class DynamicDataSourceConfiguration { / * get the database link * / @Autowired DataSourceItem dataSourceItem; / * injection Tencent cloud database * / @Bean (name = "TENCENTDB" ) public the DataSource getTencentDataSource () { DataSourceElement tencentSoure = dataSourceItem.getTencentDb (); the DataSource the dataSource = DataSourceBuilder.create () .url (tencentSoure.getUrl ()) .username (tencentSoure.getUserName ()) .password (tencentSoure.getPassword ()) .driverClassName(tencentSoure.getClassDirver()) .build(); return dataSource; } /*注入本地数据库*/ @Bean(name = "LOCALDB") public DataSource getLocalDataSource() { DataSourceElement localSource = dataSourceItem.getLocalDb(); DataSource dataSource = DataSourceBuilder.create() .url(localSource.getUrl()) .username(localSource.getUserName()) .password(localSource.getPassword()) .driverClassName(localSource.getClassDirver()) .build(); return dataSource; } /*注入AbstractRoutingDataSource*/ @Bean @Primary public DynamicDataSource getDyanmiceDataSource(@Qualifier("TENCENTDB") DataSource tencentDb, @Qualifier("LOCALDB") DataSource localDb) { Map<Object,Object> hashMap=new HashMap<Object, Object>(); hashMap.put(DataSourceEnum.TENCENT,tencentDb); hashMap.put(DataSourceEnum.LOCAL,localDb); DynamicDataSource dataSource= New new DynamicDataSource (); / * set the data source * / dataSource.setTargetDataSources (hashMap '); / * set the default data source * / dataSource.setDefaultTargetDataSource (tencentDb); / * invoke methods implement data source configuration * / dataSource.afterPropertiesSet () ; return the dataSource; } }
Spring Boot startup settings change, the data source automatically shut down and manual injection configuration class our injected into the vessel IOC
@Import(DynamicDataSourceConfiguration.class) @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) public class DynamicApplication { public static void main(String[] args) { SpringApplication.run(DynamicApplication.class, args); } }
Eight, write entity classes, Mybatis the Mapper and XML, configuration Mybatis
Here I built a table called t_user in Tencent cloud, built in the local library table called a person of
We are writing their Mapper and entities, and XML.
The following codes are removed from the get and set, and the code is written together to facilitate comparison, the actual open time is written (which is the basis of it .... I should not say)
public class Person { private Integer id; private String name; private String address; private String province; private String city; private String area; } public class User { private Integer id; private String name; private String sex; private String address; private String city; private String area; }
Mapper
@Mapper public interface PersonMapper { List<Person> selectAllPerson(); } @Mapper public interface UserMapper { List<User> selectAllUser(); }
XML
<mapper namespace="com.example.dynamic.mapper.PersonMapper"> <select id="selectAllPerson" resultType="com.example.dynamic.model.Person"> select * from person </select> </mapper> <mapper namespace="com.example.dynamic.mapper.UserMapper"> <select id="selectAllUser" resultType="com.example.dynamic.model.User"> select * from t_user </select> </mapper>
interface
We both interfaces were called Tencent cloud and two local data sources, before calling in DynamicDataSourceManger written by switching fifth to implement key source of data for the current thread
@RestController @RequestMapping("/hello") public class DynamicDataSourceController { @Autowired UserMapper userMapper; @Autowired PersonMapper personMapper; @RequestMapping("/user") public List<User> selectAllUser(){ DynamicDataSourceManger.set(DataSourceEnum.TENCENT); return userMapper.selectAllUser(); } @RequestMapping("/person") public List<Person> selectAllPerson(){ DynamicDataSourceManger.set(DataSourceEnum.LOCAL); return personMapper.selectAllPerson(); } }
Nine, call interface
Call Tencent cloud data source
Call local data source
We found that this time has been achieved to switch multiple data sources, such an approach is actually a little stiff, you need to manually set the data source, by way of AOP compiled into the data source settings
It would be more convenient, I would not bother to write here, I believe we will springAOP.