好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Spring AbstractRoutingDatasource 动态数据源的实例讲解

Spring AbstractRoutingDatasource 动态数据源

数据源上下文

AbstractRoutingDatasource 需要信息决定路由到那个数据源,该信息我们称为上下文。可以市任何对象,下面示例我们使用枚举 ClientDatabase 作为上下文:

?

1

2

3

public enum ClientDatabase {

     CLIENT_A, CLIENT_B

}

值得注意的是,实际中上下文可以是任何有意义的领域对象。如 Environment 定义上下文,在这种上下文中枚举可以包括 PRODUCTION, DEVELOPMENT, and TESTING.

上下文持有者 ( ContextHolder )

上下文持有者实现是存储当前上下文的容器,如 ThreadLocal 对象。除了包括上下文引用外,还应该包括set , get , clear 静态方法,AbstractRoutingDatasource 将查询 ContextHolder 获得 上下文,然后使用上下文查找实际的数据源。

这里最重要的是使用 ThreadLocal ,让上下文绑定只当前执行线程。使用这种方法就是为了保障当数据访问逻辑跨多个数据源使用事务:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

public class ClientDatabaseContextHolder {

     private static ThreadLocal<ClientDatabase> CONTEXT  = new ThreadLocal<>();

     public static void set(ClientDatabase clientDatabase) {

         Assert.notNull(clientDatabase, "clientDatabase cannot be null" );

         CONTEXT.set(clientDatabase);

     }

     public static ClientDatabase getClientDatabase() {

         return CONTEXT.get();

     }

     public static void clear() {

         CONTEXT.remove();

     }

}

数据源路由器

下面定义 ClientDataSourceRouter 继承 AbstractRoutingDataSource. 重写方法 determineCurrentLookupKey ,查询 ClientDatabaseContextHolder 获得当前 上下文。AbstractRoutingDataSource 帮我们处理了其他逻辑,仅了解它透明地返回了合适的数据源:

?

1

2

3

4

5

6

public class ClientDataSourceRouter extends AbstractRoutingDataSource {

     @Override

     protected Object determineCurrentLookupKey() {

         return ClientDatabaseContextHolder.getClientDatabase();

     }

}

配置

下面利用Map上下文存储DataSource对象,用于配置 AbstractRoutingDataSource 。当然也可以指定缺省数据源,当没有设定上下文时选择缺省数据源。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

@Configuration

public class RoutingTestConfiguration {

     @Bean

     public ClientService clientService() {

         return new ClientService( new ClientDao(clientDatasource()));

     }

 

     @Bean

     public DataSource clientDatasource() {

         Map<Object, Object> targetDataSources = new HashMap<>();

         DataSource clientADatasource = clientADatasource();

         DataSource clientBDatasource = clientBDatasource();

         targetDataSources.put(ClientDatabase.CLIENT_A, clientADatasource);

         targetDataSources.put(ClientDatabase.CLIENT_B, clientBDatasource);

         ClientDataSourceRouter clientRoutingDatasource  = new ClientDataSourceRouter();

         clientRoutingDatasource.setTargetDataSources(targetDataSources);

         clientRoutingDatasource.setDefaultTargetDataSource(clientADatasource);       

         return clientRoutingDatasource;

     }

     // ...

}

我们可以使用不同方式的数据源,但典型场景时运行时创建,或使用JNDI方式查找。下面定义示例的Dao类,它依赖动态数据源进行实例化:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

public class ClientDao {

     private static final String SQL_GET_CLIENT_NAME = "select name from client" ;

     private final JdbcTemplate jdbcTemplate;

     public ClientDao(DataSource datasource) {

         this .jdbcTemplate = new JdbcTemplate(datasource);

     }

     public String getClientName() {

         return this .jdbcTemplate.query(SQL_GET_CLIENT_NAME, rowMapper).get( 0 );

     }

     private static RowMapper<String> rowMapper = (rs, rowNum) -> {

         return rs.getString( "name" );

     };

}

使用动态数据源

实际使用时,首先设置上下文,然后再执行业务操作。我们定义业务层,其中业务方法包括上下文作为参数。在执行业务之前设置上下文,调用之后清除上下文:

?

1

2

3

4

5

6

7

8

9

10

11

12

public class ClientService {

     private final ClientDao clientDao;

     public ClientService(ClientDao clientDao) {

         this .clientDao = clientDao;

     }

     public String getClientName(ClientDatabase clientDb) {

         ClientDatabaseContextHolder.set(clientDb);

         String clientName = this .clientDao.getClientName();

         ClientDatabaseContextHolder.clear();

         return clientName;

     }

}

总结

本文通过示例解释如何使用 Spring AbstractRoutingDataSource 实现 动态数据源切换。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/neweastsun/article/details/118281324

查看更多关于Spring AbstractRoutingDatasource 动态数据源的实例讲解的详细内容...

  阅读:16次