How to use Spring AbstractRoutingDataSource with dynamic datasources?

前端 未结 2 1854
情歌与酒
情歌与酒 2020-12-05 21:25

I am working in a project using Spring, Spring Data JPA, Spring Security, Primefaces...

I was following this tutorial about dynamic datasource routing with spring.

相关标签:
2条回答
  • 2020-12-05 21:55

    Nothing in AbstractRoutingDataSource forces you to use a static map of DataSourceS. It is up to you to contruct a bean implementing Map<Object, Object>, where key is what you use to select the DataSource, and value is a DataSource or (by default) a String referencing a JNDI defined data source. You can even modify it dynamically since, as the map is stored in memory, AbstractRoutingDataSource does no caching.

    I have no full example code. But here is what I can imagine. In a web application, you have one database per client, all with same structure - ok, it would be a strange design, say it is just for the example. At login time, the application creates the datasource for the client and stores it in a map indexed by sessionId - The map is a bean in root context named dataSources

    @Autowired
    @Qualifier("dataSources");
    Map<String, DataSource> sources;
    
    // I assume url, user and password have been found from connected user
    // I use DriverManagerDataSource for the example because it is simple to setup
    DataSource dataSource = new DriverManagerDataSource(url, user, password);
    sources.put(request.getSession.getId(), dataSource);
    

    You also need a session listener to cleanup dataSources in its destroy method

    @Autowired
    @Qualifier("dataSources");
    Map<String, DataSource> sources;
    
    public void sessionDestroyed(HttpSessionEvent se)  {
        // eventually cleanup the DataSource if appropriate (nothing to do for DriverManagerDataSource ...)
        sources.remove(se.getSession.getId());
    }
    

    The routing datasource could be like :

    public class SessionRoutingDataSource extends AbstractRoutingDataSource {
    
        @Override
        protected Object determineCurrentLookupKey() {
            HttpServletRequest request = ((ServletRequestAttributes)
                    RequestContextHolder.getRequestAttributes()).getRequest();
            return request.getSession().getId();
        }
    
        @Autowired
        @Qualifier("dataSources")
        public void setDataSources(Map<String, DataSource> dataSources) {
            setTargetDataSources(dataSources);
    }
    

    I have not tested anything because it would be a lot of work to setting the different database, but I thing that it should be Ok. In real world there would not be a different data source per session but one per user with a count of session per user but as I said it is an over simplified example.

    0 讨论(0)
  • 2020-12-05 22:02

    The datasource used by a thread might change from time to time.
    Should pay attention to concurrency, applications might get concurrency issues in concurrent environment.
    thread-bound AbstractRoutingDataSource sample

    0 讨论(0)
提交回复
热议问题