Как настроить TransactionManager программно

У меня есть приложение, основанное на Spring MVC. Мой напарник (кстати его здесь нет) настроил его программно и вроде все работает, кроме TransactionManager. Я никогда не настраивал такое веб-приложение Spring, и я понятия не имею, что делать, а также не могу найти никакой документации о том, как настроить такое веб-приложение.

Я просто покажу вам «AppInitializer» и «EntityManagerConfig».

Инициализатор приложения:

public class AppInitializer implements WebApplicationInitializer {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    AnnotationConfigWebApplicationContext context;
    ServletRegistration.Dynamic dispatcherServletRegistration;
    FilterRegistration.Dynamic encodingFilterRegistration, compressionFilterRegistration;
    Set<SessionTrackingMode> sessionTrackingModes = new HashSet<SessionTrackingMode>();

    sessionTrackingModes.add(SessionTrackingMode.SSL);

    context = new AnnotationConfigWebApplicationContext();
    context.setServletContext(servletContext);
    context.scan("de.devbliss.doc");

    servletContext.addListener(new ContextLoaderListener(context));
    servletContext.addListener(new Log4jConfigListener());

    dispatcherServletRegistration = servletContext.addServlet("main", new DispatcherServlet(context));
    dispatcherServletRegistration.setLoadOnStartup(1);
    dispatcherServletRegistration.addMapping("/*");

    encodingFilterRegistration = servletContext.addFilter("encodingFilter", CharacterEncodingFilter.class);
    encodingFilterRegistration.setInitParameter("encoding", "UTF-8");
    encodingFilterRegistration.setInitParameter("forceEncoding", "true");
    encodingFilterRegistration.addMappingForUrlPatterns(null, false, "/*");

    compressionFilterRegistration = servletContext.addFilter("compressionFilter", GzipFilter.class);
    compressionFilterRegistration.addMappingForUrlPatterns(null, false, "/*");

    compressionFilterRegistration = servletContext.addFilter("springSecurityFilterChain",
            DelegatingFilterProxy.class);
    compressionFilterRegistration.addMappingForUrlPatterns(null, false, "/*");

    servletContext.setSessionTrackingModes(sessionTrackingModes);
}
}

EntityManagerConfig:

@Configuration
@PropertySource("classpath:/db.properties")
public class EntityManagerConfig {

@Bean
public DataSource dataSource(Environment env) {
    BasicDataSource ds = new BasicDataSource();

    ds.setUrl(env.getProperty("url", "localhost"));
    ds.setUsername(env.getProperty("user", "blissdoc"));
    ds.setPassword(env.getProperty("password", "s3cret"));

    return ds;
}

@Bean
@Inject
public LocalSessionFactoryBean sessionFactory(DataSource dataSource) {
    LocalSessionFactoryBean factory = new LocalSessionFactoryBean();

    factory.setDataSource(dataSource);

    return factory;
}

@Bean
public HibernateTransactionManager transactionManager(
        SessionFactory sessionFactory) {
    HibernateTransactionManager tm = new HibernateTransactionManager(
            sessionFactory);
    return tm;
}

@SuppressWarnings("unchecked")
@Bean
@Inject
public LocalContainerEntityManagerFactoryBean entityManager(
        DataSource dataSource, AbstractEnvironment env) {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
    HibernateJpaDialect jpaDialect = new HibernateJpaDialect();
    org.springframework.core.env.PropertySource<?> source;
    Iterator<org.springframework.core.env.PropertySource<?>> sources;

    // jpaVendorAdapter.setDatabase(Database.MYSQL);

    jpaVendorAdapter.setGenerateDdl(true);
    jpaVendorAdapter.setShowSql(true);

    Properties jpaProperties = new Properties();

    sources = env.getPropertySources().iterator();
    while (sources.hasNext()) {
        source = sources.next();
        if (source.getSource() instanceof Map) {
            for (Map.Entry<String, String> property : ((Map<String, String>) source
                    .getSource()).entrySet()) {
                jpaProperties.put(property.getKey(), property.getValue());
            }
        }
    }

    em.setJpaProperties(jpaProperties);

    em.setDataSource(dataSource);
    em.setPersistenceUnitName("blissdoc-unit");
    em.setPackagesToScan("de.devbliss.doc.model");
    em.setJpaDialect(jpaDialect);
    em.setJpaVendorAdapter(jpaVendorAdapter);

    return em;
}

// @Bean
// @Inject
// public JpaTransactionManager jpaTransactionManager(
// EntityManagerFactory entityManagerFactory) {
// JpaTransactionManager tm = new JpaTransactionManager(
// entityManagerFactory);
// return tm;
// }

@Bean
@Inject
public JpaRepositoryFactory jpaRepositoryFactory(
        EntityManagerFactory entityManagerFactory) {
    JpaRepositoryFactory factory = new JpaRepositoryFactory(
            entityManagerFactory.createEntityManager());
    return factory;
}

@Bean
@Inject
public UserRepository userRepository(
        JpaRepositoryFactory jpaRepositoryFactory) {
    return jpaRepositoryFactory.getRepository(UserRepository.class);
}

@Bean
@Inject
public ProjectRepository projectRepository(
        JpaRepositoryFactory jpaRepositoryFactory) {
    return jpaRepositoryFactory.getRepository(ProjectRepository.class);
}
}

