我有一个带有Hibernate的Spring MVC项目(Spring 4.2.2 - Hibernate 4.3.6)。我想将两个数据源(两个不同的postgresql数据库)连接到它,所以我使用atomikos作为JTA的实现。我的配置全部都是注释,因此配置文件是这样的:
@Configuration
@PropertySource(value = { "classpath:hibernate.properties" })
public class HibernateConfig {
@Autowired
private Environment environment;
// First DB connection
@Primary
@Bean(name = "sessionFactory")
@DependsOn("setMyAtomikosSystemProps")
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[] { "org.spring.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean(name = "statsSessionFactory")
@DependsOn("setMyAtomikosSystemProps")
public LocalSessionFactoryBean statsSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(statsDataSource());
sessionFactory.setPackagesToScan(new String[] { "org.spring.stats.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Primary
@Bean(name = "dataSource")
public DataSource dataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
ds.setUniqueResourceName("first");
ds.setXaDataSourceClassName("org.postgresql.xa.PGXADataSource");
ds.setXaProperties(dataSourceProperties("first"));
ds.setMinPoolSize(5);
ds.setMaxPoolSize(75);
ds.setMaxIdleTime(60 * 15);
return ds;
}
@Bean(name = "statsDataSource")
public DataSource statsDataSource() {
AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
ds.setUniqueResourceName("second");
ds.setXaDataSourceClassName("org.postgresql.xa.PGXADataSource");
ds.setXaProperties(dataSourceProperties("second"));
ds.setMinPoolSize(5);
ds.setMaxPoolSize(75);
ds.setMaxIdleTime(60 * 15);
return ds;
}
private Properties dataSourceProperties(String database) {
Properties p = new Properties();
p.setProperty("user", environment.getRequiredProperty("hibernate.connection.username"));
p.setProperty("password", environment.getRequiredProperty("hibernate.connection.password"));
p.setProperty("serverName", environment.getRequiredProperty("hibernate.connection.url"))
p.setProperty("portNumber", environment.getRequiredProperty("hibernate.connection.port"))
p.setProperty("databaseName", database);
return p;
}
@Bean(name = "userTransactionService")
@DependsOn("setMyAtomikosSystemProps")
public UserTransactionService userTransactionService() {
UserTransactionServiceImp uts = new UserTransactionServiceImp();
Properties prop = new Properties();
prop.setProperty("com.atomikos.icatch.service", "com.atomikos.icatch.standalone.UserTransactionServiceFactory");
uts.init(prop);
return uts;
}
@Bean
@DependsOn("userTransactionService")
public UserTransactionManager AtomikosTransactionManager() {
UserTransactionManager utm = new UserTransactionManager();
utm.setForceShutdown(true);
utm.setStartupTransactionService(false);
return utm;
}
@Bean
@DependsOn("userTransactionService")
public UserTransaction AtomikosUserTransaction() {
UserTransactionImp ut = new UserTransactionImp();
try {
ut.setTransactionTimeout(300);
} catch (SystemException e) {
e.printStackTrace();
}
return ut;
}
@Bean
@DependsOn("userTransactionService")
public PlatformTransactionManager JtaTransactionManager() {
JtaTransactionManager jtaTM = new JtaTransactionManager();
jtaTM.setTransactionManager(AtomikosTransactionManager());
jtaTM.setUserTransaction(AtomikosUserTransaction());
jtaTM.setAllowCustomIsolationLevels(true);
return jtaTM;
}
// SharedProperties
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
// JTA
properties.put("hibernate.current_session_context_class", "jta");
properties.put("hibernate.transaction.factory_class", "org.hibernate.transaction.JTATransactionFactory");
properties.put("hibernate.transaction.jta.platform", "com.atomikos.icatch.jta.hibernate4.AtomikosPlatform");
return properties;
}
@Bean
public MethodInvokingFactoryBean setMyAtomikosSystemProps() {
MethodInvokingFactoryBean mifb = new MethodInvokingFactoryBean();
Properties p = new Properties();
p.setProperty("com.atomikos.icatch.hide_init_file_path", "true");
p.setProperty("com.atomikos.icatch.no_file", "true");
mifb.setArguments(new Object[] { p });
mifb.setTargetObject(java.lang.System.getProperties());
mifb.setTargetMethod("putAll");
return mifb;
}
}
如果事务只涉及一个数据源,则此配置有效,但如果我创建了一个想要从两者获取数据的服务,则会收到此错误:
GRAVE: Servlet.service() for servlet [dispatcher] in context with path [/api] threw exception [Request processing failed; nested exception is org.springframework.transaction.UnexpectedRollbackException: JTA transaction unexpectedly rolled back (maybe due to a timeout); nested exception is javax.transaction.RollbackException: Prepare: NO vote] with root cause
com.atomikos.icatch.RollbackException: Prepare: NO vote
at com.atomikos.icatch.imp.ActiveStateHandler.prepare(ActiveStateHandler.java:202)
at com.atomikos.icatch.imp.CoordinatorImp.prepare(CoordinatorImp.java:523)
at com.atomikos.icatch.imp.CoordinatorImp.terminate(CoordinatorImp.java:687)
at com.atomikos.icatch.imp.CompositeTransactionImp.commit(CompositeTransactionImp.java:282)
at com.atomikos.icatch.jta.TransactionImp.commit(TransactionImp.java:172)
at com.atomikos.icatch.jta.TransactionManagerImp.commit(TransactionManagerImp.java:414)
at com.atomikos.icatch.jta.UserTransactionImp.commit(UserTransactionImp.java:86)
at org.springframework.transaction.jta.JtaTransactionManager.doCommit(JtaTransactionManager.java:1021)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:485)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:291)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy91.findById(Unknown Source)
但这不是一个超时问题,因为响应只需几秒钟。
我还从postgres收到了很长的错误列表。我" m"过滤"错误:
WARN XAResourceTransaction - XA resource 'second': rollback for XID '3139322E3136382E322E322E746D313438373639323737373736333030303032:3139322E3136382E322E322E746D32' raised -4: the supplied XID is invalid for this XA resource
org.postgresql.xa.PGXAException: Errore durante il «rollback» di una transazione preparata
(这个是意大利语,它说"错误期间"回滚"准备好的交易)
Caused by: org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled
Suggerimento: Set max_prepared_transactions to a nonzero value.
Caused by: org.postgresql.util.PSQLException: ERROR: prepared transactions are disabled
Suggerimento: Set max_prepared_transactions to a nonzero value.
ERROR XAResourceTransaction - XA resource 'first': prepare for XID '3139322E3136382E322E322E746D313438373639323737373736333030303032:3139322E3136382E322E322E746D33' raised -3: the XA resource detected an internal error
org.postgresql.xa.PGXAException: Error in preparing transaction
所以它似乎需要准备好的交易,但因为只有包含它们的交易?并强制启用它们?我可以避免这个吗?
答案 0 :(得分:0)
您必须编辑postgresql.conf文件,找到max_prepared_transactions并取消注释它(删除行开头的#)并设置合理的值。 请参阅:https://www.postgresql.org/docs/9.4/static/runtime-config-resource.html