我在我的应用程序上下文中使用基于弹簧的验证与hibernate验证器结合使用:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
....
<property name="jpaPropertyMap">
<map>
<entry key="javax.persistence.validation.factory" value-ref="validator" />
</map>
</property>
</bean>
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
我已经实现了一个自定义验证器,它使用弹簧注入的DAO访问数据库以检查特定对象的有效性约束。这会导致java.lang.StackOverflowError,因为每次从验证器中从数据库加载对象时都会调用验证,从而导致无限循环。为了解决这个问题,我尝试在我的实体管理器上设置刷新模式,使用以下代码在验证器中提交:
entityManager.setFlushMode(FlushModeType.COMMIT);
这导致hibernate的“集合不是由flush()处理”异常。
是否有一个从自定义验证器访问数据库的最佳实践示例,这将允许我解决这两个问题?
答案 0 :(得分:1)
经过多次实验,看来最好的方法是直接在代码中使用EntityManagerFactory。在验证器类的initialize(...)方法中,我有以下代码:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("pu_name");
entityManager = emf.createEntityManager();
缺点是您没有获得Spring的DI功能,但您仍然可以访问数据库。
答案 1 :(得分:0)
我也遇到过这个问题,这是我解决它的方法: @Autowired bean works with @Valid on controller but fails with CRUD repository
简而言之,我也得到了EntityManagerFactory
对象的引用。但是,在调用我的服务方法之前,我将setFlushMode
设置为FlushModeType.COMMIT
。最后我将其设置回FlushModeType.AUTO
:
以下是一个例子:
public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {
@PersistenceContext
private EntityManager em;
@Autowired
UserService userService;
@Override
public void initialize(UniqueUsername constraintAnnotation) {
}
@Override
public boolean isValid(String username, ConstraintValidatorContext context) {
try {
em.setFlushMode(FlushModeType.COMMIT);
return userService.findByUsername(username) == null;
} finally {
em.setFlushMode(FlushModeType.AUTO);
}
}
}