Spring MVC处理独特的约束违规

时间:2015-02-20 10:33:59

标签: java spring spring-mvc exception-handling spring-data-jpa

我有一个Spring MVC应用程序,它使用Spring Data JPA来持久化Hibernate作为我的JPA提供程序。我有一个对列有唯一约束的数据库表,因此保存相应实体可能导致唯一约束违规。我想检测是否在我的服务层内发生这种情况,以便我可以向用户提供有意义的错误消息。以下是我的服务方法。

@Service
public class IndustryServiceImpl implements IndustryService {
    @Autowired
    private IndustryRepository industryRepository;

    @Override
    @Transactional
    public void add(Collection<Industry> industries) {
        this.industryRepository.save(industries);
        this.industryRepository.flush();
    }
}

我的Spring Data JPA存储库看起来像这样:

@Repository
public interface IndustryRepository extends JpaRepository<Industry, Integer> { }

现在,当发生唯一约束违规时,我得到以下异常(为简洁起见缩短):

javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement
    ...

org.hibernate.exception.ConstraintViolationException: could not execute statement
    ...

org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "industry_name_unique_index"
  Detail: Key (name)=(SomeValue) already exists.
  ...

正如您所看到的,&#34;主要&#34;异常属于javax.persistence.PersistenceException类型,这是一个非常普遍的例外。理想情况下,我想捕获一个异常,告诉我该错误是由于一个唯一的约束违规。因此,我有几个问题:

  1. 异常应该是javax.persistence.PersistenceException类型是正确的,还是因为Spring异常翻译没有开始?我可以配置Spring以减少一般异常,例如DuplicateKeyException
  2. 如果此行为与丢失的异常转换无关,那么您是否知道检测更具体的错误的方法比调用e.getCause()更好?我可以轻松地做到这一点,但出于两个原因,这对我来说似乎并不合适;首先,代码似乎更脆弱&#34;对我来说,其次,我还必须检查JPA提供程序特定的异常,因为嵌套异常的类型为org.hibernate.exception.ConstraintViolationException。如果可能的话,我希望我的服务不知道我正在使用哪个JPA提供商。
  3. 以下是我的持久性配置,以防相关。

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = { "com.example.company.repository", "com.example.account.repository" })
    public class PersistenceConfig {
        @Autowired
        private LocalValidatorFactoryBean validator;
    
        @Value("${jndi.data.source}")
        private String dataSourceName;
    
        @Bean
        public DataSource dataSource() {
            final JndiDataSourceLookup dsLookup = new JndiDataSourceLookup();
            dsLookup.setResourceRef(true);
    
            return dsLookup.getDataSource(this.dataSourceName);
        }
    
        @Bean
        public EntityManagerFactory entityManagerFactory() {
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            vendorAdapter.setGenerateDdl(false);
            vendorAdapter.setDatabase(Database.POSTGRESQL);
            vendorAdapter.setShowSql(true);
    
            LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
            factory.setJpaVendorAdapter(vendorAdapter);
            String[] packagesToScan = new String[] { "com.example.company.entity", "com.example.account.entity" };
            factory.setPackagesToScan(packagesToScan);
            factory.setDataSource(this.dataSource());
            factory.setValidationMode(ValidationMode.NONE); // Prevents errors when using custom validators when persisting
            factory.afterPropertiesSet();
    
            return factory.getObject();
        }
    
        @Bean
        public JpaTransactionManager transactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(this.entityManagerFactory());
    
            return transactionManager;
        }
    
        @Bean
        public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
            return new PersistenceExceptionTranslationPostProcessor();
        }
    }
    

    提前谢谢!

1 个答案:

答案 0 :(得分:0)

Spring允许通过@Repository注释透明地应用异常转换。后处理器自动查找所有异常转换器(PersistenceExceptionTranslator接口的实现),并建议所有标记有@Repository注释的bean,以便发现的转换器可以拦截并对引发的异常应用适当的转换。

总结:您可以基于普通持久性技术的API和注释实现DAO,同时仍然可以从Spring管理的事务,依赖项注入和Spring的自定义异常层次结构的透明异常转换(如果需要)中受益。

`

<!-- Exception translation bean post processor -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>

<bean id="myProductDao" class="product.ProductDaoImpl"/>

`

直接来自here

另外,您可以查看this

HTH。