Я создаю приложение за Spring WebMVC UI с hibernate HPA. Каждый из отдельных частей головоломки прошел модульное тестирование, но у меня возникли проблемы с склеиванием приложения.Hibernate Entity Manager не может зачислить datasosurce в транзакции
Похоже, что стратегия транзакций Hibernate не позволяет Hibernate участвовать в транзакции.
Исследования до сих пор: Hibernate имеет стратегию транзакций jta, настроенную по умолчанию. Предполагается, что
Выполняется аннотация @Transactional на служебном уровне (я вижу его в журналах). Источник данных JDBC извлекается из диспетчера транзакций. Затем, в тот момент, когда диспетчер транзакций пытается подключить источник данных JDBC к транзакции, он неожиданно не может найти транзакцию. Я проследил в коде, и транзакции просто нет, когда Bitronix охотится за ней.
Стек для этой проблемы: водители
- Postgresql XA
- Bitronics 2.1.7
- Hibernate 4.3.7
- Spring 4.1.6
- Pivotal дц Продолжительность 3.0.2 .RELEASE/8.0.15.A.RELEASE
Вот код ошибки Метод:
@Service
public class ConfigPropertiesServiceImpl {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private ConfigPropertiesSDO configPropertiesSDO;
@Autowired
private ConfigPropertiesDAO configPropertiesDAO;
@Transactional
public PropertyValue fetchPropertyValue (String key)
{
return configPropertiesSDO.fetchProperty(key);
}
}
Лог показывает, что транзакция запускается:
DEBUG DispatcherServlet - DispatcherServlet with name 'dispatcher' processing GET request for [/myapp-war/ajax/cfgFind]
DEBUG RequestMappingHandlerMapping - Looking up handler method for path /ajax/cfgFind
DEBUG RequestMappingHandlerMapping - Returning handler method [public org.springframework.web.servlet.ModelAndView com.myApp.ui.security.controller.ConfigurationLayoutController.getCfgFind()]
DEBUG DefaultListableBeanFactory - Returning cached instance of singleton bean 'configurationLayoutController'
DEBUG DispatcherServlet - Last-Modified value for [/myapp-war/ajax/cfgFind] is: -1
DEBUG JtaTransactionManager - Creating new transaction with name [com.myApp.svc.config.ConfigPropertiesServiceImpl.fetchPropertyValue]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
DEBUG BitronixTransactionManager - beginning a new transaction
DEBUG BitronixTransactionManager - dumping 0 transaction context(s)
DEBUG BitronixTransaction - creating new transaction with GTRID [3139322E3136382E302E35300000000005692D6D00000002]
DEBUG BitronixTransactionManager - creating new thread context
DEBUG BitronixTransactionManager - changing current thread context to a ThreadContext with transaction null, default timeout 60s
DEBUG ThreadContext - assigning <a Bitronix Transaction with GTRID [3139322E3136382E302E35300000000005692D6D00000002], status=NO_TRANSACTION, 0 resource(s) enlisted (started null)> to <a ThreadContext with transaction null, default timeout 60s>
DEBUG BitronixTransaction - changing transaction status to ACTIVE
DEBUG TransactionLogAppender - between 14848 and 14909, writing a Bitronix TransactionLogRecord with status=ACTIVE, recordLength=53, headerLength=28, time=90778990, sequenceNumber=4, crc32=-880986447, gtrid=3139322E3136382E302E35300000000005692D6D00000002, uniqueNames=
DEBUG TransactionLogAppender - disk journal appender now at position 14909
DEBUG BitronixTransaction - transaction status is changing from NO_TRANSACTION to ACTIVE - executing 0 listener(s)
DEBUG TaskScheduler - scheduling transaction timeout task on a Bitronix Transaction with GTRID [3139322E3136382E302E35300000000005692D6D00000002], status=ACTIVE, 0 resource(s) enlisted (started Thu Jan 01 19:12:58 CST 1970) for Thu Jan 01 19:13:58 CST 1970
DEBUG TaskScheduler - removing task by a Bitronix Transaction with GTRID [3139322E3136382E302E35300000000005692D6D00000002], status=ACTIVE, 0 resource(s) enlisted (started Thu Jan 01 19:12:58 CST 1970)
DEBUG TaskScheduler - scheduled a TransactionTimeoutTask on a Bitronix Transaction with GTRID [3139322E3136382E302E35300000000005692D6D00000002], status=ACTIVE, 0 resource(s) enlisted (started Thu Jan 01 19:12:58 CST 1970) scheduled for Thu Jan 01 19:13:58 CST 1970, total task(s) queued: 3
DEBUG BitronixTransactionManager - begun new transaction at Thu Jan 01 19:12:58 CST 1970
Log показывает, что оператор не смог присоединиться к транзакции:
DEBUG EntityManagerFactoryUtils - Opening JPA EntityManager
TRACE SessionFactoryImpl$SessionBuilderImpl - Opening Hibernate Session. tenant=null, [email protected]
TRACE SessionImpl - Opened session at timestamp: 14400807842
DEBUG TransactionCoordinatorImpl - Skipping JTA sync registration due to auto join checking
TRACE TransactionCoordinatorImpl - registered JTA platform says we cannot currently register synchronization; skipping
DEBUG AbstractEntityManagerImpl - Looking for a JTA transaction to join
DEBUG AbstractEntityManagerImpl - Unable to join JTA transaction
DEBUG TransactionCoordinatorImpl - Skipping JTA sync registration due to auto join checking
Вот моя инициализация Spring Контекст:
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) throws ServletException {
Logger logger = LoggerFactory.getLogger(this.getClass());
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(DatabaseConfig.class);
rootContext.refresh();
// Manage the lifecycle of the root appcontext
container.addListener(new ContextLoaderListener(rootContext));
container.setInitParameter("defaultHtmlEscape", "true");
AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
mvcContext.register(ViewConfig.class);
mvcContext.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(mvcContext));
servlet.setLoadOnStartup(1);
Set<String> mappingConflicts = servlet.addMapping("/");
if (!mappingConflicts.isEmpty()) {
for (String s : mappingConflicts) {
logger.error("Mapping conflict: " + s);
}
throw new IllegalStateException(
"'appServlet' cannot be mapped to '/' under Tomcat versions <= 7.0.14");
}
}
}
... и класс конфигурации базы данных, где настроено transactioning ...
@EnableTransactionManagement
@ComponentScan({ "com.myApp.svc.*","com.myApp.core.*","com.myApp.ui.*" })
@Configuration
public class DatabaseConfig {
@Bean(destroyMethod="shutdown")
public BitronixTransactionManager bitronixTransactionManager() {
btmConfig();
return new BitronixTransactionManager();
}
@Bean
public JtaTransactionManager transactionManager() {
JtaTransactionManager mgr = new JtaTransactionManager();
mgr.setTransactionManager(bitronixTransactionManager());
mgr.setUserTransaction(bitronixTransactionManager());
mgr.afterPropertiesSet();
return mgr;
}
@Bean
public TransactionTemplate transactionTemplate()
{
return new TransactionTemplate (transactionManager());
}
@Bean(initMethod = "init", destroyMethod = "close")
public DataSource dataSource() {
PoolingDataSource dataSourceInstance = new PoolingDataSource();
dataSourceInstance.set ...();
dataSourceInstance.init();
return dataSourceInstance;
}
@Bean
public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean()
throws IOException {
// The bean isn't created yet, but we need some of its functions
// This instance will be released as soon as the method goes out of
// scope
BitronixTransactionManager tm = bitronixTransactionManager();
PrivateDatastoreServiceImpl pds = new PrivateDatastoreServiceImpl();
pds.setPrivateDatastorePropertiesFile(privateDatastorePropertiesFile());
pds.init();
LocalContainerEntityManagerFactoryBean emf = null;
PrivateDatastoreConfigurationModel model = pds
.retrieveRawJdbcParameters();
Properties props = new Properties();
props.setProperty(HIBERNATE_DIALECT,
pds.getHibernateStrategy(model.getDbType()));
props.setProperty(HIBERNATE_DDL_AUTO, "false");
props.setProperty(HIBERNATE_SHOW_SQL, "false");
props.setProperty(HIBERNATE_FORMAT_SQL, "false");
props.setProperty("hibernate.current_session_context_class",
"jta");
props.setProperty("hibernate.transaction.jta.platform",
org.hibernate.engine.transaction.jta.platform.internal.BitronixJtaPlatform.class.getName());
props.setProperty("hibernate.jndi.class",
bitronix.tm.jndi.BitronixInitialContextFactory.class.getName());
props.setProperty("jta.UserTransaction",
"BTMUserTransaction");
emf = new LocalContainerEntityManagerFactoryBean();
emf.setJtaDataSource(securityDataSource());
emf.setJpaVendorAdapter(jpaVendorAdapter());
emf.setPersistenceUnitName("myAppPersistence");
emf.setPackagesToScan("com.myApp.*");
emf.setJpaProperties(props);
return emf;
}
}
Изменение: добавлены детали программного стека