Spring 3.1.3+;带注释和(动态)AbstractRoutingDataSource的Hibernate配置
我正在尝试更改一个只包含一个数据源的hibernate注释,以便在数据库中保存尽可能多的数据源。为了让用户拥有其分配的连接,并只需重新启动服务器即可添加新类型的连接(避免.war重新编译) 服务器首先加载SecurityHibernateConfiguration,没有任何问题: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
@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路由“动态”数据源和注释的示例