继续上篇文章如何使用mybatis3+spring3并且配置多数据源呢
先上代码在讲解吧
替换上一篇中spring中datasource的配置
新的类DynamicDataSource
新的类DataSourceContextHolder
原来的单元测试新添加一行信息,修改为
最主要的变化是DynamicDataSource 类,这个类继承了AbstractRoutingDataSource,我们再继续考察,发现这个类实现了datasource这个接口。
再仔细研究,发现我配置了多个数据源给DynamicDataSource,默认的数据源是ds1。
我们研究下AbstractRoutingDataSource类的代码,主要是两个实现datasource的方法
根据这段代码发现主要玄机都在determineTargetDataSource()方法上。
根据这段代码发现,首先在使用数据源之前,首先判断使用数据源的key,也就是我们配置给
这个map中的key值,找到key值之后再找到对应的datasource然后并使用这个数据源。
从上面我们发现,实际上DynamicDataSource只是在内部封装了数据源,然后调用它,只不过在内部他加了一些控制而已。(此处不知道是否可以理解为代理模式)
再深一步想想,此处使用的orm层是mybatis,如果换成hibernate呢,或者jdbctemplate呢。
实际上这个方法都适用。
先上代码在讲解吧
替换上一篇中spring中datasource的配置
- <!--数据源配置-->
- <beanid="ds1"class="org.apache.commons.dbcp.BasicDataSource"
- destroy-method="close">
- <propertyname="driverClassName"value="com.mysql.jdbc.Driver"/>
- <propertyname="url"
- value="jdbc:mysql://localhost:3306/payoffdatabase?useUnicode=true&characterEncoding=UTF-8"/>
- <propertyname="username"value="root"/>
- <propertyname="password"value="root"/>
- <propertyname="defaultAutoCommit"value="true"></property>
- </bean>
- <beanid="ds2"class="org.apache.commons.dbcp.BasicDataSource"
- destroy-method="close">
- <propertyname="driverClassName"value="com.mysql.jdbc.Driver"/>
- <propertyname="url"
- value="jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8"/>
- <propertyname="username"value="root"/>
- <propertyname="password"value="root"/>
- <propertyname="defaultAutoCommit"value="true"></property>
- </bean>
- <beanid="dataSource"class="a.b.router.DynamicDataSource">
- <propertyname="targetDataSources">
- <mapkey-type="java.lang.String">
- <entryvalue-ref="ds1"key="ds1"></entry>
- <entryvalue-ref="ds2"key="ds2"></entry>
- </map>
- </property>
- <propertyname="defaultTargetDataSource"ref="ds1"></property>
- </bean>
新的类DynamicDataSource
- packagea.b.router;
- importorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
- publicclassDynamicDataSourceextendsAbstractRoutingDataSource{
- @Override
- protectedObjectdetermineCurrentLookupKey(){
- returnDataSourceContextHolder.getDbType();
- }
- }
新的类DataSourceContextHolder
- packagea.b.router;
- publicclassDataSourceContextHolder{
- privatestaticfinalThreadLocal<String>contextHolder=newThreadLocal<String>();
- publicstaticvoidsetDbType(StringdbType){
- contextHolder.set(dbType);
- }
- publicstaticStringgetDbType(){
- return((String)contextHolder.get());
- }
- publicstaticvoidclearDbType(){
- contextHolder.remove();
- }
- }
原来的单元测试新添加一行信息,修改为
- @Test
- publicvoidaddTest()throwsException{
- UserLoginuserLogin=newUserLogin();
- userLogin.setPassword("102");
- userLogin.setUsername("102");
- DataSourceContextHolder.setDbType("ds2");
- service.add(userLogin);
- }
最主要的变化是DynamicDataSource 类,这个类继承了AbstractRoutingDataSource,我们再继续考察,发现这个类实现了datasource这个接口。
再仔细研究,发现我配置了多个数据源给DynamicDataSource,默认的数据源是ds1。
我们研究下AbstractRoutingDataSource类的代码,主要是两个实现datasource的方法
- publicConnectiongetConnection()throwsSQLException{
- returndetermineTargetDataSource().getConnection();
- }
- publicConnectiongetConnection(Stringusername,Stringpassword)throwsSQLException{
- returndetermineTargetDataSource().getConnection(username,password);
- }
根据这段代码发现主要玄机都在determineTargetDataSource()方法上。
- protectedDataSourcedetermineTargetDataSource(){
- Assert.notNull(this.resolvedDataSources,"DataSourcerouternotinitialized");
- ObjectlookupKey=determineCurrentLookupKey();
- DataSourcedataSource=this.resolvedDataSources.get(lookupKey);
- if(dataSource==null&&(this.lenientFallback||lookupKey==null)){
- dataSource=this.resolvedDefaultDataSource;
- }
- if(dataSource==null){
- thrownewIllegalStateException("CannotdeterminetargetDataSourceforlookupkey["+lookupKey+"]");
- }
- returndataSource;
- }
根据这段代码发现,首先在使用数据源之前,首先判断使用数据源的key,也就是我们配置给
- privateMap<Object,Object>targetDataSources;
这个map中的key值,找到key值之后再找到对应的datasource然后并使用这个数据源。
从上面我们发现,实际上DynamicDataSource只是在内部封装了数据源,然后调用它,只不过在内部他加了一些控制而已。(此处不知道是否可以理解为代理模式)
再深一步想想,此处使用的orm层是mybatis,如果换成hibernate呢,或者jdbctemplate呢。
实际上这个方法都适用。