【问题标题】:How to configure TransactionManager programmatically如何以编程方式配置 TransactionManager
【发布时间】:2012-10-09 21:02:24
【问题描述】:

我在这里有一个基于 Spring MVC 的应用程序。我的同事(顺便说一句,他不在这里)以编程方式对其进行了配置,并且似乎一切正常,除了 TransactionManager。我从来没有像这样配置过 Spring Web 应用程序,我不知道该怎么做,也找不到任何关于如何配置这样的 Web 应用程序的文档。

我将向您展示“AppInitializer”和“EntityManagerConfig”。

AppInitializer:

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();
}
}

【问题讨论】:

  • 这里是 TransactionManager 的链接,static.springsource.org/spring/docs/2.0.x/reference/…
  • 此链接仅描述了 xml 配置的 TransactionManager,但我必须坚持编程配置。
  • 本节只描述程序化事务管理。不是 TransactionManager 的编程配置。这篇文档也适用于 Spring 2.0。据我所知,这个版本根本不知道编程配置。
  • 我对提供不正确的链接很不利。是的,3.x.x 版本开始提供注释和配置相同的编程方式。您可以在static.springsource.org/spring/docs 找到您特定版本的链接。我正在使用 3.0.7,static.springsource.org/spring/docs/3.0.7.RELEASE/reference/… 的第 10.5.6 节有你的解决方案。
  • 我记得,这些基于注释的配置(它不是真正的“程序化”)只是将配置呈现给 Spring 的另一种方式(除了 XML)。思路应该是一样的吧?配置如何“不起作用”?

标签: java hibernate spring-mvc spring-transactions


【解决方案1】:

您是否尝试过从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 Data Repositories。

希望这会有所帮助:)

【讨论】:

    【解决方案2】:

    @Configuration 特定对应的自定义 XML 元素(例如 &lt;tx:annotation-driven&gt;)是 @Enable... 注释。

    为了启用对@Transactional 的支持,您需要使用@EnableTransactionManagement 注释您的@Configuration 类:

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

    另请参阅:

    【讨论】:

    • 谢谢,添加了 EnableTransactionManagement 注释,但 Jetty 仍然声称没有配置事务管理器。另请参阅我使用新配置更新的问题。
    • @entek:据我记忆,Jetty的这条消息与Spring事务管理无关,可以忽略。
    • 好的,我们假设这条消息来自其他东西并且无关紧要。所以我创建了一个新用户(来自我的 UserModel)并调用userRepository.save(user)。不会引发错误,但不会将任何内容写入数据库。如果我打电话给userRepository.flush(),我会收到以下消息:org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.persistence.TransactionRequiredException: no transaction is in progress
    • 如果您认为对您有帮助,我可以将 UserController 和 UserRepository 发布在我的原始帖子中。
    • 不是真的.. 问题是 TransactionManager 的奇怪行为。但我们只是决定接受它并保持这种状态。
    猜你喜欢
    • 2016-11-20
    • 2014-12-15
    • 2011-02-17
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 2015-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多