English 中文(简体)
@transactional don t work with @Async in Websphere
原标题:@Transactional doesn t work with @Async in Websphere

我正在尝试使用@ Transactional within @Async方法追踪文件转换过程如下:

@Async
@Transactional
public void convertFile(String documentId) {
     
    CustomLog customLog = new CustomLog();
    customLog.setStatus("IN_PROGRESS");
    mySpringDataRepo.save(customLog);

    try {
      doConvertFunction(documentId);    
    } catch (Exception e) {
      customLog.setStatus("FAIL");
      mySpringDataRepo.save(customLog);
      return;
    }

    customLog.setStatus("SUCCESS");
    mySpringDataRepo.save(customLog);   
}

我正在使用以下技术:

  • Spring Boot 2.7.18
  • Hibernate Core 5.6.15.Final
  • Websphere ND 9.0.5.13
  • Java 1.8

我的客户实体组合:

@Primary
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder,
    DataSource dataSource) {
    LocalContainerEntityManagerFactoryBean em = builder.dataSource(dataSource).packages("com.myapp").persistenceUnit("MyEntityManagerFactory").properties(jpaProperties()).build();
    JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    return em;
}

protected Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.physical_naming_strategy", CamelCaseToUnderscoresNamingStrategy.class.getName());
        props.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
        return props;
}

当操作上述《汤姆斯法典》时 9 它完全是罚款的,但在试图在网上进行交易时,交易是公开的,储蓄方法根本就没有执行!

I made several tries with no luck as follows:

  1. 使用@ Transactional(propagation = Propagation。 REQUIRES_NEW

  2. 将储蓄方法推至新的单独服务方法,具体如下:

    @Service
    public class MyService {
    
      @Autowired
      private MySpringDataRepo mySpringDataRepo;
    
      @Transactional(propagation = Propagation.REQUIRES_NEW)
      public CustomLog save(CustomLog customLog) {
         mySpringDataRepo.save(customLog);
         return customLog;
      }
    
    }
    

UPDATE:

<>只有>解决办法在网上开展工作,即从实体管理基金会创建实体管理:

@Service
public class CustomLogService {

    @Autowired
    private EntityManagerFactory entityManagerFactory;

    
    public Long save(CustomLog customLog) {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        entityManager.persist(customLog);
        entityManager.flush();
        entityManager.getTransaction().commit();
        return customLog.getId();
    }

    public CustomLog find(Long id) {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        CustomLog customLog = entityManager.find(CustomLog.class, id);
        entityManager.getTransaction().commit();
        return customLog;
    }

    public void update(CustomLog customLog) {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        entityManager.getTransaction().begin();
        entityManager.merge(customLog);
        entityManager.getTransaction().commit();
    }

}

更改我的<代码>@Async 守则如下:

@Async
public void convertFile(String documentId) {

    CustomLog customLog = new CustomLog();
    customLog.setStatus("IN_PROGRESS");
    customLogService.save(customLog);

    try {
       doConvertFunction(documentId);    
    } catch (Exception e) {
      customLog = customLogService.find(customLog.getId());
      customLog.setStatus("FAIL");
      customLogService.update(customLog);
      return;
    }

    customLog = customLogService.find(customLog.getId());
    customLog.setStatus("SUCCESS");
    customLogService.update(customLog);

}

我试图注入实体 经理,但只有创建实体才能工作。 实体经理:

@PersistenceContext(name = "MyEntityManagerFactory")
private EntityManager entityManager;

Are there any disadvantages/things to consider in this solution because I will be heavily using this method and it returns a new EntityManager instance each time it is invoked?

最佳回答

1. 更新你的配置代码。

@Configuration
@EnableJpaRepositories(basePackages = { "com.myapp.dao" }, transactionManagerRef = "websphereTxManager")
@EnableTransactionManagement
public class WebSphereDBConfiguration {

    @Resource(lookup = "jdbc/sample", name = "java:comp/env/jdbc/sample")
    private DataSource dataSource;

    @Primary
    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
        LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
        entityManagerFactoryBean.setPackagesToScan("com.myapp.entity");
        entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        entityManagerFactoryBean.setDataSource(dataSource);
        entityManagerFactoryBean.setJpaPropertyMap(jpaProperties());
        return entityManagerFactoryBean;
    }

    @Bean
    public EntityManagerFactory entityManagerFactory(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
        return entityManagerFactoryBean.getObject();
    }

    @Bean
    public PlatformTransactionManager websphereTxManager(EntityManagerFactory entityManagerFactory) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory);
        return transactionManager;
    }


    protected Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.physical_naming_strategy", CamelCaseToUnderscoresNamingStrategy.class.getName());
        props.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
        return props;
    }


}

采用相同的法典:

@Async
@Transactional
public void convertFile(String documentId) {
     
    CustomLog customLog = new CustomLog();
    customLog.setStatus("IN_PROGRESS");
    mySpringDataRepo.save(customLog);
    
    try {
      doConvertFunction(documentId);    
    } catch(Exception e) {
      customLog.setStatus("FAIL");
      mySpringDataRepo.save(customLog);
      return;
    }

    customLog.setStatus("SUCCESS");
    mySpringDataRepo.save(customLog);
       
}

www.un.org/Depts/DGACM/index_spanish.htm 注意的要点很少:

  1. Creating a bean of LocalContainerEntityManagerFactoryBean.
  2. Creating a bean of EntityManagerFactory via injecting LocalContainerEntityManagerFactoryBean and getting the object via LocalContainerEntityManagerFactoryBean.getObject(). Also, make that bean as the primary bean for the whole application.
  3. You will need to create a custom transaction manager. So, creating a JpaTransactionManager bean via injection and using the EntityManagerFactory bean.
  4. You can see this annotation @EnableTransactionManagement. By use of this annotation, you will tell Spring to use this configuration class to manage your transaction.
  5. See this annotation @EnableJpaRepositories. By this annotation, you will tell Spring which packages to scan containing the JPA repositories and also tell which transaction manager to use via this property transactionManagerRef by default.
  6. You have to configure datasource on the WebSphere (I guess you already did) and inject it via @Resource and set that datasource in the LocalContainerEntityManagerFactoryBean bean.

如果有这种帮助的话。

问题回答

请注意,我没有用于网站和最近版本的jakartaEE。

只是一些一般性考虑:

  • @Async methods defer the process to another thread.
  • Transaction propagation rely on a threadLocal context and so the current transaction / entityManager instance is probably not reachable from your @Async method thread.
  • All of this is very probably dependent on provider implementation. Maybe you could have better result using Container Managed transaction Manager provided by the Websphere server itself.
  • Generally speaking using both a jakartaEE server and Spring might lead to additional complexity as their scope often overlap (You can use either Spring or JakartaEE containers in many cases: JPA, DI, Security, etc and problems will emerge if you mix features from both)
  • Regarding your workaround, instantiating an new EntityManager instance for each method is not necessarily shocking, particularly if the method is directly invoked through a dedicated http request (see https://stackoverflow.com/a/22773758/2087640)




相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签