--- Обновление PersistenceJPAConfig (бывший EntityManagerConfig):

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:/db.properties")
public class PersistenceJPAConfig {

@Inject
private Environment env;

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
    LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
    factoryBean.setDataSource(dataSource());
    factoryBean.setPackagesToScan(new String[] { "de.devbliss.doc" });
    JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter() {
        {
            // JPA properties
        }
    };
    factoryBean.setJpaVendorAdapter(vendorAdapter);

    return factoryBean;
}

@Bean
public DataSource dataSource() {
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setUrl(env.getProperty("url", "localhost"));
    dataSource.setUsername(env.getProperty("user", "blissdoc"));
    dataSource.setPassword(env.getProperty("password", "s3cret"));
    return dataSource;
}

@Bean
public PlatformTransactionManager transactionManager() {
    JpaTransactionManager transactionManager = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(entityManagerFactoryBean()
            .getObject());

    return transactionManager;
}

@Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    return new PersistenceExceptionTranslationPostProcessor();
}
}

person dwalldorf    schedule 19.10.2012    source источник
comment
Вот ссылка на TransactionManager, static.springsource.org/spring/ документы/2.0.x/ссылка/   -  person Arham    schedule 19.10.2012
comment
Эта ссылка описывает только настроенный xml TransactionManager, но мне придется придерживаться программной конфигурации.   -  person dwalldorf    schedule 19.10.2012
comment
В этом разделе описывается только программное управление транзакциями. Непрограммная конфигурация TransactionManager. Также эта часть документации предназначена для Spring 2.0. Насколько я знаю, эта версия еще вообще не знала программной настройки.   -  person dwalldorf    schedule 19.10.2012
comment
Мой плохой для предоставления неправильной ссылки. Да, версии 3.x.x начали предоставлять аннотацию и программный способ настройки. Вы можете найти ссылки на вашу конкретную версию по адресу static.springsource.org/spring/docs. Я использую 3.0.7 и раздел 10.5.6 static.springsource.org/spring/docs/3.0.7.RELEASE/reference/ содержит ваше решение.   -  person Arham    schedule 19.10.2012
comment
насколько я помню, эта конфигурация на основе аннотаций (на самом деле она не является программной) - это просто еще один способ (помимо XML) представить конфигурацию Spring. Идея должна быть такой же, не так ли? Как конфигурация не работает?   -  person Adrian Shum    schedule 19.10.2012
comment
Знайте, похоже, что сама конфигурация работает, но Jetty все еще говорит, что диспетчер транзакций не настроен. Обновлена ​​конфигурация в верхнем посте. И почему это не должно быть программной конфигурацией?   -  person dwalldorf    schedule 19.10.2012
comment
Вы, вероятно, видите эту проблему - stackoverflow.com /questions/11339758/, это просто информационное сообщение о том, что в Jetty не зарегистрирован диспетчер транзакций, совместимый с JTA, не относящийся к вашему веб-приложению.   -  person Biju Kunjummen    schedule 19.10.2012


Ответы (2)


@Configuration специфические аналоги пользовательских элементов XML, таких как <tx:annotation-driven>, являются @Enable... аннотациями.

Чтобы включить поддержку @Transactional, вам нужно аннотировать класс @Configuration с помощью @EnableTransactionManagement:

@Configuration 
@PropertySource("classpath:/db.properties") 
@EnableTransactionManagement
public class EntityManagerConfig { ... }

См. также:

person axtavt    schedule 19.10.2012
comment
Спасибо, добавлена ​​аннотация EnableTransactionManagement, но Jetty по-прежнему утверждает, что диспетчер транзакций не настроен. Также см. мой обновленный вопрос с новой конфигурацией. - person dwalldorf; 19.10.2012
comment
@entek: Насколько я помню, это сообщение от Jetty не имеет ничего общего с управлением транзакциями Spring, его можно игнорировать. - person axtavt; 19.10.2012
comment
Хорошо, давайте предположим, что это сообщение от чего-то другого и не имеет значения. Итак, я создаю нового пользователя (из моей модели пользователя) и вызываю userRepository.save(user). Никаких ошибок не выдается, но в базу данных ничего не записывается. Если я позвоню userRepository.flush(), я получу следующее сообщение: org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress - person dwalldorf; 19.10.2012
comment
Я мог бы опубликовать UserController и UserRepository в своем исходном посте, если вы считаете, что это может вам помочь. - person dwalldorf; 19.10.2012
comment
Не совсем... Проблема заключалась в странном поведении TransactionManager. Но мы просто решили с этим жить и оставить все как есть. - person dwalldorf; 10.01.2013

Вы пытались расшириться с TransactionManagementConfigurer?

@Configuration
@EnableTransactionManagement
@PropertySource("classpath:/db.properties")
public class EntityManagerConfig implements TransactionManagementConfigurer {

    ...

    @Override
    public PlatformTransactionManager annotationDrivenTransactionManager() {
        return transactionManager();
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager(entityManagerFactory());
        transactionManager.setDataSource(dataSource);
        transactionManager.setJpaDialect(new HibernateJpaDialect());
        return transactionManager;
    }

    ...
}

И похоже, что вы используете Spring Data JPA, поэтому я рекомендую вам также использовать @EnableJpaRepositories("com.your.repositories.package") для автоматической настройки ваших репозиториев данных Spring.

Надеюсь это поможет :)

person jelies    schedule 05.04.2013