2

Я пытаюсь изменить спящий аннотацию только с одним источником данных, чтобы иметь столько, сколько сохраняется в базе данных. Для того, чтобы пользователь имеет назначенную связь, и добавить новый тип соединения только с перезагрузкой сервера (избегая .war перекомпиляции)Spring 3.1.3 + Конфигурация спящего режима с аннотациями и с помощью (Dynamic) AbstractRoutingDataSource

сервер загружает первый SecurityHibernateConfiguration без проблем:

@Configuration 
@EnableTransactionManagement 
public class SecurityHibernateConfiguration { 

    @Autowired 
    public Parameters parameters; 

    @Bean 
    DataSource datasourcesecurity() { 

     org.apache.commons.dbcp.BasicDataSource dataSource = new org.apache.commons.dbcp.BasicDataSource(); 

     dataSource.setDriverClassName(parameters.getDriverClassName()); 
     dataSource.setUrl(parameters.getUrlSecurity()); 
     dataSource.setUsername(parameters.getUserNameSecurity()); 
     dataSource.setPassword(parameters.getPasswordSecurity()); 

     return dataSource; 
    } 

    @Bean 
    public SessionFactory securitySessionFactory() throws Exception { 
     Properties props = new Properties(); 
     props.put("hibernate.dialect", parameters.getHibernateDialect()); 
     props.put("hibernate.format_sql", parameters.getFormatSql()); 

     AnnotationSessionFactoryBean bean = new AnnotationSessionFactoryBean(); 
     bean.setAnnotatedClasses(new Class[] { 
        Login.class,  
        LoginRol.class, 
        Aplicacio.class, 
        Rol.class, 
        RolObjecte.class, 
        Objecte.class, 
        RolObjecteAcl.class, 
        Acl.class, 
        Tema.class, 
        Connexio.class 
     }); 
     bean.setHibernateProperties(props); 
     bean.setDataSource(datasourcesecurity()); 
     bean.setSchemaUpdate(false); 
     bean.afterPropertiesSet(); 

     SessionFactory factory = bean.getObject(); 
     return factory; 
    } 

    @Bean 
    public HibernateTransactionManager securitytransactionManager() throws Exception { 
     return new HibernateTransactionManager(securitySessionFactory()); 
    } 

} 

Тогда Я создал маршрутизации DataSource вроде этого:

public class RoutingDataSource extends AbstractRoutingDataSource { 
    @Autowired 
    private SecurityManager securitymanager; 

    private Map<Long, DataSource> targetDataSources = new HashMap<Long, DataSource>(); 

    @SuppressWarnings({ "unchecked", "rawtypes" }) 
    public void setTargetDataSources(Map targetDataSources) { 
     this.targetDataSources = (Map<Long, DataSource>) targetDataSources; 
    } 

    @Override 
    protected DataSource determineTargetDataSource() { 
     Long lookupKey = determineCurrentLookupKey(); 
     DataSource dataSource = this.targetDataSources.get(lookupKey); 
     if (dataSource == null) { 
      throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]"); 
     } 
     return dataSource; 
    } 

    @Override 
    protected Long determineCurrentLookupKey() { 
     try { 
      String username = securitymanager.getUserName(); 
      Login login = null; 
      if (!StringUtils.isEmpty(username)) { 
       login = securitymanager.getLogin(username); 
      } 
      return login == null ? 1L : login.getConnexio() == null ? 1L : login.getConnexio().getId(); 
     } catch (Exception e) { 
      return 1L; 
     } 
    } 

    @Override 
    public void afterPropertiesSet() { 
     // do nothing 
     // overridden to avoid datasource validation error by Spring 
    } 

} 

Используется в HibernateConfiguration так:

@Configuration 
@EnableTransactionManagement 
public class HibernateConfiguration { 
    @Autowired 
    private SecurityManager securitymanager; 
    @Autowired 
    private Parameters parameters; 

    @Bean 
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() { 

     LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean(); 

     lcemfb.setDataSource(this.dataSource()); 
     lcemfb.setPackagesToScan(new String[] { "cat.itec.pgm.persistence" }); 
     lcemfb.setPersistenceUnitName("pgmdb"); 

     HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter(); 
     va.setShowSql(true); 
     lcemfb.setJpaVendorAdapter(va); 

     Properties ps = new Properties(); 
     ps.put("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect"); 
     ps.put("hibernate.format_sql", "true"); 
     ps.put("hibernate.show_sql", "true"); 
     lcemfb.setJpaProperties(ps); 

     lcemfb.afterPropertiesSet(); 
     return lcemfb; 
    } 

