当前位置: 首页 > 知识库问答 >
问题:

Spring MVC 处理唯一约束冲突

严成礼
2023-03-14

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

@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.
  ...

如您所见,“main”异常属于javax.persistence.PersistenceException类型,这是一个非常普遍的异常。理想情况下,我希望捕获一个异常,该异常告诉我错误是由于唯一的约束违规造成的。因此我有几个问题:

  1. 异常应该是javax.persistence.PersistenceException类型,还是因为Spring异常转换没有启动?我可以配置Spring以提供不太常见的异常吗,例如DuplicateKeyException?
  2. 如果这种行为与缺少异常转换无关,那么您知道有比调用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();
    }
}

提前感谢您!

共有1个答案

王渊
2023-03-14

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

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

'

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

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

'

直接从这里拿走。

还有,你可以看看这个。

嗯。

 类似资料:
  • 我有一个用户创建屏幕,它记录了各种用户详细信息以及名字和手机号码。我有一个对应的用户表,其中名字和手机号码构成一个复合唯一键。此表中还定义了其他完整性约束。 当在创建用户屏幕上输入违反此约束的用户数据时,需要向用户显示“用户友好”错误消息。 当这种违反发生时,我从MySQL数据库中得到的异常是: 有两个选项可以显示有意义的消息(例如:“错误:给定手机号码的用户名已存在,请更改其中一个”)。 选项1

  • 我想用插页。。请务必更新。。对两列具有唯一约束的表的语法。这可能吗? mytable对col1和col2有单独的唯一约束。 我可以写: 然而,这不起作用: 错误:冲突时,更新是否需要推理规范或约束名称 这也不起作用: 错误:不存在与冲突规范匹配的唯一或排除约束 这种语法似乎是为两列上的单一复合唯一约束而设计的,而不是两个约束。 如果违反了其中一个唯一约束,有没有办法进行条件更新?这个问题是如何在博

  • 问题内容: 当违反唯一约束时,将引发a。但是可能有多种原因抛出异常。我如何才能发现违反了唯一约束? 问题答案: 我如何才能发现违反了唯一约束? 异常是链接在一起的,您必须递归调用以获取提供程序特定的异常(并可能转到),以将其转换为应用程序可以很好地为用户处理的内容。下面将打印异常链: 对于异常处理和“翻译”,您可以执行类似于Spring的操作(请参阅各种类,例如,以获取想法)。 所有这些都不是很好

  • 我的桌子有两个独特的列: 我想写保存或更新方法 My jooq code: 但我遇到了异常: “错误:没有唯一或排除约束匹配ON CONFLICT规范” 请帮助。

  • 我有一个实体,比如说雇员 with字段名标记为唯一。 提前谢谢你

  • 主要内容:在创建表时设置唯一约束,在修改表时添加唯一约束,删除唯一约束MySQL 唯一约束(Unique Key)是指所有记录中字段的值不能重复出现。例如,为 id 字段加上唯一性约束后,每条记录的 id 值都是唯一的,不能出现重复的情况。如果其中一条记录的 id 值为‘0001’,那么该表中就不能出现另一条记录的 id 值也为‘0001’。 唯一约束与主键约束相似的是它们都可以确保列的唯一性。不同的是,唯一约束在一个表中可有多个,并且设置唯一约束的列允许有空值,但