You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

升级Vaadin24/SpringBoot3后EclipseLink性能骤降问题求助

问题描述

负责一款已投产17年的Web应用,当前技术栈:Vaadin23 + EclipseLink2.7.8。因Vaadin23停止支持,需升级至依赖SpringBoot3的Vaadin24,同步需将JPA从2.1(javax.persistence)迁移至3.x(jakarta.persistence)。

性能问题现象

  • EclipseLink2.7.8:JUnit测试耗时约10分钟
  • 升级至2.7.9:测试耗时增至20分钟
  • 升级至2.7.14:测试耗时达30分钟
  • 升级至3.0.4:测试至少需40分钟,应用整体变慢

核心问题:从2.7.8升级至2.7.9后,简单全表查询(如select o from YXZ o)耗时大幅上升,所有@OneToMany关联已显式标注fetch=FetchType.LAZY(默认配置)。

临时方案尝试

在SpringBoot3中保留EclipseLink2.7.8,编译与测试启动正常,persistence.xml配置可读取,但EntityManager无法识别@Entity类。

复现测试用例

编写JUnit测试对5个实体执行全表查询:

EntityManager em = Persistence.createEntityManagerFactory(Constants.PERSISTENCE_UNIT).createEntityManager();
String format = "%-20s: %6d %8d \n";
System.out.printf("%-20s: %6s %8s \n", "Entity", "Count", "Duration");
long start = System.currentTimeMillis();
String[] entities = {"Entity1", "Entity2", "Entity3", "Entity4", "Entity5"};
for (String entity: entities) {
   String query = String.format("select o from %s o", entity);
   long sStart = System.currentTimeMillis();
   int size = em.createQuery(query).getResultList().size();
   System.out.printf(format, entity, em.createQuery(query).getResultList().size(), System.currentTimeMillis() - sStart);
}
System.out.println("Duration summary:" + (System.currentTimeMillis() - start));

测试结果

EclipseLink2.7.8

EntityCountDuration
Entity13448328
Entity21224560
Entity31427533
Entity494073172
Entity5235488970

总耗时:13565毫秒

EclipseLink2.7.9

EntityCountDuration
Entity13448465
Entity212245187
Entity314275834
Entity4940740513
Entity523548114871

总耗时:166872毫秒


解决方案

1. 检查并调整缓存策略

EclipseLink 2.7.9+可能调整了默认缓存行为,尝试:

  • 给实体显式添加@Cache(shared = false, type = CacheType.NONE)关闭二级缓存,验证是否是缓存加载导致的延迟
  • 全局配置eclipselink.cache.shared.default=false关闭二级缓存

2. 优化查询执行逻辑

  • 启用SQL日志(配置eclipselink.logging.level.sql=FINE),对比2.7.8和2.7.9生成的SQL,确认是否出现意外的关联查询或执行计划变化
  • 对全表查询添加只读提示,减少实体管理开销:
    em.createQuery(query).setHint("eclipselink.read-only", true).getResultList();
    
  • 增大JDBC fetch size,减少数据库交互次数:配置eclipselink.jdbc.fetch-size=1000(根据数据量调整)

3. 排查动态编织问题

EclipseLink的动态编织可能在新版本中引入性能损耗,尝试:

  • 启用静态编织,在编译阶段生成增强的实体类,避免运行时编织开销
  • 配置eclipselink.weaving=false关闭动态编织,验证性能变化

4. 校验实体注解规范

2.7.9对JPA 2.2规范的兼容性更严格,检查:

  • @OneToMany的mappedBy属性是否正确指向关联实体的对应字段
  • 实体类是否存在未正确标注的关联关系,导致隐式的EAGER加载

Spring Boot 3基于Jakarta EE 9(使用jakarta.persistence),而EclipseLink 2.7.x仅支持javax.persistence,需解决包名兼容问题:

1. 依赖调整与包名桥接

  • 排除Spring Boot自带的jakarta.persistence-api,引入javax.persistence-api:
    <!-- Maven示例 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <exclusions>
            <exclusion>
                <groupId>jakarta.persistence</groupId>
                <artifactId>jakarta.persistence-api</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.hibernate</groupId>
                <artifactId>hibernate-core</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.eclipse.persistence</groupId>
        <artifactId>org.eclipse.persistence.jpa</artifactId>
        <version>2.7.8</version>
    </dependency>
    <dependency>
        <groupId>javax.persistence</groupId>
        <artifactId>javax.persistence-api</artifactId>
        <version>2.2</version>
    </dependency>
    
  • 通过IDE全局替换或编译工具,将代码中的jakarta.persistence注解批量替换为javax.persistence

2. 手动配置EntityManagerFactory

关闭Spring Boot的JPA自动配置,手动创建EntityManagerFactory确保实体被扫描:

@SpringBootApplication(exclude = JpaAutoConfiguration.class)
public class Application {
    @Bean
    public DataSource dataSource() {
        // 配置你的数据源(如HikariCP)
        return new HikariDataSource();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource);
        // 指定实体类所在包路径
        em.setPackagesToScan("com.your.app.entities");
        em.setPersistenceProviderClass(org.eclipse.persistence.jpa.PersistenceProvider.class);
        em.setPersistenceUnitName(Constants.PERSISTENCE_UNIT);

        Properties jpaProperties = new Properties();
        jpaProperties.put("eclipselink.persistencexml", "META-INF/persistence.xml");
        // 添加其他EclipseLink配置
        jpaProperties.put("eclipselink.logging.level", "INFO");
        em.setJpaProperties(jpaProperties);

        return em;
    }

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

3. 验证实体扫描

确保persistence.xml中正确配置了实体类,或通过setPackagesToScan指定扫描路径,避免EntityManager无法识别@Entity类的问题。


内容的提问来源于stack exchange,提问作者Matthias

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 19:14:52