In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces "how to achieve the switching of multiple data sources by SpringBoot". In the daily operation, I believe that many people have doubts about how to achieve the switching of multiple data sources by SpringBoot. The editor has consulted all kinds of materials and sorted out simple and easy-to-use methods of operation. I hope it will be helpful to answer the doubts of "how to achieve the switching of multiple data sources by SpringBoot". Next, please follow the editor to study!
Preface
In the process of software development, at the beginning, because it is impossible to estimate the number of visits and concurrency in the later stage of the system, we will adopt a single architecture at the beginning, but in the later stage, if the website traffic becomes larger and the concurrency becomes larger, then the architecture may be extended to a micro-service architecture, and each micro-service corresponds to a database, but the cost is a little high, but it may be that some modules are used by more people. Some modules are not used by many people, and if all of them are split into services, it is not necessary. If there are more people using some modules, then we can use read-write separation to reduce the pressure. In this way, the user experience of the system can be improved to a certain extent, but this is only done on the Ibalance O of the database. If the system is under a lot of pressure, then we must do load balancing. Today, we will first talk about the separation of read and write from the database. If we want to achieve the read-write separation of the database at the code level, then the core is the switching of the data source. This paper realizes the switching of the data source based on AOP.
Engineering structure └─ com └─ steak └─ transaction │ TransactionDemoApplication.java │ ├─ datasource │ │ DatasourceChooser.java │ DatasourceConfiguration.java │ │ DatasourceContext.java │ │ DatasourceScope.java │ │ DynamicDatasourceAspect.java │ │ │ └─ properties │ DynamicDatasourceProperties.java │ MainDatasourceProperties.java │ ├─ execute │ PlaceOrderExecute.java │ ├─ rest │ PlaceOrderApi.java │ ├─ result │ R.java │ └─ service IntegralService.java OrderService.java StockService.java
In the following implementation, one of us has three data sources, one of which is the default. If we do not specify a specific data source, then we use the default. We switch the data source based on the declaration method. You only need to annotate the specific interface to switch the data source.
Coding to realize yml file
The main data source directly uses the configuration of spring, and other data sources are customized. Here, a map structure is used to define it, which is convenient for parsing. Multiple data sources can be added in the yml file, and there is no need to change them at the code logic level.
Spring: datasource: type: com.alibaba.druid.pool.DruidDataSource druid: username: root password: 123456 url: jdbc:mysql://127.0.0.1:3306/db?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC driver-class-name: com.mysql.cj.jdbc.Driverdynamic: datasource: {slave1: {username: 'root', password:' 123456' Url: 'url: jdbc:mysql://127.0.0.1:3306/db?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC', driver-class-name:' com.mysql.cj.jdbc.Driver'}, slave2: {username: 'root', password:' 123456, url: 'url: jdbc:mysql://127.0.0.1:3306/db?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC'
For the main data source, we take it out and put it in a class, but it can also be put into dynamic, but we just need to do some processing, so we simply put a few connection attributes.
/ * @ author Liu Brand * @ date 2022 Unip 3Jax 220 spring.datasource.druid 14 * / @ Component@ConfigurationProperties (prefix = "spring.datasource.druid") @ Datapublic class MainDatasourceProperties {private String username; private String password; private String url; private String driverClassName;} other data sources DynamicDatasourceProperties
Other data sources use a Map to accept the data source configuration in the yml file
/ * * @ author Liu Brand * @ date 2022 Unip 3According to 213 Component@ConfigurationProperties 47 * / @ Component@ConfigurationProperties (prefix = "dynamic") @ Datapublic class DynamicDatasourceProperties {private Map datasource;} data source configuration class DatasourceConfiguration
DataSource is mainly configured in the configuration class. The main data source is defined according to the normal bean, while other data sources use reflection to configure the connection properties, because the main data source generally does not change, but other data sources may change and may be added. At this time, if the configuration is taken through hard coding, then each additional data source You need to add a configuration, which is obviously not very good, so you use reflection for assignment.
/ * @ author Liu Brand * @ date 2022 @ Configuration@AllArgsConstructorpublic class DatasourceConfiguration {final MainDatasourceProperties mainDatasourceProperties; final DynamicDatasourceProperties dynamicDatasourceProperties; @ Bean public DataSource datasource () {Map datasourceMap = new HashMap (); DatasourceChooser datasourceChooser = new DatasourceChooser (); / * * main database * / DruidDataSource mainDataSource = new DruidDataSource (); mainDataSource.setUsername (mainDatasourceProperties.getUsername ()) MainDataSource.setPassword (mainDatasourceProperties.getPassword ()); mainDataSource.setUrl (mainDatasourceProperties.getUrl ()); mainDataSource.setDriverClassName (mainDatasourceProperties.getDriverClassName ()); datasourceMap.put ("main", mainDataSource); / * * other database * / Map sourceMap = dynamicDatasourceProperties.getDatasource (); sourceMap.forEach ((datasourceName,datasourceMaps)-> {DruidDataSource dataSource = new DruidDataSource ()) DatasourceMaps.forEach ((KQuery V)-> {String setField = "set" + K.substring (0,1). ToUpperCase () + K.substring (1); / / convert the attribute String [] strings = setField.split ("") with-symbol in yml file; StringBuilder newStr = new StringBuilder (); for (int I = 0) I < strings.length; iTunes +) {if (strings [I] .equals ("-")) strings [I + 1] = strings [I + 1] .toUpperCase (); if (! strings [I] .equals ("-")) newStr.append (strings [I]) } try {DruidDataSource.class.getMethod (newStr.toString (), String.class) .invoke (dataSource,V);} catch (Exception e) {e.printStackTrace ();}}); datasourceMap.put (datasourceName,dataSource);}) / / set target data source datasourceChooser.setTargetDataSources (datasourceMap); / / set default data source datasourceChooser.setDefaultTargetDataSource (mainDataSource); return datasourceChooser;}}
The above uses reflection in the data source configuration class to set connection properties for other data sources, and then sets the target data source and default data source, where there is a DatasourceChooser.
DatasourceChooser
DatasourceChooser inherits from AbstractRoutingDataSource,AbstractRoutingDataSource to switch data sources. The determineCurrentLookupKey () method in it requires us to return the name of a data source, and it will automatically match the data source to us.
/ * @ author Liu Brand * @ date 2022 Unip / public class DatasourceChooser extends AbstractRoutingDataSource {@ Override protected Object determineCurrentLookupKey () {return DatasourceContext.getDatasource ();}}
The following is part of the source code of AbstractRoutingDataSource, we can see that the data source is a Map structure, you can find the corresponding data source through the data source name.
Package org.springframework.jdbc.datasource.lookup;public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {@ Nullable private Map resolvedDataSources; public AbstractRoutingDataSource () {} protected DataSource determineTargetDataSource () {Object lookupKey = this.determineCurrentLookupKey (); DataSource dataSource = (DataSource) this.resolvedDataSources.get (lookupKey);} @ Nullable protected abstract Object determineCurrentLookupKey ();} DatasourceContext
Inside DatasourceContext is a ThreadLocal, which is mainly used to store the data source name of each thread and get the data source name, and the name of the data source is obtained by using the AOP aspect.
/ * * @ author Liu Brand * @ date 2022 Leo * @ public class DatasourceContext {private static final ThreadLocal threadLocal = new ThreadLocal (); public static void setDatasource (String key) {threadLocal.set (key);} public static String getDatasource () {return threadLocal.get ();}} data Source Note DatasourceScope
The DatasourceScope standard specifies the data source through scope above the method, not the default master data source main.
/ * * @ author Liu Brand * @ date 2022 @ Target ({ElementType.METHOD}) @ Retention (RetentionPolicy.RUNTIME) @ Documentedpublic @ interface DatasourceScope {String scope () default "main";} data source section DynamicDatasourceAspect
When we visit every method with DatasourceScope annotations, we will go through the data source section DynamicDatasourceAspect, get the value of scope above the comments, and then set the data source name through DatasourceContext to switch the data source.
/ * * @ author Liu Brand * @ date 2022 Aspect@Componentpublic class DynamicDatasourceAspect {@ Pointcut ("@ annotation (dataSourceScope)") public void dynamicPointcut (DatasourceScope dataSourceScope) {} @ Around (value = "dynamicPointcut (dataSourceScope)", argNames = "joinPoint,dataSourceScope") public Object dynamicAround (ProceedingJoinPoint joinPoint, DatasourceScope dataSourceScope) throws Throwable {String scope = dataSourceScope.scope (); DatasourceContext.setDatasource (scope); return joinPoint.proceed () }} use
You only need to mark the data source annotation @ DatasourceScope on the specific method and specify the value of scope to switch, if not, then the main data source is used.
/ * * @ author Liu Brand * @ date 2022 Service@AllArgsConstructorpublic class OrderService {private JdbcTemplate jdbcTemplate; @ DatasourceScope (scope = "slave1") public R saveOrder (Integer userId, Integer commodityId) {String sql = "INSERT INTO `order` (user_id,commodity_id) VALUES (" + userId+ "," + commodityId+ ")"; jdbcTemplate.execute (sql) Return R.builder (). Code (200). Msg ("save order success"). Build ();} at this point, the study on "how to switch multiple data sources in SpringBoot" is over, hoping to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.