hibernate下SQLQuery返回BigInteger而不是Long的问题

    使用数据库为mysql5.1.6,hibernate版本为4.3.11.Final。
    遇到问题:在使用hibernate的SQLQuery执行sql查询时,执行count语句或者查询数据库中的bigint(20)类型数据,返回的BigInteger类型,不是Long类型。然而在使用hibernate的Query执行hql查询时,返回的都是Long类型。甚至于使用原生的JDBC方法,获取的结果类型也是Long类型。代码如下:
    User类
@Entity
@Table(name = "user", catalog = "newsclient_hnxxt", uniqueConstraints = @UniqueConstraint(columnNames = {
        "schoolId", "userId" }))
public class User implements java.io.Serializable {
 
    // Fields
 
    private Long userId;
    private String username;
    private String name;
    private String password;
    private String mobile;
    private Integer schoolId;
    private String orderType;
    private String role;
    private Integer status;
    private Timestamp createTime;
    private Timestamp updateTime;
    private Timestamp loginTime;
    private Date expireTime;
     
    private String schoolName;
    
    //省略constructor,省略getter、setter,shoolName是临时属性@Transient
}

    dao层
    count方法:
/**
     * 执行sql count查询
     * @param sql
     * @param values
     * @return
     */
    protected long countSqlResult(final String sql, final Map<String, ?> values) {
        String countSql = prepareCountSql(sql);
        //Hibernate Query执行count,返回结果类型为Long,而SQLQuery执行count返回类型为BigInter????
        Long count = (Long)createSQLQuery(countSql, values).uniqueResult();
        return count;
    }

    findPage方法:
/**
     * 按sql分页查询.
     * 
     * @param page 分页参数.
     * @param sql sql语句.
     * @param values 命名参数,按名称绑定.
     * 
     * @return 分页查询结果, 附带结果列表及所有查询输入参数.
     */
    @SuppressWarnings("unchecked")
    public <X> Page<X> findPage(Class<X> clasz,final Page<X> page, final String sql, final Map<String, ?> values) {
        Assert.notNull(page, "page不能为空");
 
        Query q = createSQLQuery(sql, values);
        if ("Map".equals(clasz.getSimpleName())) {
            q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
        } else {
            q.setResultTransformer(Transformers.aliasToBean(clasz));
        }
 
        if (page.isAutoCount()) {
            long totalCount = countSqlResult(sql, values);
            page.setTotalCount(totalCount);
        }
 
        setPageParameterToQuery(q, page);
 
        List result = q.list();
        page.setResult(result);
        return page;
    }

    service层
    测试调用方法:
public Page<User> findPage(Page<User> page) {
        StringBuffer sb = new StringBuffer();
        sb.append("select u.userId, s.name as schoolName ");
        sb.append("from User u, School s ");
        sb.append("where u.schoolId = s.id and u.userId = 13323712806");
        Map<String, Object> params = null;
        return userDao.findPage(User.class, page, sb.toString(), params);
    }

    count报错信息
java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.Long

    findPage报错
IllegalArgumentException occurred while calling setter for property [com.zlstudy.entity.User.userId (expected type = java.lang.Long)]; target = [com.zlstudy.entity.User@4c0a66bc], property value = [13323712806]
Caused by: java.lang.IllegalArgumentException: argument type mismatch

    原因及解决方法:
    1、使用addScalar,为查询列指定返回类型
Query q = createSQLQuery(sql, values).addScalar("userId", StandardBasicTypes.LONG);

    这是网上给出的最普遍的解决方法,这样只能针对某个返回类做特殊处理。但是我的findPage方法是在PagingHibernateDao类,作为通用方法,不想针对某个返回类进行特殊处理,否则就不能够通用。
    2、自定义方言类,修改org.hibernate.dialect.Dialect的构造方法,hibernate使用自定义方言类
    查看hibernate的源代码,hibernate对于未指定的返回类型的查询列,会根据ResultSet.getMetaData().getColumnType(...)的sqlType编号匹配相应的类型,匹配的类型放在放在方言类org.hibernate.dialect.Dialect中。
    hibernate部分源码:
    org.hibernate.loader.Loader.class类
       
   
/**
     * Execute given <tt>PreparedStatement</tt>, advance to the first result and return SQL <tt>ResultSet</tt>.
     */
    protected final ResultSet getResultSet(
            final PreparedStatement st,
            final RowSelection selection,
            final LimitHandler limitHandler,
            final boolean autodiscovertypes,
            final SessionImplementor session)
    throws SQLException, HibernateException {
 
        try {
            ResultSet rs = session.getTransactionCoordinator().getJdbcCoordinator().getResultSetReturn().extract( st );
            rs = wrapResultSetIfEnabled( rs , session );
 
            if ( !limitHandler.supportsLimitOffset() || !LimitHelper.useLimit( limitHandler, selection ) ) {
                advance( rs, selection );
            }
 
            if ( autodiscovertypes ) {
                autoDiscoverTypes( rs );
            }
            return rs;
        }
        catch ( SQLException sqle ) {
            session.getTransactionCoordinator().getJdbcCoordinator().release( st );
            throw sqle;
        }
    }

    该方法执行PreparedStatement,通过autoDiscoverTypes( rs )方法自动匹配查询列的类型。
    org.hibernate.loader.custom.JdbcResultMetadata类:
   
public Type getHibernateType(int columnPos) throws SQLException {
        int columnType = resultSetMetaData.getColumnType( columnPos );
        int scale = resultSetMetaData.getScale( columnPos );
        int precision = resultSetMetaData.getPrecision( columnPos );
 
        int length = precision;
        if ( columnType == Types.CHAR && precision == 0 ) {
            length = resultSetMetaData.getColumnDisplaySize( columnPos );
        }
 
        return factory.getTypeResolver().heuristicType(
                factory.getDialect().getHibernateTypeName(
                        columnType,
                        length,
                        precision,
                        scale
                )
        );
    }

    org.hibernate.dialect.Dialect类
   
// register hibernate types for default use in scalar sqlquery type auto detection
        registerHibernateType( Types.BIGINT, StandardBasicTypes.BIG_INTEGER.getName() );

    hibernate将java.sql.Types.BIGINT对应为StandardBasicTypes.BIG_INTEGER。
    自定义Dialect类,修改java.sql.Types.BIGINT对应的hibernate类型,然后hibernate使用自定义的Dialect。    
public class LocalMySQL5InnoDBDialect extends MySQL5InnoDBDialect {
     
    public LocalMySQL5InnoDBDialect() {
        super();
        registerHibernateType( Types.BIGINT, StandardBasicTypes.LONG.getName() );
    }
}

    自定义Dialect类,修改了hibernate框架本身的类型匹配,目前还未测试出对于其他地方有什么影响,也许这种修改会给自己挖个坑。

你可能感兴趣的:(Hibernate,mysql)