基于Hibernate的动态查询(HQL、Criteria、DetachedCriteria、MySQL)

概述

动态查询是指系统根据前端传递的参数,自动生成SQL、HQL进行数据查询。现在我用得比较多的是Spring Data 的动态查询,然而前段时间帮人
维护一个比较久远的项目,该项目用Hibernate作为ORM,为了方便我想在Hibernate上实现动态查询。网上搜索了很久,别人贴出的代码要么是
不完整的要么是动能缺失。于是在网上代码的基础上,我进行了调整。途中遇到了几个坑,后来都一一填上。

注:这里给出的代码都是demo级别的,不建议直接用到实际项目中。

项目预览

文件结构

先看看项目文件结构
这里写图片描述

其中动态查询语句的构造在DynamicQuery.java 实现。

测试数据

这里写图片描述
上面的数据是我随机生成的,sql文件已经导出到项目根目录的test_sfz.sql

功能实现

先看看核心代码

/**
     * 返回的是 DetachedCriteria (无需Session的离线Criteria)
     * @param clzss
     * @param map
     * @return
     */
    public static DetachedCriteria build(Class clzss, Map<String,Object> map){
        final DetachedCriteria dc = DetachedCriteria.forClass(clzss);
        Map<String,String> fieldM = buildOrCreateFieldMap(clzss);

        if(map.size()>0){
            for(Iterator<String> keys = map.keySet().iterator(); keys.hasNext();){
                String k=keys.next();
                Object v=map.get(k);
                if(v == null || v.toString().trim().length()==0)
                    continue;

                String t[] = k.split("_");
                if(t.length<2)
                    continue;

                //进行类型转换
                String fieldType=fieldM.get(t[1]);
                if("class java.lang.String".equals(fieldType))
                    try{v = (String)v;}catch (Exception e){}
                else if("int".equals(fieldType) || "class java.lang.Integer".equals(fieldType))
                    try{v = Integer.valueOf((String)v);}catch (Exception e){}
                else if("long".equals(fieldType) || "class java.lang.Long".equals(fieldType))
                    try{v = Long.valueOf((String)v);}catch (Exception e){}
                else if("float".equals(fieldType) || "class java.lang.Float".equals(fieldType))
                    try{v = Float.valueOf((String)v);}catch (Exception e){}
                else if("double".equals(fieldType) || "class java.lang.Bouble".equals(fieldType))
                    try{v = Double.valueOf((String)v);}catch (Exception e){}
                else if("class java.util.Date".equals(fieldType)){
                    try {
                        v = DateUtils.parseDate((String)v, parsePatterns);
                    }catch (Exception e){}
                }


                t[0]=t[0].toUpperCase();
                if(t[0].equals("LIKE")){
                    String like=(String)v;
                    //如果不是以%开头或者结尾,就给前后都加上%
                    if(!(like.startsWith("%")||like.endsWith("%")))
                        like="%"+like+"%";
                    if(t.length==2) dc.add(Restrictions.like(t[1], like));
                    else{
                        Disjunction dis=Restrictions.disjunction();
                        for(int i=1;i<t.length;i++){
                            dis.add(Restrictions.like(t[i], like, MatchMode.ANYWHERE));
                        }
                        dc.add(dis);
                    }
                }else if(t[0].equals("EQ"))
                    dc.add(Restrictions.eq(t[1],v));
                else if(t[0].equals("IN"))
                    dc.add(Restrictions.in(t[1], (Object[])v));
                else if(t[0].equals("GT"))
                    dc.add(Restrictions.gt(t[1], v));
                else if(t[0].equals("GTE"))
                    dc.add(Restrictions.ge(t[1],v));
                else if(t[0].equals("LT"))
                    dc.add(Restrictions.lt(t[1],v));
                else if(t[0].equals("LTE"))
                    dc.add(Restrictions.le(t[1],v));
                else if(t[0].equals("NOT"))
                    dc.add(Restrictions.not(Restrictions.like(t[1],v)));
                else if(t[0].equals("SORT")){
                    if(v.toString().equals("1")||v.toString().equalsIgnoreCase("DESC"))
                        dc.addOrder(Order.desc(t[1]));
                    else
                        dc.addOrder(Order.asc(t[1]));
                }
            }
        }
        return dc;
    }

基本思路是通过对参数的拆分,来区别使用哪种条件限定方法(Like,eq,in,gt,gte,lt,lte等),这里使用了缓存存放实体bean的字段信息。

接着编写测试代码

public class DynamicQueryTest {
    private Session session;

    @Before
    public void init(){
        session= HibernateUtil.currentSession();
    }

    /**
     * 如果想从HttpServletRequest中进行绑定,则将params替换成request.getParameterMap();
     */
    @Test
    public void testQuery(){
        //构造查询条件
        Map<String,Object> params=new HashMap<>();
        params.put("LIKE_name","方%");   //姓方的人
//      params.put("LIKE_address","四川");//家庭地址在四川的人
        params.put("IN_address",new String[]{"福建泉州","云南大理"});
        params.put("GTE_birth","1996-03-11"); //出生日期大于1996-03-11的人
//      params.put("GT_addDate","2016-01-01");  //录入时间

        Result result=query(DynamicQuery.build(IdCard.class, params));

        //打印数据
        result.getDatas().forEach(d->System.out.println(d));
        System.out.println("查询到"+result.getTotal()+"个记录(默认显示前20条记录)");
    }

    private Result query(DetachedCriteria dc){
        Result result=new Result();
        Criteria criteria=dc.getExecutableCriteria(session);
        result.setDatas(criteria
                .setFirstResult(0)
                .setMaxResults(20)
                .list());

        result.setTotal(count(dc.getExecutableCriteria(session)));
        return result;
    }

    private long count(Criteria criteria){
        criteria.setProjection(Projections.rowCount());
        return ((Number) criteria.uniqueResult()).intValue();
    }
}

运行结果
这里写图片描述

详细的代码可以在这里下载git.oschina.net

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

集成显卡

码字不易,需要您的鼓励😄

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值