基于Hibernate的动态查询(HQL、Criteria、DetachedCriteria、MySQL)
2016-03-11 11:46
971 查看
概述
动态查询是指系统根据前端传递的参数,自动生成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
相关文章推荐
- MySQL中的integer 数据类型
- MySQL存储过程
- mysql中int、bigint、smallint 和 tinyint的区别与长度
- mysql load data 导出、导入 csv
- source命令执行SQL脚本文件
- MySQL创建用户及权限控制
- MySQL管理数据表
- linux下mysql添加用户
- mysql procedure
- mysql触发器
- MySQL 备份和恢复策略
- mac下安装mysql(转载)
- mysql 修改编码 Linux/Mac/Unix/通用(杜绝修改后无法启动的情况!)
- MySQL数据的导出、导入(mysql内部命令:mysqldump、mysql)
- mysql数据行转列
- Linux下修改MySQL编码的方法
- MySQL Server 日志
- MySQL 安全事宜
- MySQL 备份与恢复