Spring + Jboss7 @Transactional 不工作

Posted

技术标签:

【中文标题】Spring + Jboss7 @Transactional 不工作【英文标题】:Spring + Jboss7 @Transactional Not working 【发布时间】:2017-06-04 18:28:44 【问题描述】:

我正在将我的 JBoss 服务器从 5 升级到 7,现在正在合并 Spring 4。我在使用 Spring 的 @Transactional 注释时遇到了一些问题。它似乎没有工作。我也在尝试使用基于 java 的配置文件而不是 xml 文件(我相信我可以在不使用任何 xml 的情况下逃脱,但如果我错了,请纠正我)。问题是我的数据库中没有保存任何内容,这让我相信@Transactional 不起作用。这是我的配置文件:

@Configuration
@ComponentScan
@EnableTransactionManagement
public class SpringBeanConfiguration 

@Bean
public FirstTestBean firstTestBean() 
    return new FirstTestBean();


@Bean
public TestService testService() 
    return new TestServiceImpl();


@Bean 
public SomethingDAO somethingDAO()
    return new SomethingDAOImpl();


@Bean 
public GeneralDAO generalDAO()
    return new GeneralDAOImpl();

这是一个带有@Transactional 方法的测试类:

//@RequestScoped
@ManagedBean(name="firstTestBean")
@Component
public class FirstTestBean 

private EntityManager em;
private EntityManagerFactory emf;


@Transactional
public String transactionalTest() 
    //ApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanConfiguration.class);
    Something something = new Something();
    getEntityManager().persist(something);
    return "dkljs";



public EntityManager getEntityManager() 
    if (em == null) 
        emf = Persistence.createEntityManagerFactory("xxx");
        em = emf.createEntityManager();
    
    return em;

我也在使用与 Spring 兼容的 Hibernate 4。我注释掉了ApplicationContext,因为我在 JBoss 启动时单独运行了它。我之前使用它来访问一个 bean,但我已经简化了一些事情以使 @Transactional 工作,因此在这里不需要它。 @ComponentScan 不需要参数,因为这些类在同一个包中。

任何帮助将不胜感激。谢谢!

更新

我已经做了一些建议的更改。事情似乎正朝着正确的方向发展。

这是我更新的文件:

@ManagedBean(name="firstTestBean")
public class FirstTestBean 

public String getTestString()      
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanConfiguration.class);
    TestService testService = context.getBean(TestService.class);       


    testService.transactionalTest();
    return "adfs";


public String test() 
    return "firstTestBean works";
   

注意 - 其中一些类将作为独立应用程序在 Jboss 应用程序服务器之外运行,因此,我在 FirstTestBean 中实例化 TestService 时远离 FacesContext,因为 Spring bean 独立工作,但 FacesContext bean不要。

@Component
@Transactional
public class TestServiceImpl implements TestService 

public GeneralDAO generalDAO;

//@Autowired
private EntityManager em;

//@Autowired
private EntityManagerFactory emf;


public TestServiceImpl()



public String transactionTest() 
    Something something = new Something();
    getEntityManager().persist(something);
    return "dkljs";

EntityManager 和 EntityManagerFactory 上的@autowired 不起作用 - 当它像建议的那样使用 @autowired 进行注释时,我收到一条错误消息,指出没有 EntityManager 类型的合格 Bean。

@Configuration
@ComponentScan
@EnableTransactionManagement
public class SpringBeanConfiguration implements     TransactionManagementConfigurer 



@Override
public PlatformTransactionManager annotationDrivenTransactionManager() 
    String hibernatePropsFilePath = "/[path]/hibernate.cfg.xml";
    File hibernatePropsFile = new File(hibernatePropsFilePath);

    org.hibernate.cfg.Configuration cfg = new org.hibernate.cfg.Configuration().configure(hibernatePropsFile);
    SessionFactory sessionFactory = cfg.buildSessionFactory();

    HibernateTransactionManager txManager = new HibernateTransactionManager(sessionFactory);
    txManager.setNestedTransactionAllowed(true);
    return txManager;



我现在得到的错误是:引起:org.springframework.beans.factory.BeanCreationException:创建名为“org.springframework.context.event.internalEventListenerProcessor”的bean时出错:bean初始化失败 ;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' 的 bean 时出错: 注入自动装配的依赖项失败;嵌套异常是 org.hibernate.service.UnknownUnwrapTypeException: Cannot unwrap to requested type [javax.sql.DataSource]

我认为这意味着@Transactional 至少已被识别,但我在使其正常工作时遇到了一些问题。任何进一步的建议将不胜感激。

更多更新

找到这篇文章:http://www.baeldung.com/the-persistence-layer-with-spring-and-jpa#javaconfig

并跟随它。我的新配置文件:

@Configuration
@ComponentScan
@EnableTransactionManagement
public class SpringBeanConfiguration  //implements  TransactionManagementConfigurer 

   @Bean
   public LocalContainerEntityManagerFactoryBean entityManagerFactory() 
      LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
      em.setDataSource(dataSource());
      em.setPackagesToScan(new String[]  "xxx.xxx.xxx" );

      JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
      em.setJpaVendorAdapter(vendorAdapter);
   //   em.setJpaProperties(additionalProperties());

      return em;
   

   @Bean
   public DataSource dataSource()
      DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setDriverClassName("com.mysql.jdbc.Driver");
      dataSource.setUrl("jdbc:mysql://localhost:3306/jboss_test");
      dataSource.setUsername( "root" );
      dataSource.setPassword( "root" );
      return dataSource;
   

   @Bean
   public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(emf);

      return transactionManager;
   

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

