title: Change database schema during runtime based on logged in user
body: <p>I've read many questions and answers about dynamic datasource routing and have implemented a solution using <code>AbstractRoutingDataSource</code> and another(see below). That's fine, but requires hardcoded properties for all datasources. As the number of users using the application increases, this isn't a suitable way of routing any more. Also it would require to add an entry to the properties every time a new user registers. The situation is as follows</p>
  
  <ul>
  <li>1 database server</li>
  <li>many schemas on that server, every user has their own schema.</li>
  <li>I only need to change the schema name during runtime</li>
  <li>schema name is retainable by logged in user</li>
  </ul>
  
  <p>I'm using <code>spring boot 1.4.0</code> together with <code>hibernate 5.1</code> and <code>spring data jpa</code></p>
  
  <p>I can't find a way to change the schema completely dynamically. Does someone know how to do it in spring?</p>
  
  <p><strong>EDIT:</strong></p>
  
  <p>Thanks to @Johannes Leimer's answer, I got a working implemantation. </p>
  
  <p>Here's the code:</p>
  
  <p><em>User Provider</em>:</p>
  
  <pre><code>@Component
  public class UserDetailsProvider {
      @Bean
      @Scope("prototype")
      public CustomUserDetails customUserDetails() {
          return (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
      }
  }
  </code></pre>
  
  <p><em>UserSchemaAwareRoutingDatasource</em>:</p>
  
  <pre><code>public class UserSchemaAwareRoutingDataSource extends AbstractDataSource {
  @Inject
  Provider&lt;CustomUserDetails&gt; customUserDetails;
  
  @Inject
  Environment env;
  private LoadingCache&lt;String, DataSource&gt; dataSources = createCache();
  
  @Override
  public Connection getConnection() throws SQLException {
      try {
          return determineTargetDataSource().getConnection();
      } catch (ExecutionException e){
          e.printStackTrace();
  
          return null;
      }
  }
  
  @Override
  public Connection getConnection(String username, String password) throws SQLException {
      System.out.println("getConnection" + username);
      System.out.println("getConnection2" + password);
      try {
          return determineTargetDataSource().getConnection(username, password);
      } catch (ExecutionException e) {
          e.printStackTrace();
          return null;
      }
  }
  
  private DataSource determineTargetDataSource() throws SQLException, ExecutionException {
      try {
          String schema = customUserDetails.get().getUserDatabase();
          return dataSources.get(schema);
      } catch (NullPointerException e) {
          e.printStackTrace();
  
          return dataSources.get("fooooo");
      }
  
  }
  </code></pre>