2015-05-16 6 views
2

У меня сейчас 2 таблицы в базе данных:AbstractRoutingDataSource карта изменения во время выполнения

  1. пользователя
  2. user_database

В пользователя хранить логин, пароль, роль
В user_database я хранить базу данных драйвер, URL-адрес, пароль и пользователь. База данных диаграмм enter image description here

Я хочу, чтобы пользовательский логин на моей странице и следующее соединение, что он сделал, будет отправлен в базу данных пользователей. Почему мне нужно что? Я планирую карту популярной электронной коммерции и создаю приложение для Android, где пользовательский логин и видят данные хранилища, могут добавлять и просматривать заказы на продукцию.
Теперь время, чтобы пройти практику, мои знания в весенних технологиях малы, пожалуйста, объясните мне что-то, когда я делаю неправильно. Все примеры в Интернете для AbstractRoutingDataSource имеют файл данных декларации в файле персистентности или создают источник данных и начинают использовать AbstractRoutingDataSource. В моем проекте я не сейчас подключаюсь к пользователю, и мне нужно получить его из базы данных. Я попытался получить репозиторий и этот пример https://stackoverflow.com/a/17575648/3037869 но я получаю null на @Autowired в контроллере, я думаю, что соединение для хранилища равно null. Как установить соединение для этого репозитория и задать маршрут? Дефект этого метода, когда я добавляю пользователя, мне нужно перезагрузить сервер, чтобы обновить соединение.
Следующая попытка использовать то, что я сейчас использую класс User реализовать UserDetails после входа в систему я могу получить подключение пользователя от getPrincipal() и добавить к карте.

private void setDataSources() { 
    HashMap<Object, Object> targetDataSources = new HashMap<>(); 
    DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); 
    dataSourceBuilder.driverClassName("org.h2.Driver"); 
    dataSourceBuilder.url("jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"); 
    dataSourceBuilder.username("sa"); 
    dataSourceBuilder.password(""); 
    targetDataSources.put("auth", dataSourceBuilder.build()); 
    setDefaultTargetDataSource(dataSourceBuilder.build()); 
    if(SecurityContextHolder.getContext().getAuthentication()!=null) { 
     User user=(User) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
     System.out.println(user.getUserDatabase().getDriver()); 
     dataSourceBuilder.driverClassName(user.getUserDatabase().getDriver()); 
     dataSourceBuilder.url(user.getUserDatabase().getUrl()); 
     dataSourceBuilder.username("3450_Menadzer"); 
     dataSourceBuilder.password(user.getUserDatabase().getPassword()); 
     targetDataSources.put("user", dataSourceBuilder.build()); 
    } 
    setTargetDataSources(targetDataSources); 
    afterPropertiesSet(); //map is refresh when i add this 

} 

я запускаю этот метод на constuctor и determineCurrentLookupKey

protected Object determineCurrentLookupKey() { 
     if(SecurityContextHolder.getContext().getAuthentication()!=null) { 
      setDataSources(); 

      return "user"; 
     } 

     return "auth"; 
} 

Это работает, но когда я обновить 3-4 раза запросить базу данных пользователей я получаю

User 3450_Menadzer already has more than 'max_user_connections' active connections 

Настройки карты подключения Мануалов и не обновлять каждый метод. determineCurrentLookupKey run У меня нет этой проблемы. Я думаю, что мой метод не связывает соединение. Как я могу это очистить? Это возможно для лучшего способа маршрутизации соединения?

EDIT @SergeBallesta я изменить код из ваших примеров Это мой класс для отображения

@Component 
@Scope(value = "singleton") 
public class DataSourceMap { 
    private Map<Object,Object> dataSourceMap; 
    public DataSourceMap() 
    { 
     DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create(); 
     dataSourceBuilder.driverClassName("org.h2.Driver"); 
     dataSourceBuilder.url("jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE"); 
     dataSourceBuilder.username("sa"); 
     dataSourceBuilder.password(""); 
     dataSourceMap=new HashMap<Object,Object>(); 
     dataSourceMap.put("auth",dataSourceBuilder.build()); 
    } 
    public void addDataSource(String session,DataSource dataSource) 
    { 
     this.dataSourceMap.put(session,dataSource); 
    } 
    public Map<Object,Object> getDataSourceMap() 
    { 
     return dataSourceMap; 
    } 
    public void removeSource(String session) 
    { 
     dataSourceMap.remove(session); 
    } 
} 

