Java Spring MVC处理唯一约束冲突

Java Spring MVC处理唯一约束冲突,java,spring,spring-mvc,exception-handling,spring-data-jpa,Java,Spring,Spring Mvc,Exception Handling,Spring Data Jpa,我有一个SpringMVC应用程序,它使用SpringDataJPA进行持久化,Hibernate作为我的JPA提供程序。我有一个数据库表,在一个列上有一个唯一的约束,因此为什么保存相应的实体可能会导致唯一约束冲突。我想检测这是否发生在我的服务层中,以便我可以向用户提供有意义的错误消息。下面是我的服务方法 @Service public class IndustryServiceImpl implements IndustryService { @Autowired privat

我有一个SpringMVC应用程序,它使用SpringDataJPA进行持久化,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();
    }
}
如您所见,“main”异常的类型为
javax.persistence.PersistenceException
,这是一个非常普遍的异常。理想情况下,我希望捕获一个异常,该异常告诉我错误是由于唯一的约束冲突造成的。因此,我有几个问题:

  • 异常的类型应该是
    javax.persistence.PersistenceException
    ,这是正确的,还是因为Spring异常转换没有启动?例如,我可以配置Spring以提供不太常见的异常吗
  • 如果此行为与缺少异常转换无关,那么您知道有比调用
    e.getCause()
    更好的方法来检测更具体的错误吗?我可以很容易地做到这一点,但这对我来说并不正确,原因有二;首先,代码对我来说似乎更“脆弱”,其次,我还必须检查JPA提供程序特定的异常,因为嵌套异常的类型是
    org.hibernate.exception.ConstraintViolationException
    。如果可能的话,我希望我的服务不知道我正在使用哪个JPA提供商
  • 下面是我的持久性配置,以防相关

    @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();
        }
    }
    

    提前谢谢你

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

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

    `

    
    
    `

    直接取自

    另外,你可以看看


    是的,你说得对。但是我已经使用了
    @Repository
    注释,并且我还像上面的代码示例一样配置了异常转换。所以它应该可以工作了,对吧?是的,我想纯JPadiotic适合你的需要。但是,我们又一次认为正常的事情也会发生。将需要实施和查看。我会尽力做到这一点,如果可能的话会回复你。谢谢你,我感谢你的帮助!我想说的是,您应该显式地验证数据,而不是依赖异常。@是的,事实上我是这样做的,但是如果发生幻象读取,那么这种情况仍然可能发生(尽管可能性很小)-我不想锁定表。我可能还需要在其他情况下回答这个问题。:-)@在繁忙的服务器中,您无法针对唯一的db约束进行验证。无论如何,我已经在本地进行了测试,不管我是否真的在app config中注册了一个PetPostProcessor,我都会得到以下结果,这样翻译才会发生:org.springframework.dao.DataIntegrityViolationException>javax.persistence.PersistenceException>org.hibernate.exception。ConstraintViolationException@AlanHay隐马尔可夫模型,奇怪的是,这不是我得到的行为。如果你有什么想法可能是错误的,或者如果你想让我发布更多的代码,那么请让我知道。我真的很感谢你花时间来测试这个-谢谢!
    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.
      ...
    
    @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();
        }
    }
    
    <!-- Exception translation bean post processor -->
    <bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
    
    <bean id="myProductDao" class="product.ProductDaoImpl"/>