好消息是我不再遇到部署问题。日志记录还表明我的更改对服务器产生了一些影响。不幸的是,没有任何东西被保存,所以它仍然不能正常工作。

【问题讨论】:

【参考方案1】:

首先引起我注意的是 @Transactional 和 @Component 在 ManagedBean 上的使用。

JSF 和 Spring 绝对可以一起工作,但我从未在我从事的许多项目中看到它们以这种方式使用过。

我不确定这是否是您的问题的原因,但请考虑改变它。

我会这样做:

a) 定义一些服务层,您可以在其中使用事务包装调用并注入 JPA 类:

@Component
@Transactional
class Service

   @Autowired
   private EntityManager em;

   @Autowired
   private EntityManagerFactory emf;

   public String serviceMethod(..) .. 


b) 将其注入到 Jsf 的 ManagedBean 中,同时删除不必要的注释:

@ManagedBean(name="firstTestBean")
public class FirstTestBean 

  @ManagedProperty("#service")
  private Service service;

  public String transactionalTest() 
      return service.serviceMethod(); 
  


【讨论】:

我最初有这个,但尝试简化它只是为了看看我是否可以得到任何工作......我会将更改恢复到我最初的更改并尝试你所说的。我会发布更新。感谢您的帮助。 做了一些更新。抱歉回复晚了 - 想先修补一下。 据我记得,绑定 JPA、Hibernate 和 Spring 的方式有些不同(至少我使用了不同的配置)。尝试注入 SessionFactory 而不是 EntityManagerFactory 并查看它是否有效。如果你真的需要坚持使用 JPA,那么我会给你一些配置链接 我尝试自动装配 Sessionfactory 并得到与 EntityManagerFactory 相同的错误。坚持使用 JPA 绝对是理想的选择。配置链接肯定会受到赞赏。谢谢! 找到一篇有帮助的文章 - 我在上面列出了一些更改,但仍然不是我需要的地方【参考方案2】:

好的,所以我终于明白了(请查看我的 OP 以了解所有导致我达到这一点的更新)。

这是我的最终配置文件:

@Configuration
@ComponentScan
@EnableTransactionManagement
public class SpringBeanConfiguration  

   @Bean
   public LocalContainerEntityManagerFactoryBean entityManagerFactory() 
      LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
      em.setPersistenceUnitName("myPersistenceContext");
      em.setDataSource(dataSource());
      em.setPackagesToScan(new String[]  "xxx.xxx.xxx" );

      JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
      em.setJpaVendorAdapter(vendorAdapter);
   //   em.setJpaProperties(additionalProperties());

      return em;
   

   @Bean
   public DataSource dataSource()
      DriverManagerDataSource dataSource = new DriverManagerDataSource();
      dataSource.setDriverClassName("com.mysql.jdbc.Driver");
      dataSource.setUrl("jdbc:mysql://localhost:3306/jboss_test");
      dataSource.setUsername( "root" );
      dataSource.setPassword( "root" );
      return dataSource;
   

   @Bean
   public PlatformTransactionManager transactionManager(EntityManagerFactory emf)
      JtaTransactionManager transactionManager = new JtaTransactionManager();
     // transactionManager.setEntityManagerFactory(emf);

      return transactionManager;
   

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

所以首先,我添加了

em.setPersistenceUnitName("myPersistenceContext");  

这给了我错误:

Spring IllegalStateException: A JTA EntityManager 不能使用 getTransaction()

从这里开始,我做了一些研究 (Spring IllegalStateException: A JTA EntityManager cannot use getTransaction())

改变了

JpaTransactionManager transactionManager = new JpaTransactionManager();

JtaTransactionManager transactionManager = new JtaTransactionManager();

另外,我的 persistence.xml 文件是:

    <persistence-unit name="myPersistenceContext">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>java:jboss/datasources/myDS</jta-data-source>
    <class>xxx.xxx.xxx.Something</class>    
    <exclude-unlisted-classes>false</exclude-unlisted-classes>

    <properties>
        <property name="hibernate.cache.use_second_level_cache" value="true" />
        <property name="hibernate.id.new_generator_mappings" value="false"/>
        <property name="hibernate.classloading.use_current_tccl_as_parent" value="false"/>
        <property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" /> 
        <property name="hibernate.show_sql" value="true" />
        <property name="hibernate.archive.autodetection" value="class, hbm" />
    </properties>
</persistence-unit>

感谢 Maciej Kowalski 的帮助 - 你把我推向了正确的方向。

【讨论】:

以上是关于Spring + Jboss7 @Transactional 不工作的主要内容,如果未能解决你的问题,请参考以下文章

Jboss 7 - Spring - 使用 Jboss TransactionManager

Jboss7安装和使用

Jboss7集群配置说明

为啥从 JBoss 7.1.0EAP 到 Oracle 11g 生成了 100 个幽灵 Oracle 会话

报错解决:No Hibernate Session bound to thread, and configuration does not allow creation of non-transact

Jboss7.1 MDB - 本地 JNDI 参考与全球 JNDI 参考