【问题标题】:Spring 3.1.3 + Hibernate Configuration with annotations and with (Dynamic) AbstractRoutingDataSource带有注释和(动态)AbstractRoutingDataSource 的 Spring 3.1.3 + Hibernate 配置
【发布时间】:2015-04-30 05:26:14
【问题描述】:

我正在尝试仅使用一个数据源更改注释休眠状态,以使尽可能多的数据源保存在数据库中。为了使用户拥有分配的连接,并添加新类型的连接,只需重新启动服务器(避免 .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
    }

}

在 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”,还是没有正确配置。

任何帮助或评论将不胜感激。 (我会尽快发布任何其他需要更好理解的代码)。

提前致谢。

编辑(无用,参见 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:

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

【问题讨论】:

    标签: hibernate spring-mvc spring-security spring-3 spring-annotations


    【解决方案1】:

    我发现问题出在我的道层。在服务器启动时无法访问当前会话,所以我做了类似的事情:

    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 的内容可能很有用(如果需要用它初始化 1 个以上的包,则使用 FetchMode.Subselect)

    我将编辑该问题,以便将此作为示例,为 Spring 3.1.3 配置路由“动态”数据源并使用注释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-25
      • 1970-01-01
      • 2010-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-03
      相关资源
      最近更新 更多