我有一个情况。我正在创建一个Spring Boot项目来与一堆传统的OpenJPA实体进行交互。
问题在于,因为Spring Boot Starter Data JPA使用Hibernate作为基础,所以Spring应用程序抛出Hibernate异常,如:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]
: Invocation of init method failed; nested exception is org.hibernate.AnnotationException:
Using default @DiscriminatorValue for a discriminator of type CHAR is not safe
现在,虽然可以通过更新实体代码轻松修复,但我们无法触及或更改该代码。我们必须保持原样 - 不符合Hibernate标准。
那么,在Spring中是否有任何方法来禁用这样的Hibernate异常,所以我们可以接受不符合Hibernate标准的实体并抛出Hibernate异常?
我们的代码设计很简单,是一个标准的Service-Repository设置。例如:
PersonRepository.java:
public interface PersonRepository extends CrudRepository<Person, Long> {
Person findFirstByPersonSsnSsn(String ssn);
Person findFirstByPersonId(Integer personId);
}
PersonDomainService.java:
public interface PersonDomainService {
Person findPersonBySsn(String ssn);
public Person findPerson(Integer id);
}
PersonDomainServiceImpl.java:
@Service
@Transactional
public class PersonDomainServiceImpl implements PersonDomainService {
private PersonRepository personRepository;
@Autowired
public PersonDomainServiceImpl(PersonRepository personRepository) {
this.personRepository = personRepository;
}
@Transactional(readOnly=true)
public Person findPersonBySsn(String ssn) {
Person person = personRepository.findFirstByPersonSsnSsn(ssn);
System.out.println(person.getAddresses().size());
System.out.println(person.getPhones().size());
return person;
}
@Transactional(readOnly=true)
public Person findPerson(Integer id) {
// TODO Auto-generated method stub
Person person = personRepository.findFirstByPersonId(id);
System.out.println(person.getAddresses().size());
System.out.println(person.getPhones().size());
return person;
}
}
实体非常标准:
@Entity
@Table(name = "PERSON", schema = "SCHEMA")
public class Person implements Serializable, EntityWithAuditInfo {
...
答案 0 :(得分:0)
异常表明hibernate拒绝初始化自身,所以这不是一个异常处理问题,但你必须以某种方式说服hibernate初始化,即使它觉得鉴别器是危险的&#34;
搜索hibernate's source code会发现此异常为thrown at
public void bindDiscriminatorValue() {
if ( StringHelper.isEmpty( discriminatorValue ) ) {
Value discriminator = persistentClass.getDiscriminator();
if ( discriminator == null ) {
persistentClass.setDiscriminatorValue( name );
}
else if ( "character".equals( discriminator.getType().getName() ) ) {
throw new AnnotationException(
"Using default @DiscriminatorValue for a discriminator of type CHAR is not safe"
);
}
else if ( "integer".equals( discriminator.getType().getName() ) ) {
persistentClass.setDiscriminatorValue( String.valueOf( name.hashCode() ) );
}
else {
persistentClass.setDiscriminatorValue( name ); //Spec compliant
}
}
else {
//persistentClass.getDiscriminator()
persistentClass.setDiscriminatorValue( discriminatorValue );
}
}
正如您所看到的,如果没有为char类型的鉴别器提供discriminatorValue,则hibernate将始终抛出此类异常。没有办法防止改变hibernate的源代码。
此方法is invoked from:
public void bindEntity() {
persistentClass.setAbstract( annotatedClass.isAbstract() );
persistentClass.setClassName( annotatedClass.getName() );
persistentClass.setJpaEntityName(name);
//persistentClass.setDynamic(false); //no longer needed with the Entity name refactoring?
persistentClass.setEntityName( annotatedClass.getName() );
bindDiscriminatorValue();
persistentClass.setLazy( lazy );
if ( proxyClass != null ) {
persistentClass.setProxyInterfaceName( proxyClass.getName() );
}
persistentClass.setDynamicInsert( dynamicInsert );
persistentClass.setDynamicUpdate( dynamicUpdate );
... and 170 more lines of code to parse all other annotations in this class
}
正如我们可以看到缺少一个catch块,如果无法确定鉴别器值,hibernate将中止解析该实体。
因此,当鉴别器的类型为char时,即使最新版本的hibernate也不能与缺少鉴别器值的实体一起使用。 (顺便说一句,在过去的7年里,hibernate团队还没有采取open issue about this行动。
解决此问题的唯一方法是更改实体,更改休眠或使用其他JPA实现。