Java Spring MVC处理唯一约束冲突
我有一个SpringMVC应用程序,它使用SpringDataJPA进行持久化,Hibernate作为我的JPA提供程序。我有一个数据库表,在一个列上有一个唯一的约束,因此为什么保存相应的实体可能会导致唯一约束冲突。我想检测这是否发生在我的服务层中,以便我可以向用户提供有意义的错误消息。下面是我的服务方法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
@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"/>