繁体   English   中英

Spring中的自定义@Unique验证器抛出休眠声明失败

[英]Custom @Unique validator in Spring throws Hibernate Assertion failure

我制作了一个自定义@UniqueNombre验证器,以检查数据库中是否已存在用户名,当不重复用户名并尝试保留数据时,它会引发Hibernate异常:

ERROR org.hibernate.AssertionFailure - HHH000099: an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session): org.hibernate.AssertionFailure: null id in es.cesga.cloudpyme2.openinnovation.Usuario entry (don't flush the Session after an exception occurs)

验证器的代码为:

public class UniqueNombreValidator implements ConstraintValidator<UniqueNombre, String> {

    @Override
    public void initialize(UniqueNombre paramA) {
    }

    @Override
    public boolean isValid(String nombre, ConstraintValidatorContext ctx) {
        return (Usuario.countFindUsuariosByNombreEquals(nombre) == 0);
    }

}

和控制器:

@RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String create(@Valid Usuario usuario, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
    if (bindingResult.hasErrors()) {
        populateEditForm(uiModel, usuario);
        return "usuario/create";
    }
    uiModel.asMap().clear();
    setUpUsuario(usuario, httpServletRequest);
    usuario.persist();
    return "redirect:/usuario/" + encodeUrlPathSegment(usuario.getIdUsuario().toString(), httpServletRequest);
}

如果不检查重复的用户名,则控制器的工作方式就像魅力。 有任何想法吗?

更新:这是在验证器中使用的方法:

public static Long Usuario.countFindUsuariosByNombreEquals(String nombre) {
    if (nombre == null || nombre.length() == 0) throw new IllegalArgumentException("The nombre argument is required");
    EntityManager em = Usuario.entityManager();
    TypedQuery q = em.createQuery("SELECT COUNT(o) FROM Usuario AS o WHERE o.nombre = :nombre", Long.class);
    q.setParameter("nombre", nombre);
    return ((Long) q.getSingleResult());
}

我不确定没有完整的堆栈跟踪,但是看起来您正在尝试在事务外部使用EntityManager Usuario类中将其声明为静态,然后通过静态方法进行调用。 但是除非您在控制器中声明了一个事务(这是罕见的), em.createQuery(...)在调用em.createQuery(...)时不会打开任何em.createQuery(...) ,因此Hibernate会引发异常。

因为您只做只读操作,所以一个简单的解决方法是将打开的会话以 OpenSessionInViewFilter 模式OpenSessionInViewFilter一起使用。 它允许整个请求处理期间(通常是只读的)会话是不负责任的。

我认为您的验证程序会在为实体分配了适当的标识符值之前触发,因此您遇到了异常。

我不建议在验证器中运行查询。 无论如何,数据库总是会更好地执行这种类型的规则。 您的应用程序逻辑应尝试避免此类情况,因此第一步是在保存数据之前运行查询。

应该尽快将异常报告给用户,以防止失败的事务可能丢失的其他操作。 会话引发异常后,您就不能再使用它,因为无论如何它都可能处于不一致状态。

出于某种原因必须成为习俗吗? 不能仅使用独特的约束? 您可以在脚本中放置或添加注释

   @Column(name = "usuario",unique=true)
   String usuario;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM