Spring + Jboss7 @Transactional不工作

时间:2017-01-19 21:44:04

标签: java spring hibernate jsf jboss

我正在将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上的@autowired和EntityManagerFactory都不起作用 - 我收到了一个错误,说明没有合格的Bean类型为EntityManager,当它被@autowired注释为建议时。

@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:无法解包到请求的类型[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();
   }

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

2 个答案:

答案 0 :(得分:2)

引起我注意的第一件事是在ManagedBean上使用@Transactional和@Component。

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

}

答案 1 :(得分:0)

好的,所以我终于明白了(查看我的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: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的帮助 - 你把我推向正确的方向。