我有一个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
类型,这是一个非常普遍的例外。理想情况下,我想捕获一个异常,告诉我该错误是由于一个唯一的约束违规。因此,我有几个问题:
javax.persistence.PersistenceException
类型是正确的,还是因为Spring异常翻译没有开始?我可以配置Spring以减少一般异常,例如DuplicateKeyException?e.getCause()
更好?我可以轻松地做到这一点,但出于两个原因,这对我来说似乎并不合适;首先,代码似乎更脆弱&#34;对我来说,其次,我还必须检查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();
}
}
提前谢谢!
答案 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。