【问题标题】:Spring Boot / @Transactional is working in Standalone-Mode, but not in GlassfishSpring Boot / @Transactional 在独立模式下工作,但不在 Glassfish 中
【发布时间】:2018-11-01 16:50:46
【问题描述】:

我有一个使用 JPA 存储库来操作 Postgres 数据库的服务 (JHipster4)。该服务正在导入 CSV 并创建大量实体。创建实体的公共方法用@Transactional注解(import org.springframework.transaction.annotation.Transactional)

独立启动应用程序(bootRun、OpenJDK 1.8、内部 tomcat 服务器)时,Import 以 700 个实体/秒的速度快速运行。导入完成后,我可以立即看到数据库中出现的数据。这让我确信事务正常工作。

一旦我将我的应用程序部署到 payara 4.1,@Transactional 注释似乎不像以前那样工作。我可以看到数据库正在逐行填充,并且速度很慢(20 个实体/秒),就像没有 @Transactional 一样。

在我的导入中,我使用 entityManager 和 createNativeQuery(..).executeUpdate(); 截断数据库表;

如果我删除@Transactional,我会得到

javax.persistence.TransactionRequiredException: Executing an update/delete

这很好。在带有 @Transactional 的 glassfish 上,我没有收到这样的错误(这也很好),但从数据库的角度来看,似乎没有事务正在运行(实体缓慢填充)。

payara 配置是完全默认的。 spring 数据库配置也最少,com.zaxxer.hikari.HikariDataSource,database-platform:io.github.jhipster.domain.util.FixedPostgreSQL82Dialect,database:POSTGRESQL。

在 beans.xml 上我设置了 bean-discovery-mode="none" 因为 CDI 给了我问题。

那么在独立上下文和应用程序容器(glassfish)中使用 Spring Boot JPA 的主要区别是什么?

为什么@Transactional 不像在独立版本上那样工作?你能解释一下发生了什么以及如何解决吗?

提前谢谢你!

【问题讨论】:

    标签: java spring-boot jakarta-ee glassfish payara


    【解决方案1】:

    在应用程序服务器环境中运行时,应用程序服务器向应用程序提供一个 EntityManager。独立运行时,EntityManager 来自 spring。这意味着如果应用程序在 glassfish 中运行,则 glassfish 会管理事务。

    由于 Glassfisch 事务管理器不理解 Spring 的 @Transactional 注解,因此没有效果。

    选项 1 是更改您的代码以使用应用程序服务器事务 API。我不想这样做,因为我会失去独立运行的能力(即用于测试)。

    选项2是实现自己的EntityManager、TransactionManager和DataSource,像这样。我的目标是创建一个默认 TransactionManager 的替代品,它读取 spring boot 配置。

    @Configuration
    public class EntityManagerConfiguration {
    
        protected final static Logger log = LoggerFactory.getLogger(EntityManagerConfiguration.class);
    
        private final ConfigurableEnvironment env;
    
        @Autowired
        public EntityManagerConfiguration(ConfigurableEnvironment env) {
            this.env = env;
        }
    
        @Bean
        @Primary
        public LocalContainerEntityManagerFactoryBean entityManager() {
    
            LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
            em.setDataSource(dataSource());
            em.setPackagesToScan(
                    "com.project.domain"
            );
    
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            em.setJpaVendorAdapter(vendorAdapter);
            HashMap<String, Object> properties = new HashMap<>();
            properties.put("hibernate.physical_naming_strategy", SpringPhysicalNamingStrategy.class.getName());
            properties.put("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName());
            Map<String,Object> props = ConfigAccessService.getPropertiesStartingWith(
                    env,
                    "spring.jpa.properties"
            );
    
            for(Map.Entry<String,Object> config : props.entrySet()) {
                String configName = config.getKey().replace("spring.jpa.properties.","");
                properties.put(configName, config.getValue());
                log.info("setting " + configName + " = " + config.getValue());
            }
            em.setJpaPropertyMap(properties);
            log.info("EntitiyManager configured");
    
            return em;
        }
    
        /**
         * as we want to run stand-alone (tests) and in glassfish(JavaEE) the same, we setup our own connection
         * using the Hikari Connection-Pooling.
         * @return
         */
        @Primary
        @Bean
        public DataSource dataSource(){
            HikariConfig hikariConfig = new HikariConfig();
            hikariConfig.setDriverClassName("org.postgresql.Driver");
            hikariConfig.setJdbcUrl(env.getProperty("spring.datasource.url"));
            hikariConfig.setUsername(env.getProperty("spring.datasource.username"));
            hikariConfig.setPassword(env.getProperty("spring.datasource.password"));
    
            hikariConfig.setMaximumPoolSize(10);
            hikariConfig.setConnectionTestQuery("SELECT 1");
            hikariConfig.setPoolName("springHikariCP");
    
            HikariDataSource dataSource = new HikariDataSource(hikariConfig);
    
            return dataSource;
        }
    
        @Primary
        @Bean
        public PlatformTransactionManager transactionManager() {
    
            JpaTransactionManager transactionManager
                    = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(
                    entityManager().getObject());
            return transactionManager;
        }
    
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-04
      • 2015-04-02
      • 1970-01-01
      • 1970-01-01
      • 2018-09-27
      • 2021-08-08
      • 1970-01-01
      • 2015-10-25
      相关资源
      最近更新 更多