【问题标题】:Enabling exception translation for JPA in plain Spring在纯 Spring 中为 JPA 启用异常翻译
【发布时间】:2022-01-10 18:25:25
【问题描述】:

出于教育目的,我在纯 Spring(没有 Spring Boot 或 Spring Data JPA)中使用 JPA 设置了一个基本的 CRUD Web 应用程序,但遇到了一个奇怪的问题:Spring 不会为我的存储库转换异常。根据 Spring 文档(herehere),使用 @Repository 注释标记存储库就足够了,Spring 将自动为该存储库启用异常翻译。

但是,当我这样做并触发 UNIQUE 约束违规时,我仍然得到 JPA PersistenceException(内部带有 Hibernate ConstraintViolationException)而不是 Spring DataIntegrityViolationException

我使用了纯 Java Spring 配置,我花了很长时间才意识到我应该将它与文档中的 XML 配置进行比较。与纯 Java 配置相比,XML 配置在上下文中添加了一个PersistenceExceptionTranslationPostProcessor。当我使用@Bean 手动添加它时,它起作用了,但现在我有一个问题。

我是否配置错误? Spring 文档不需要为纯 Java 配置手动注册该后处理器。 也许还有另一种注册方式,比如@EnableXXX 注释?


这是我的配置摘要。

@Configuration
@ComponentScan("com.example.secured_crm")
public class SpringConfiguration {
    // the problem is solved if I uncomment this
    //@Bean
    //public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
    //    return new PersistenceExceptionTranslationPostProcessor();
    //}
}

@Configuration
@PropertySource("classpath:db.properties")
@EnableTransactionManagement
public class DataSourceConfiguration {

    @Value("${jdbc.driver}")
    private String driverClass;

    @Value("${jdbc.url}")
    private String url;

    // ...

    @Value("${hibernate.debug}")
    private String hibernateDebug;

    @Bean
    public DataSource dataSource() {
        var dataSource = new ComboPooledDataSource();
        // ...
        return dataSource;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        var emFactory = new LocalContainerEntityManagerFactoryBean();
        emFactory.setDataSource(dataSource());
        emFactory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        emFactory.setPackagesToScan("com.example.secured_crm.entities");
        var properties = new Properties();
        properties.setProperty("hibernate.dialect", hibernateDialect);
        properties.setProperty("hibernate.show_sql", hibernateDebug);
        properties.setProperty("hibernate.format_sql", "true");
        emFactory.setJpaProperties(properties);
        return emFactory;
    }

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

public interface UserRepository {
    User findByName(String username);
    List<User> findAll();
    void save(User user);
    boolean deleteById(int id);
    User findById(int id);
}

@Repository
public class UserJpaRepository implements UserRepository {
    @PersistenceContext
    EntityManager em;

    @Override
    public void save(User user) {
        if (user.getId() == null) {
            em.persist(user);
        } else {
            em.merge(user);
        }
    }

   // and so on...
}

顺便说一句,当我尝试在DataSourceConfiguration 中添加后处理器时,它禁用了@PropertySource 效果。到目前为止,我对 Spring 的印象是它是一个大黑客......

【问题讨论】:

    标签: java spring jpa spring-orm


    【解决方案1】:

    需要手动注册PersistenceExceptionTranslationPostProcessor才能使异常翻译生效。

    您提到的documentation 还没有更新以显示完全工作的java 配置。应该提到注册这个后处理器。 (请随时提供PR 来更新文档。)

    如果你查看它的javadoc,它已经提到PersistenceExceptionTranslationPostProcessor是必须注册的:

    因此,启用自动 异常翻译正在标记所有受影响的bean(例如 带有 @Repository 注释的存储库或 DAO),以及 将此后处理器定义为应用程序上下文中的 bean。

    附:如果你使用的是 spring-boot ,如果检测到 PersistenceExceptionTranslationPostProcessor 在 class-path 中,默认会自动注册,无需手动注册。

    【讨论】:

    • 答案快得惊人!
    猜你喜欢
    • 2011-08-27
    • 2015-04-14
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-05
    相关资源
    最近更新 更多