将 Hibernate HQL 应用于 H2 时遇到困难

Posted

技术标签:

【中文标题】将 Hibernate HQL 应用于 H2 时遇到困难【英文标题】:Facing difficulty with Hibernate HQL when applying it to H2 【发布时间】:2014-09-15 06:14:03 【问题描述】:

我是 hibernate 和 spring maven 环境的新手。

我尝试使用 H2 实现嵌入式数据库,之前使用的是 mysql。有两个 DAO

OffersDao.java

package com.skam940.main.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Component("offersDao")
@Transactional
public class OffersDao 

    @Autowired
    private SessionFactory sessionFactory;

    public Session session() 
        return sessionFactory.getCurrentSession();
    

    @SuppressWarnings("unchecked")
    public List<Offer> getOffers() 

        Criteria crit = session().createCriteria(Offer.class);
        crit.createAlias("user", "u").add(Restrictions.eq("u.enabled", true));
        return crit.list();

    

    @SuppressWarnings("unchecked")
    public List<Offer> getOffers(String username) 

        Criteria crit = session().createCriteria(Offer.class);
        crit.createAlias("user", "u");

        crit.add(Restrictions.eq("u.enabled", true));
        crit.add(Restrictions.eq("u.username", username));

        return crit.list();

    

    public void saveOrUpdate(Offer offer) 

        session().saveOrUpdate(offer);

    

    public boolean delete(int id) 

        Query query = session().createQuery("delete from Offer where id=:id");
        query.setLong("id", id);
        return query.executeUpdate() == 1;

    

    public Offer getOffer(int id) 

        Criteria crit = session().createCriteria(Offer.class);
        crit.createAlias("user", "u");

        crit.add(Restrictions.eq("u.enabled", true));
        crit.add(Restrictions.idEq(id));

        return (Offer) crit.uniqueResult();

    


和UsersDao.java

package com.skam940.main.dao;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional
@Component("usersDao")
public class UsersDao 

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private SessionFactory sessionFactory;

    public Session session() 
        return sessionFactory.getCurrentSession();
    

    @Transactional
    public void create(User user) 
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        session().save(user);

    

    public boolean exists(String username) 
        Criteria crit = session().createCriteria(User.class);
        crit.add(Restrictions.idEq(username));

        User user = (User) crit.uniqueResult();
        return user != null;

    

    @SuppressWarnings("unchecked")
    public List<User> getAllUsers() 
        return session().createQuery("from User").list();
    


不,我得到了一个例外

HTTP 状态 500 - PreparedStatementCallback;错误的 SQL 语法 [选择用户名、密码,从二进制用户名 = ?的用户启用];嵌套异常是 org.h2.jdbc.JdbcSQLException:找不到列“BINARY”; SQL语句:

我想在这里做的事情是让用户名区分大小写,显然 H2 将 BINARY 识别为表名,但不是类型或你所说的任何东西,谁能告诉哪个方法正在实现这个 SQL语法?

用户.java

 package com.skam940.main.dao;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotBlank;

import com.skam940.main.validation.ValidEmail;

