通过Hql、Sql生成Hibernate CountQuery 字符串

当我们在写Hibernate Orm组件的时候,经常会遇到分页查询这种操作,分页查询的原理不在熬述,比较重要的一点是需要计算查询的总数count,大部分人还是采用传统的hql/sql字符串截取或者拼接等方式实现。下面给出的代码是通过字符串模板、正则匹配等方式实现的,直接上代码:

public class QueryTemplateUtil {

 public static final String COUNT_QUERY_STRING = "select count(%s) from %s x";
 public static final String DELETE_ALL_QUERY_STRING = "delete from %s x";

 private static final String COUNT_REPLACEMENT_TEMPLATE = "select count(%s) $5$6$7";
 private static final String SIMPLE_COUNT_VALUE = "$2";
 private static final String COMPLEX_COUNT_VALUE = "$3$6";

 private static final Pattern COUNT_MATCH;

 private static final String IDENTIFIER = "[\\p{Alnum}._$]+";
 private static final String IDENTIFIER_GROUP = String.format("(%s)",
   IDENTIFIER);

 private static final String EQUALS_CONDITION_STRING = "%s.%s = ?";

 static {

  StringBuilder builder = new StringBuilder();
  builder.append("(?<=from)"); // from as starting delimiter
  builder.append("(?: )+"); // at least one space separating
  builder.append(IDENTIFIER_GROUP); // Entity name, can be qualified (any
  builder.append("(?: as)*"); // exclude possible "as" keyword
  builder.append("(?: )+"); // at least one space separating
  builder.append("(\\w*)"); // the actual alias

  builder = new StringBuilder();
  builder.append("(select\\s+((distinct )?(.+?)?)\\s+)?(from\\s+");
  builder.append(IDENTIFIER);
  builder.append("(?:\\s+as)?\\s+)");
  builder.append(IDENTIFIER_GROUP);
  builder.append("(.*)");

  COUNT_MATCH = compile(builder.toString(), CASE_INSENSITIVE);
 }

 /**
  * Private constructor to prevent instantiation.
  */
 private QueryTemplateUtil() {

 }

 /**
  * getCountQueryString:根据实体名称,count字段,查询条件生成count查询字符串
  * <p>
  * <b>例如:</b>{@code entityName="User"},{@code countQueryPlaceHolder="*"},
  * {@code conditionAttributes=["name","sex"]},生成的countQueryString是:
  * </p>
  * <p>
  * {@code select count(*) from User x where x.name=? and x.sex=?}
  * </p>
  *
  * @Title: getCountQueryString
  * @param entityName
  *            实体名称,不允许{@literal null}或者{@literal empty}
  * @param countQueryPlaceHolder
  *            count查询占位字段,不允许{@literal null}或者{@literal empty}
  * @param conditionAttributes
  *            查询条件字段
  * @return String
  */
 public static String getCountQueryString(String entityName,
   String countQueryPlaceHolder, Iterable<String> conditionAttributes) {
  Assert.hasText(entityName, "实体名称不允许为null或empty!");
  StringBuilder sb = new StringBuilder(String.format(COUNT_QUERY_STRING,
    countQueryPlaceHolder, entityName));
  sb.append(" WHERE ");

  if (conditionAttributes != null) {
   for (String conditionAttribute : conditionAttributes) {
    sb.append(String.format(EQUALS_CONDITION_STRING, "x",
      conditionAttribute));
    sb.append(" AND ");
   }
  }

  sb.append("1 = 1");
  return sb.toString();
 }

 /**
  * getCountQueryString:根据实体名称,生成count查询字符串
  * <p>
  * <b>注意:</b>count占位字符默认为{@literal *},不带查询条件
  * </p>
  *
  * @Title: getCountQueryString
  * @param entityName
  *            实体名称,不允许{@literal null}或者{@literal empty}
  * @return {@code select count(*) from SomeEntity x }
  */
 public static String getCountQueryString(String entityName) {
  return getCountQueryString(entityName, "*", null);
 }

 /**
  * getCountQueryString:根据实体名称、查询条件生成count查询字符串
  *
  * @Title: getCountQueryString
  * @param entityName
  *            实体名称,不允许{@literal null}或者{@literal empty}
  * @param conditionAttributes
  *            查询条件字段
  * @return {@code select count(*) from SomeEntity x where condition1=? and condition2=? and 1=1}
  */
 public static String getCountQueryString(String entityName,
   Iterable<String> conditionAttributes) {
  return getCountQueryString(entityName, "*", conditionAttributes);

 }

 /**
  * getQueryString:通过实体名称与查询字符串模板,创建查询字符串
  * <p>
  * <b>参见:</b>{@link org.mk.mini.orm.util.DELETE_ALL_QUERY_STRING}
  * </p>
  *
  * @Title: getQueryStringByTemplate
  * @param template
  *            查询字符串模板
  * @param entityName
  *            实体名称
  * @return 查询字符串
  */
 public static String getQueryStringByTemplate(String template,
   String entityName) {

  Assert.hasText(entityName, "实体名称不允许为null或empty!");

  return String.format(template, entityName);
 }

 /**
  * createCountQueryFor:通过给定的原始sql或hql创建count查询字符串.
  *
  * @Title: createCountQueryFor
  * @param originalQuery
  *            原始查询字符串,支持sql与hql 不能为 {@literal null} 或者 {@literal empty}
  * @return
  */
 public static String createCountQueryFor(String originalQuery) {

  Assert.hasText(originalQuery, "查询字符串不允许为null或empty");

  Matcher matcher = COUNT_MATCH.matcher(originalQuery);
  String variable = matcher.matches() ? matcher.group(4) : null;
  boolean useVariable = ExtraStringUtils.hasText(variable)
    && !variable.startsWith("new")
    && !variable.startsWith("count(");

  return matcher.replaceFirst(String.format(COUNT_REPLACEMENT_TEMPLATE,
    useVariable ? SIMPLE_COUNT_VALUE : COMPLEX_COUNT_VALUE));
 }
}

