Spring 3.1.3 +使用注释和动态AbstractRoutingDataSource的Hibernate配置 [英] Spring 3.1.3 + Hibernate Configuration with annotations and with (Dynamic) AbstractRoutingDataSource

查看:119
本文介绍了Spring 3.1.3 +使用注释和动态AbstractRoutingDataSource的Hibernate配置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图只用一个数据源来修改一个注释hibernate,以便保存在一个数据库中。为了让用户拥有其分配的连接,并添加新类型的连接,只需要重新启动服务器(避免.war重新编译)

服务器首先加载一个SecurityHibernateConfiguration Without任何问题:

  @Configuration 
@EnableTransactionManagement
公共类SecurityHibernateConfiguration {

@Autowired
public参数参数;

@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());

返回dataSource;


$Be
public SessionFactory securitySessionFactory()抛出异常{
属性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(道具);
bean.setDataSource(datasourcesecurity());
bean.setSchemaUpdate(false);
bean.afterPropertiesSet();

SessionFactory factory = bean.getObject();
退货工厂;



public HibernateTransactionManager securitytransactionManager()抛出异常{
return new HibernateTransactionManager(securitySessionFactory());
}

}

然后我创建了一个Routing DataSource这个:

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

私人地图< 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(无法确定目标数据源的查找键[+ lookupKey +]);
}
返回dataSource;
}

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

@Override
public void afterPropertiesSet(){
// do nothing
//覆盖以避免数据源验证错误by Spring
}

}

用于HibernateConfiguration这个:

  @Configuration 
@EnableTransactionManagement
公共类HibernateConfiguration {
@Autowired
私人SecurityManager安全管理者;
@Autowired
私有参数参数;

@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);

属性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();
返回lcemfb;


$Be
public DataSource dataSource(){

RoutingDataSource rds = new RoutingDataSource();
Map< Long,DataSource> targetDataSources = new HashMap< Long,DataSource>();
列表< Connexio> connexioLogins = new ArrayList< Connexio>();
尝试{
connexioLogins = securitymanager.getConnexioLogins();
} catch(Exception e){
System.out.println(无法加载连接列表);

(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);
返回rds;


$Be
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();


$ / code>

关键是当我启动服务器时它会抛出a:

 引起:org.hibernate.HibernateException:没有Hibernate Session绑定到线程,并且配置不允许创建非 - 事务一在这里
在org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
在org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:685)
at cat.itec.security.persistence.dao.login.impl.LoginDaoImpl.getConnexioLogins(LoginDaoImpl.java:37)

我不知道如果错误是让RoutingDataSource获取每个Connexio,或者它没有正确配置,那该怎么办。



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



预先感谢。



编辑(Unuseful,请参阅EDIT2):

更改一下这两个有冲突的数据库点:

  @Bean 
public DataSource dataSource(){
RoutingDataSource rds = new RoutingDataSource();
Map< Long,DataSource> targetDataSources = new HashMap< Long,DataSource>();
Connexio c =新的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:



将第一项中添加的代码更改为以完整的工作人员为例。

解决方案

我发现问题出现在我的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);
列表< T> list =(List< T>)crit.list();
session.disconnect();
session.close();
返回列表;
}

通过这个,我可以正确填充RoutingDataSources并使数据源的数量稍微增加一点动态的(填充数据库中的新条目和简单的服务器重新启动)。

考虑到懒惰映射将被禁用,因此评估什么是有用的将需要设置为FetchType.Eager(使用FetchMode.Subselect如果需要使用它初始化超过1个包)



我要编辑问题,以此作为配置Spring 3.1.3路由动态数据源的注释示例。


I'm trying to change an annotation hibernate with only one datasource, to have as many as are saved in a database. In order to make an user have its assigned connection, and add new type of connections with only a server restart (avoiding .war recompile)

The server first loads a SecurityHibernateConfiguration Without any Problem:

@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());
    }

}

Then I created a Routing DataSource like this:

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
    }

}

Used in the HibernateConfiguration like this:

@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();
    }
}

The point is that when I start the server it throws a:

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)

I don't know how if the error is to make the RoutingDataSource get every "Connexio", or it is not properly configured.

Any help or comment will be appreciated. (any other piece of code needed for better understanding will be posted as soon as I can).

Thanks in advance.

EDIT (Unuseful, See EDIT2):

Changing a bit the two conflictive Database points like this:

@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;
}

And

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

Makes the app work like it was before this changes. So it seems a problem to acces DB in server startup. Any Idea?

EDIT2:

Changed the code added in first term to post the full working one as an example.

解决方案

I found that the problem was in my Dao Layer. In server startup It is not possible to access the current session, so I've done something like:

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;
}

With this I can fill the RoutingDataSources properly and make the number of datasources a little dynamic (with filling a new entry in the DB and a simple server restart).

Take into account that lazy mappings will be disabled, so it may be useful to evaluate what will be need to be set to FetchType.Eager (with FetchMode.Subselect if more than 1 bag is needed to be initialized with it)

I'm going to edit the question in order to leave this as an example for configuring routing "dynamic" datasources for Spring 3.1.3 with annotations.

这篇关于Spring 3.1.3 +使用注释和动态AbstractRoutingDataSource的Hibernate配置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