@Entity
@Table(name="users")
public class User 

    @NotBlank(groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    @Size(min=6, max=15, groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    @Pattern(regexp="^\\w8,$", groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    @Id
    @Column(name="username")
    private String username;

    @NotBlank(groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    @Pattern(regexp="^\\S+$", groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    @Size(min=8, max=15, groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    private String password;

    @ValidEmail(groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    private String email;

    @NotBlank(groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    @Size(min=3, max=30, groups=FormValidationGroup.class)
    private String name;

    private boolean enabled = false;
    private String authority;


    public User() 

    

    public User(String username, String name, String password, String email, boolean enabled,
            String authority) 
        this.username = username;
        this.name = name;
        this.password = password;
        this.email = email;
        this.enabled = enabled;
        this.authority = authority;
    

    public String getUsername() 
        return username;
    

    public void setUsername(String username) 
        this.username = username;
    

    public String getPassword() 
        return password;
    

    public void setPassword(String password) 
        this.password = password;
    

    public boolean isEnabled() 
        return enabled;
    

    public void setEnabled(boolean enabled) 
        this.enabled = enabled;
    

    public String getAuthority() 
        return authority;
    

    public void setAuthority(String authority) 
        this.authority = authority;
    

    public String getEmail() 
        return email;
    

    public void setEmail(String email) 
        this.email = email;
    

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    @Override
    public int hashCode() 
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((authority == null) ? 0 : authority.hashCode());
        result = prime * result + ((email == null) ? 0 : email.hashCode());
        result = prime * result + (enabled ? 1231 : 1237);
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result
                + ((username == null) ? 0 : username.hashCode());
        return result;
    

    @Override
    public boolean equals(Object obj) 
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (authority == null) 
            if (other.authority != null)
                return false;
         else if (!authority.equals(other.authority))
            return false;
        if (email == null) 
            if (other.email != null)
                return false;
         else if (!email.equals(other.email))
            return false;
        if (enabled != other.enabled)
            return false;
        if (name == null) 
            if (other.name != null)
                return false;
         else if (!name.equals(other.name))
            return false;
        if (username == null) 
            if (other.username != null)
                return false;
         else if (!username.equals(other.username))
            return false;
        return true;
    

    @Override
    public String toString() 
        return "User [username=" + username + ", email=" + email + ", name="
                + name + ", enabled=" + enabled + ", authority=" + authority
                + "]";
    





Offer.java

package com.skam940.main.dao;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.Size;

@Entity
@Table(name="offers")
public class Offer 

    @Id
    @GeneratedValue
    // because this is an auto increment value
    private int id;

    @Size(min=5, max=255, groups=PersistenceValidationGroup.class, FormValidationGroup.class)
    @Column(name="text")
    private String text;

    // every user can have only one offer
    @ManyToOne
    @JoinColumn(name="username")
    private User user;

    public Offer() 
        this.user = new User();
    

    public Offer(User user, String text) 
        this.user = user;
        this.text = text;
    

    public Offer(int id, User user, String text) 
        this.id = id;
        this.user = user;
        this.text = text;
    

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public String getText() 
        return text;
    

    public void setText(String text) 
        this.text = text;
    

    public User getUser() 
        return user;
    

    public void setUser(User user) 
        this.user = user;
    

    public String getUsername() 
        return user.getUsername();
    

    @Override
    public int hashCode() 
        final int prime = 31;
        int result = 1;
        result = prime * result + ((text == null) ? 0 : text.hashCode());
        result = prime * result + ((user == null) ? 0 : user.hashCode());
        return result;
    

    @Override
    public boolean equals(Object obj) 
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Offer other = (Offer) obj;
        if (text == null) 
            if (other.text != null)
                return false;
         else if (!text.equals(other.text))
            return false;
        if (user == null) 
            if (other.user != null)
                return false;
         else if (!user.equals(other.user))
            return false;
        return true;
    

    @Override
    public String toString() 
        return "Offer [id=" + id + ", text=" + text + ", user=" + user + "]";
    






完整的文件内容在这里-> https://app.box.com/s/c3uq71khbwf05p8asu27

【问题讨论】:

在 exists 方法中 Restrictions.eq 而不是 Restrictions.idEq 不能正常工作(我猜是问题出在哪里)? @geo 我试过了,我认为它已经实现了,因为用户名是外键和主键集成。 不管是不是外键,你所做的只是用它作为标准 你能发布你的 UDT 映射吗? @geoand 我已经尝试改变它,我得到一个错误the method eq(String, Object0 is not applicable for the arguments (String) 【参考方案1】:

此查询来自您的 Spring 安全配置,请检查 security-context.xml,您可以找到使用 authority-by-username-query as 的 Spring 安全身份验证提供程序

select username, authority from users where binary username = ?

此查询使用 MySQL 特定的函数 BINARY 进行区分大小写的比较 (http://gilfster.blogspot.com/2005/08/case-sensitivity-in-mysql.html)。另一方面,H2 默认区分大小写。

尝试改变它

select username, authority from users where username = ?

这同样适用于 users-by-username-query 属性。

【讨论】:

以上是关于将 Hibernate HQL 应用于 H2 时遇到困难的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate命名查询

嵌入式模式下的 h2 并发更新

Hibernate HQL,Criteria和SQL

hibernate之HQL

第九节:Hibernate Hql

Hibernate中Hql的查询