Spring 3.1.3+;带注释和(动态)AbstractRoutingDataSource的Hibernate配置

Spring 3.1.3+;带注释和(动态)AbstractRoutingDataSource的Hibernate配置,hibernate,spring-mvc,spring-security,spring-3,spring-annotations,Hibernate,Spring Mvc,Spring Security,Spring 3,Spring Annotations,我正在尝试更改一个只包含一个数据源的hibernate注释,以便在数据库中保存尽可能多的数据源。为了让用户拥有其分配的连接,并只需重新启动服务器即可添加新类型的连接(避免.war重新编译) 服务器首先加载SecurityHibernateConfiguration,没有任何问题: @Configuration @EnableTransactionManagement public class SecurityHibernateConfiguration { @Autowired

我正在尝试更改一个只包含一个数据源的hibernate注释,以便在数据库中保存尽可能多的数据源。为了让用户拥有其分配的连接,并只需重新启动服务器即可添加新类型的连接(避免.war重新编译)

服务器首先加载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());
    }

}
然后我创建了一个路由数据源,如下所示:

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
    }

}
@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();
    }
}
@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;
}
我不知道错误是如何使RoutingDataSource获取每个“Connexio”,还是没有正确配置

如有任何帮助或意见,将不胜感激。(为了更好地理解而需要的任何其他代码都将尽快发布)

提前谢谢

编辑(无用,请参见编辑2):

稍微更改两个冲突的数据库点,如下所示:

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
    }

}
@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();
    }
}
@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;
}
使应用程序与此更改之前一样工作。因此,在服务器启动时访问数据库似乎是一个问题。有什么想法吗

EDIT2:


更改了第一学期添加的代码,以发布完整的工作代码为例。

我发现问题出在我的Dao层。在服务器启动时,无法访问当前会话,因此我执行了如下操作:

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;
}
试试看{
会话会话=securitySessionFactory.getCurrentSession();
Criteria crit=session.createCriteria(clazz);
return(List)crit.List();
}捕获(例外e){
Session Session=securitySessionFactory.openSession();
事务=会话。beginTransaction();
transaction.begin();
Criteria crit=session.createCriteria(clazz);
List=(List)crit.List();
session.disconnect();
session.close();
退货清单;
}
有了它,我可以正确地填充RoutingDataSources,并使数据源的数量有点动态(通过在DB中填充一个新条目和简单的服务器重启)

考虑到惰性映射将被禁用,因此评估需要设置为FetchType.Eager的内容可能会很有用(使用FetchMode.Subselect,如果需要使用它初始化多个包)

我将对这个问题进行编辑,以便将其作为配置Spring3.1.3路由“动态”数据源和注释的示例