Recently, a project of the company needs to connect two databases (A and b) for operation. Some modules query database a, and some modules query database B. therefore, the project background uses the spring MVC + mybatis + MySQL architecture. After two days of tossing, it is finally completed. Here, the modification process is recorded.
Usage scenarios
The scenarios for using multiple data sources are as follows:
- Master-slave database switching
- Read / write separation
- Compatible with old Libraries
Realization principle
In the version of spring 2. X, the Proxy mode is used to implement a virtual data source in the scheme, and use it to encapsulate the data source selection logic, so that the data source selection logic can be effectively separated from the Client. The Client provides the context needed for selection, and the virtual dynamic datasource implements the selection of data source according to the context provided by the Client.
The specific implementation is that the virtual dynamic DataSource only needs to inherit AbstractRoutingDataSource to implement determineCurrentLookupKey(), which returns the key value of the DataSource to be used, and then takes the corresponding DataSource from the map of resolvedDataSources according to the key value. If it cannot be found, the default resolvedDefaultDataSource is used.
Detailed implementation process
- Modify spring's configuration file
Multiple data sources need to be configured in the configuration file. After transformation, the main configuration is as follows:
<bean id="dataSourceTargetA" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" scope="singleton"> <property name="driverClass" value="${jdbc.a.driverClassName}" /> <property name="jdbcUrl" value="${jdbc.a.url}" /> <property name="user" value="${jdbc.a.username}" /> <property name="password" value="${jdbc.a.password}" /> <!--When the connections in the connection pool are exhausted c3p0 The number of connections acquired at one time. Default: 3 --> <property name="acquireIncrement" value="${c3p0.acquireIncrement}"></property> <!--Obtain three connections during initialization. The value should be minPoolSize And maxPoolSize Between. Default: 3 --> <property name="initialPoolSize" value="${c3p0.initialPoolSize}"></property> <!--Maximum idle time,60 If not used within seconds, the connection is discarded. If it is 0, it will never be discarded. Default: 0 --> <property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property> <!--The maximum number of connections remaining in the connection pool. Default: 15 --> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property> <property name="minPoolSize" value="${c3p0.minPoolSize}"></property> <!--The interval between two connections, in milliseconds. Default: 1000 --> <property name="acquireRetryDelay" value="1000"></property> <!--Defines the number of times a new connection from the database has failed to be retried. Default: 30 --> <property name="acquireRetryAttempts" value="60"></property> <!--Failure to get the connection will cause all threads waiting for the connection pool to get the connection to throw an exception. But the data source is still valid and will be called next time getConnection()Continue trying to get a connection. If set to true,The data source will declare that it is disconnected and permanently shut down after an attempt to get a connection fails. Default: false --> <property name="breakAfterAcquireFailure" value="false"></property> </bean> <bean id="dataSourceTargetB" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" scope="singleton"> <property name="driverClass" value="${jdbc.b.driverClassName}" /> <property name="jdbcUrl" value="${jdbc.b.url}" /> <property name="user" value="${jdbc.b.username}" /> <property name="password" value="${jdbc.b.password}" /> <!--When the connections in the connection pool are exhausted c3p0 The number of connections acquired at one time. Default: 3 --> <property name="acquireIncrement" value="${c3p0.acquireIncrement}"></property> <!--Obtain three connections during initialization. The value should be minPoolSize And maxPoolSize Between. Default: 3 --> <property name="initialPoolSize" value="${c3p0.initialPoolSize}"></property> <!--Maximum idle time,60 If not used within seconds, the connection is discarded. If it is 0, it will never be discarded. Default: 0 --> <property name="maxIdleTime" value="${c3p0.maxIdleTime}"></property> <!--The maximum number of connections remaining in the connection pool. Default: 15 --> <property name="maxPoolSize" value="${c3p0.maxPoolSize}"></property> <property name="minPoolSize" value="${c3p0.minPoolSize}"></property> <!--The interval between two connections, in milliseconds. Default: 1000 --> <property name="acquireRetryDelay" value="1000"></property> <!--Defines the number of times a new connection has failed to get from the database. Default: 30 --> <property name="acquireRetryAttempts" value="60"></property> <!--Failure to get the connection will cause all threads waiting for the connection pool to get the connection to throw an exception. But the data source is still valid and will be called next time getConnection()Continue trying to get a connection. If set to true,The data source will declare that it is disconnected and permanently shut down after an attempt to get a connection fails. Default: false --> <property name="breakAfterAcquireFailure" value="false"></property> </bean> <!-- Dynamic data source --> <bean id="dynamicDataSource" class="com.test.util.DynamicDataSource" > <property name="targetDataSources"> <map key-type="java.lang.String"> <entry value-ref="dataSourceTargetA" key="dataSourceTargetA"></entry> <entry value-ref="dataSourceTargetB" key="dataSourceTargetB"></entry> </map> </property> <property name="defaultTargetDataSource" ref="dataSourceTargetA" > </property> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dynamicDataSource" /> </bean> <!-- MyBatis ORM operation class --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dynamicDataSource" /> <property name="mapperLocations"> <list> <value>classpath*:com/test/**/*Mapper.xml</value> </list> </property> <property name="configLocation" value="classpath:provider-sql-map-config.xml" /> </bean>