实例就不用写了,注释已经写的很清楚,关于Assert和ExtraStringUtils只是做了断言判断与字符串判断,需要copy该代码的同学们可以改造一下,写的不好,请指正。

时间: 2024-08-28 07:03:27

通过Hql、Sql生成Hibernate CountQuery 字符串的相关文章

sql 生成唯一随机数字字符串

oracle 实现快速批量生成随机数字字符串: --表 create table RANDOM_NUMBER_TEMP ( ROW_NUM NUMBER default 0 not null, RANDOM_NUM VARCHAR2(30) not null ) --type type number_array_t is table of number index by binary_integer; --实现生成唯一随机数 PROCEDURE INIT_RANDOM_NUMBRE(P_QUAN

Hibernate SQL方言 (hibernate.dialect) Spring配置文件applicationContext.xml

转自:http://www.cnblogs.com/wj-wangjun/archive/2009/10/21/1587624.html Hibernate SQL方言 (hibernate.dialect) 数据库 hibernate方言 DB2 org.hibernate.dialect.DB2Dialect DB2 AS/400 org.hibernate.dialect.DB2400Dialect DB2 OS390 org.hibernate.dialect.DB2390Dialect

【51CTO/BBS】请教: SQL里有没有字符串组合Join的函数??

[51CTO/BBS]请教: SQL里有没有字符串组合Join的函数?? 原帖地址:http://bbs.51cto.com/thread-1133863-1.html 问题描述: VB 中有两个非常好用的字符串处理函数: Split(字符串,分隔符)作用:将[字符串]以[分隔符]作为边界,分解成数组. 返回:一个字符串数组. Join(字符数组,分隔符)作用:将[字符数组]中的元素,以[分隔符]作为边界,连接成一个字符串.返回:一个字符串. 请教老师们,SQL里是否有类似的函数? 解决方案:

MyEclipse 从数据库反向生成Hibernate实体类

第一个大步骤 window-->open Perspective-->MyEclipse Java Persistence 进行了上面的 操作后会出现一个视图DB Brower:MyEclipse Derby,点击右键新建一个在出现的面板中,driver template中选择MySQL的,driver name自己写个随便的,Connection URL就写平常的JDBC中的URL,用户密码也是的,接下来就是add Jars了这个JAR大家很清楚肯定是MYSQL的驱动包了测试下是否可用,可用

SQL生成一年每一天的时间列表的几种方法

工作好几年了,一直没有写博客,准备捡起来... 以下脚本适用环境:SQL SERVER (starting with 2012) 1.构建序列: /*1-1:利用交叉连接,推荐下列这种写法*/ SELECT /*2012 开始已支持OFFSET 语法,不再推荐使用TOP N */ s1.i + s2.i + s3.i + s4.i + s5.i + s6.i + s7.i + s8.i + s9.i AS seq FROM ( SELECT i = 0 UNION ALL SELECT i =

【51CTO/BBS】请教: SQL里有没有字符串分解、组合的函数??

[51CTO/BBS]请教: SQL里有没有字符串分解.组合的函数?? 原帖地址:http://bbs.51cto.com/thread-1133863-1.html 问题描述: VB 中有两个非常好用的字符串处理函数: Split(字符串,分隔符)作用:将[字符串]以[分隔符]作为边界,分解成数组. 返回:一个字符串数组. Join(字符数组,分隔符)作用:将[字符数组]中的元素,以[分隔符]作为边界,连接成一个字符串.返回:一个字符串. 请教老师们,SQL里是否有类似的函数? 解决方案: 如

eclipse从数据库逆向生成Hibernate实体类(eclipse中反向生成hibernate实体类+jpa注释)

eclipse从数据库逆向生成Hibernate实体类 做项目必然要先进行数据库表设计,然后根据数据库设计建立实体类(VO),这是理所当然的,但是到公司里做项目后,让我认识到,没有说既进行完数据库设计后还要再"自己"建立一变VO.意思是,在项目设计时,要么根据需求分析建立实体类,由正向生成数据库表:要么就先进行数据库表设计,再逆向生成实体类.没有说进行完任意一方的设计后再去花时间去自己匹配建立另一方的设计. 原因是: 1. 1.5倍工作量,浪费时间.(时间对公司来说很重要) 2. 无法

Eclipse中通过Hibernate Tools插件实现从数据库逆向生成Hibernate带注解的实体类

一.安装hibernate tools插件 1.在线安装 通过Eclipse的Help->Install New Software 在线安装插件,插件连接为: eclipse helios(3.6)版 添加如下地址:http://download.jboss.org/jbosstools/updates/stable/helios/ 选择性安装:hibernate tools在All Jboss tools节点下面 eclipse indigo(3.7)版 添加如下地址:http://downl

SQL Server中截取字符串常用函数

SQL Server 中截取字符串常用的函数: 1.LEFT ( character_expression , integer_expression ) 函数说明:LEFT ( '源字符串' , '要截取最左边的字符数' ) 返回从字符串左边开始指定个数的字符 select LEFT('SQL_Server_2008',4 ); 返回结果:SQL_ 2.RIGHT ( character_expression , integer_expression ) 函数说明:RIGHT ( '源字符串'