    @Bean 
    public DataSource dataSource() { 

     RoutingDataSource rds = new RoutingDataSource(); 
     Map<Long, DataSource> targetDataSources = new HashMap<Long, DataSource>(); 
     List<Connexio> connexioLogins = new ArrayList<Connexio>(); 
     try { 
      connexioLogins = securitymanager.getConnexioLogins(); 
     } catch (Exception e) { 
      System.out.println("Cannot Load List Of Connections"); 
     } 
     for (Connexio c : connexioLogins) { 
      DriverManagerDataSource ds = new DriverManagerDataSource(); 
      ds.setDriverClassName(parameters.getDriverClassName()); 
      ds.setUrl(generateUrlConnection(c)); 
      ds.setUsername(c.getDbUsername()); 
      ds.setPassword(c.getDbPassword()); 
      targetDataSources.put(c.getId(), ds); 
     } 
     rds.setTargetDataSources(targetDataSources); 
     return rds; 
    } 

    @Bean 
    public PlatformTransactionManager transactionManager() { 
     JpaTransactionManager tm = new JpaTransactionManager(); 
     tm.setEntityManagerFactory(this.entityManagerFactoryBean().getObject()); 
     return tm; 
    } 

    @Bean 
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() { 
     return new PersistenceExceptionTranslationPostProcessor(); 
    } 

    private String generateUrlConnection(Connexio c) { 
     StringBuilder sb = new StringBuilder(); 
     sb.append("jdbc:oracle:thin:@"); 
     sb.append(c.getServer()); 
     sb.append(":"); 
     sb.append(c.getPort()); 
     sb.append(":"); 
     sb.append(c.getSid()); 
     return sb.toString(); 
    } 
} 

Дело в том, что, когда я начинаю сервера он бросает:

Caused by: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here 
    at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63) 
    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:685) 
    at cat.itec.security.persistence.dao.login.impl.LoginDaoImpl.getConnexioLogins(LoginDaoImpl.java:37) 

Я не знаю, как если ошибка сделать RoutingDataSource получить каждый «Connexio», или он не настроен правильно.

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

Заранее спасибо.

EDIT (неудобные, см edit2):

Изменение чуток две противоречивых точек базов данных, как это:

@Bean 
public DataSource dataSource() { 
    RoutingDataSource rds = new RoutingDataSource(); 
    Map<Long,DataSource> targetDataSources = new HashMap<Long,DataSource>(); 
    Connexio c = new Connexio(); 
    c.setDbPassword("XXXXXXXXX"); 
    c.setDbUsername("XXX"); 
    c.setId(1L); 
    c.setPort("XXXXXXX"); 
    c.setServer("XXXXXXXX"); 
    c.setSid("XXXX"); 
    DriverManagerDataSource ds = new DriverManagerDataSource(); 
    ds.setDriverClassName(parameters.getDriverClassName()); 
    ds.setUrl(generateUrlConnection(c)); 
    ds.setUsername(c.getDbUsername()); 
    ds.setPassword(c.getDbPassword()); 
    targetDataSources.put(c.getId(), ds); 
    rds.setTargetDataSources(targetDataSources); 

    return rds; 
} 

И

@Override 
protected Long determineCurrentLookupKey() { 
    return 1L; 
} 

делает приложение работает, как это было до этого. Таким образом, кажется, проблема с доступом к БД при запуске сервера. Есть идеи?

EDIT2:

изменил код добавлен в первый срок, чтобы отправить полный рабочий один в качестве примера.

ответ

1

Я обнаружил, что проблема была в моем Dao Layer. В запуске сервера это не представляется возможным получить доступ к текущей сессии, так что я сделал что-то вроде:

try { 
    Session session = securitySessionFactory.getCurrentSession(); 
    Criteria crit = session.createCriteria(clazz); 
    return (List<T>) crit.list(); 
} catch (Exception e) { 
    Session session = securitySessionFactory.openSession(); 
    Transaction transaction = session.beginTransaction(); 
    transaction.begin(); 
    Criteria crit = session.createCriteria(clazz); 
    List<T> list = (List<T>) crit.list(); 
    session.disconnect(); 
    session.close(); 
    return list; 
} 

С этим я могу заполнить RoutingDataSources правильно и сделать количество источников данных немного динамики (с заполнением новой запись в БД и простой перезапуск сервера).

Учтите, что ленивые сопоставления будут отключены, поэтому может быть полезно оценить, что нужно будет настроить для FetchType.Eager (с помощью FetchMode.Subselect, если для его инициализации требуется более 1 мешка)

Я собираюсь отредактировать вопрос, чтобы оставить это в качестве примера для настройки маршрутизации «динамических» источников данных для Spring 3.1.3 с аннотациями.

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