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

Spring Boot中JPA-Hibernate无法将MySQL异常转为DataAccessException

Spring Boot + Hibernate 异常转换失效:PersistenceException未转为DataAccessException

我们的Spring Boot应用使用Hibernate配合MySQL数据库,当前遇到异常转换失效问题:当DAO层方法抛出java.sql.SQLException时,Spring并未将其转换为org.springframework.dao.DataAccessException体系异常,而是被Hibernate封装为javax.persistence.PersistenceException体系(例如查询无结果时抛出javax.persistence.NoResultException)。


相关配置

JPA-Hibernate配置类

package ....;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@RequiredArgsConstructor
@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
public class JpaConfig {

    @Value("${spring.profiles.active}")
    private String activeProfile;

    private final LocalContainerEntityManagerFactoryBean emf;

    @Bean
    public PlatformTransactionManager txManager() {
        JpaTransactionManager txManager = new JpaTransactionManager();
        txManager.setEntityManagerFactory(emf.getObject());
        txManager.setJpaDialect(emf.getJpaDialect());
        txManager.setRollbackOnCommitFailure(true);
        txManager.setPersistenceUnitName(activeProfile);
        return txManager;
    }

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

应用属性配置

spring.datasource.url=jdbc:mysql://xxx
spring.datasource.username=xxx
spring.datasource.password=xxx
spring.datasource.hikari.maximum-pool-size=20
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.data.jpa.repositories.bootstrap_mode=lazy
spring.datasource.name=${xxx}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.pool-name=${xxx}
spring.datasource.hikari.auto-commit=false
spring.datasource.hikari.max-lifetime=600000
spring.datasource.hikari.connection-timeout=600000
spring.datasource.hikari.validation-timeout=600000
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.open-in-view=false
spring.jpa.generate-ddl=false
spring.jpa.hibernate.ddl-auto=validate
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.connection.autocommit=false
spring.jpa.properties.hibernate.ddl-auto=validate
spring.jpa.properties.hibernate.format_sql=false
spring.jpa.properties.hibernate.use_sql_comments=false

DAO层代码

@Repository
public class XxxxxDaoImpl implements XxxxxDao {

@Override
public Entity getXXX(Long xxx) {
   try {
       return entityManager.createQuery("SELECT c FROM xxx c " +
               "INNER JOIN c.xx e ON e.id = :xxx " +
               "INNER JOIN FETCH xxx i", xxx.class)
           .setParameter("xxx", xxx).getSingleResult();
   } catch(DataAccessException e) {
       // 无法进入此catch块,因为抛出的是javax.persistence.PersistenceException类型异常
       log.error("DAO: exception in querying xxx for xxx: {} => {}", xxx, e.getMessage());
            return null;
   }
}
}

日志提示

启动日志中出现如下提示,怀疑与异常转换失效相关:

INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'spring.sql.init-org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties' of type [org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'dataSourceScriptDatabaseInitializer' of type [org.springframework.boot.autoconfigure.sql.init.SqlDataSourceScriptDatabaseInitializer] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'spring.jpa-org.springframework.boot.autoconfigure.orm.jpa.JpaProperties' of type [org.springframework.boot.autoconfigure.orm.jpa.JpaProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'spring.jpa.hibernate-org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties' of type [org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration' of type [org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'hikariPoolDataSourceMetadataProvider' of type [org.springframework.boot.autoconfigure.jdbc.metadata.DataSourcePoolMetadataProvidersConfiguration$HikariPoolDataSourceMetadataProviderConfiguration$$Lambda$449/0x00000008403ab840] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration' of type [org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'jpaVendorAdapter' of type [org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO  o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker.postProcessAfterInitialization:376: Bean 'entityManagerFactoryBuilder' of type [org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

问题分析与解决方案建议

  1. 确认@Repository代理生效
    Spring的PersistenceExceptionTranslationPostProcessor依赖AOP对标注@Repository的类生成代理实现异常转换。需确保XxxxxDaoImpl被Spring容器正确管理,可通过日志检查Bean初始化状态。

  2. 确保EntityManager由Spring注入
    若EntityManager是通过非Spring方式(如直接调用Persistence.createEntityManagerFactory)获取,Spring无法对其进行异常转换。必须使用@PersistenceContext注解注入EntityManager。

  3. 调整异常转换处理器配置
    显式开启CGLIB代理,避免JDK动态代理的局限性:

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        PersistenceExceptionTranslationPostProcessor processor = new PersistenceExceptionTranslationPostProcessor();
        processor.setProxyTargetClass(true);
        return processor;
    }
    
  4. 修复Bean初始化顺序问题
    日志中关于Bean不适合被后置处理器处理的提示,通常是因为Bean初始化早于后置处理器。可尝试移除自定义JpaConfig,改用Spring Boot自动配置;若必须保留自定义配置,确保LocalContainerEntityManagerFactoryBean由Spring Boot自动注入。

  5. 手动转换异常(临时方案)
    若上述方案无效,可在DAO层手动转换异常:

    @Autowired
    private PersistenceExceptionTranslator exceptionTranslator;
    
    @Override
    public Entity getXXX(Long xxx) {
       try {
           return entityManager.createQuery(...).getSingleResult();
       } catch(PersistenceException e) {
           DataAccessException dae = exceptionTranslator.translateExceptionIfPossible(e);
           if (dae != null) {
               throw dae;
           }
           throw e;
       }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 00:35:22