Для AbstractRoutingDataSource я сделал некоторые изменения, я был добавить afterPropertiesSet() beacuse DataSource не обновляют. Я сделал некоторое обновление, и я не получаю ошибку, я думаю, что это работает. Мне нужно проверить это для большего количества баз данных в будущем

@Component 
public class CustomRoutingDataSource extends AbstractRoutingDataSource{ 
    @Autowired 
    DataSourceMap dataSources; 
    @Override 
    protected Object determineCurrentLookupKey() { 
     setDataSources(dataSources); 
     afterPropertiesSet(); 
     System.out.println("test"); 
     if(SecurityContextHolder.getContext().getAuthentication()!=null) { 
      HttpServletRequest request = ((ServletRequestAttributes) 
        RequestContextHolder.getRequestAttributes()).getRequest(); 
      return request.getSession().getId(); 
     } 

     return "auth"; 
    } 
    @Autowired 
    public void setDataSources(DataSourceMap dataSources) { 
     System.out.println("data adding"); 
     setTargetDataSources(dataSources.getDataSourceMap()); 
    } 

} 
+0

Вы можете поделиться своим кодом? У меня есть та же миссия после входа в систему пользователя, подключитесь к базовому db и получите источник данных, а затем CRUD для источника данных taht! Но я очень новичок в Spring Framework, я пробовал месяц, но никакого хорошего результата. Надеюсь, ваш код может мне помочь. – mikezang

ответ

2

Во-первых, для каждой пользовательской базы данных очень необычный дизайн. Если все эти базы данных заканчиваются с той же структурой, пожалуйста, не делайте этого в реальном приложении, а просто добавляйте user_id в свои таблицы и запросы.

Далее я нашел еще один (не полный) пример динамического AbstractRoutingDataSource в моем another answer.

И одна большая разница между моим кодом (остерегайтесь никогда не тестироваться), и ваш вопрос заключается в том, что я использую SessionListener для закрытия баз данных, чтобы избежать того, что количество открытых баз данных растет неопределенно.

Если вы к этому научиться Spring, вы можете попробовать следующий шаблон (снизу вверх описание):

  • сеанс область действия боба будет держать фактическое соединение с базой данных для пользователя, то соединение должно быть созданный по первому запросу (чтобы убедиться, что идентификатор пользователя присутствует в сеансе) и кэшируется для последующего использования. Метод уничтожения (автоматически назначаемый Spring при закрытии сессии) должен закрыть соединение.
  • AbstractRoutingDataSource, который будет введен с прокси-сервером в над держателем, и что будет просить фактический источник данных к держателю

Как и в другом ответе, если же пользователь может иметь множество одновременных сессий, вам может быть введен один синглтон в держателях сеансов, которые будут поддерживать фактические соединения с базой данных вместе с количеством активных сеансов. Таким образом, вы получите одно соединение для каждого пользователя, независимо от того, сколько одновременных сеансов он мог бы получить.

+0

Я смотрел ваш старый пример, я думаю, что это можно сделать, но вам нужно что-то объяснить. 'sessionDestroyed' метод находится в классе, что реализует' HttpSessionListener'? Где вы выходите 'AbstractRoutingDataSource', это compoment? Добавление базы данных соединений в контексте или классе сервлета? – seti

+0

@seti: Я немного изменил свой старый пример. Идея состоит в том, что map userId -> dataSource - это одноэлементный компонент, внедренный в реализацию AbstractRoutingDataSource, в HttpSessionListener, который закрывает источники данных и удаляет их с карты. И вы можете найти [здесь] (http://stackoverflow.com/a/182203/3545273) пример слушателя для успешного входа в систему, который мог бы хранить базу данных на карте –

+0

я редактирую свой вопрос, что моя логика помогла мне , Можете ли вы объяснить, что отличается от моего старого кода и нового (это работает). В Old Code я создавал набор и набор данных dataSource, в новом я получаю datasource из набора и обновления класса @ @ Autowired. – seti

Смежные вопросы