Фабио помог направить меня в правильном направлении. Я обнаружил, что декларативные транзакции, использующие @Transactional, не работают в GAE, потому что Spring сканирует org.hibernate.impl.SessionFactoryImpl, который вызывает загрузку классов javax.naming, которых нет в белом списке GAE. У меня была та же проблема, переходящая на объявления на основе XML. Поэтому я в конечном итоге использовал программное управление транзакциями с использованием объектов TransactionTemplate, и это, похоже, работает.
РЕДАКТИРОВАТЬ: Добавлен пример кода
Из моей весенней конфигурации я удалил <tx:annotation-driven/>
, чтобы отключить @Transactional, и заменил его на
<bean id="defaultTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager"><ref local="transactionManager"/></property>
</bean>
Если вы используете семантику нескольких транзакций, например, PROPAGATION_REQUIRED и PROPAGATION_SUPPORTS, вам нужно будет создать дополнительные bean-компоненты, по одному для каждого сценария, например
<bean id="supportingTransactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="propagationBehaviorName" value="PROPAGATION_SUPPORTS"/>
<property name="transactionManager"><ref local="transactionManager"/></property>
</bean>
Я оставил свои исходные классы обслуживания с нотацией @Transactional. Это не имеет значения, поскольку <tx:annotation-driven/>
был удален, и я мог бы когда-нибудь переключиться обратно, если проблема будет решена. Вместо этого я поместил их в субтитры для использования TransactionTemplate
public class GAEUserService extends UserService {
@Autowired
private TransactionTemplate defaultTransactionTemplate;
@Override
public void update(final User user) {
defaultTransactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
UserService.super.update(user);
}
});
}
}
Единственным недостатком, который я обнаружил, было то, что мне пришлось преобразовать проверенные исключения, сгенерированные моими методами обслуживания, в непроверенные исключения, потому что проверенные исключения не соответствуют сигнатуре doInTransactionWithoutResult