mysql in 动态sql,使用建造者模式构建动态SQL语句

本节来看一个实战案例,这个案例参考了开源框架 JPA 的 SQL 构造模式。

实际应用中,在构造 SQL 查询条件的时候,需要根据不同的条件来拼接 SQL 字符串。如果查询条件复杂,SQL 拼接的过程也会变得非常复杂,从而给代码维护带来非常大的困难。

下面我们用建造者类 QueryRuleSqlBuilder 将复杂的 SQL 构造过程进行封装,用 QueryRule 对象专门保存 SQL 查询时的条件,最后根据查询条件,自动生成 SQL 语句。

首先创建 QueryRule 类,代码如下。

import java.io.Serializable;

import java.util.ArrayList;

import java.util.List;

/**

* QueryRule 主要功能用于构造查询条件

*/

public final class QueryRule implements Serializable {

private static final long serialVersionUID = 1L;

public static final int ASC_ORDER = 101;

public static final int DESC_ORDER = 102;

public static final int LIKE = 1;

public static final int IN = 2;

public static final int NOTIN = 3;

public static final int BETWEEN = 4;

public static final int EQ = 5;

public static final int NOTEQ = 6;

public static final int GT = 7;

public static final int GE = 8;

public static final int LT = 9;

public static final int LE = 10;

public static final int ISNULL = 11;

public static final int ISNOTNULL = 12;

public static final int ISEMPTY = 13;

public static final int ISNOTEMPTY = 14;

public static final int AND = 201;

public static final int OR = 202;

private List ruleList = new ArrayList();

private List queryRuleList = new ArrayList();

private String propertyName;

private QueryRule() {

}

private QueryRule(String propertyName) {

this.propertyName = propertyName;

}

public static QueryRule getInstance() {

return new QueryRule();

}

/**

* 添加升序规则

*

* @param propertyName

* @return

*/

public QueryRule addAscOrder(String propertyName) {

this.ruleList.add(new Rule(ASC_ORDER, propertyName));

return this;

}

/**

* 添加降序规则

*

* @param propertyName

*/

public QueryRule addDescOrder(String propertyName) {

this.ruleList.add(new Rule(DESC_ORDER, propertyName));

return this;

}

public QueryRule andIsNull(String propertyName) {

this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(AND));

return this;

}

public QueryRule andIsNotNull(String propertyName) {

this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(AND));

return this;

}

public QueryRule andIsEmpty(String propertyName) {

this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(AND));

return this;

}

public QueryRule andIsNotEmpty(String propertyName) {

this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(AND));

return this;

}

public QueryRule andLike(String propertyName, Object value) {

this.ruleList.add(new Rule(LIKE, propertyName, new Object[]{value}).setAndOr(AND));

return this;

}

public QueryRule andEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(EQ, propertyName, new Object[]{value}).setAndOr(AND));

return this;

}

public QueryRule andBetween(String propertyName, Object... values) {

this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(AND));

return this;

}

public QueryRule andIn(String propertyName, List values) {

this.ruleList.add(new Rule(IN, propertyName, new Object[]{values}).setAndOr(AND));

return this;

}

public QueryRule andIn(String propertyName, Object... values) {

this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(AND));

return this;

}

public QueryRule andNotIn(String propertyName, List values) {

this.ruleList.add(new Rule(NOTIN, propertyName, new Object[]{values}).setAndOr(AND));

return this;

}

public QueryRule orNotIn(String propertyName, Object... values) {

this.ruleList.add(new Rule(NOTIN, propertyName, values).setAndOr(OR));

return this;

}

public QueryRule andNotEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[]{value}).setAndOr(AND));

return this;

}

public QueryRule andGreaterThan(String propertyName, Object value) {

this.ruleList.add(new Rule(GT, propertyName, new Object[]{value}).setAndOr(AND));

return this;

}

public QueryRule andGreaterEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(GE, propertyName, new Object[]{value}).setAndOr(AND));

return this;

}

public QueryRule andLessThan(String propertyName, Object value) {

this.ruleList.add(new Rule(LT, propertyName, new Object[]{value}).setAndOr(AND));

return this;

}

public QueryRule andLessEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(LE, propertyName, new Object[]{value}).setAndOr(AND));

return this;

}

public QueryRule orIsNull(String propertyName) {

this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(OR));

return this;

}

public QueryRule orIsNotNull(String propertyName) {

this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(OR));

return this;

}

public QueryRule orIsEmpty(String propertyName) {

this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(OR));

return this;

}

public QueryRule orIsNotEmpty(String propertyName) {

this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(OR));

return this;

}

public QueryRule orLike(String propertyName, Object value) {

this.ruleList.add(new Rule(LIKE, propertyName, new Object[]{value}).setAndOr(OR));

return this;

}

public QueryRule orEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(EQ, propertyName, new Object[]{value}).setAndOr(OR));

return this;

}

public QueryRule orBetween(String propertyName, Object... values) {

this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(OR));

return this;

}

public QueryRule orIn(String propertyName, List values) {

this.ruleList.add(new Rule(IN, propertyName, new Object[]{values}).setAndOr(OR));

return this;

}

public QueryRule orIn(String propertyName, Object... values) {

this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(OR));

return this;

}

public QueryRule orNotEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[]{value}).setAndOr(OR));

return this;

}

public QueryRule orGreaterThan(String propertyName, Object value) {

this.ruleList.add(new Rule(GT, propertyName, new Object[]{value}).setAndOr(OR));

return this;

}

public QueryRule orGreaterEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(GE, propertyName, new Object[]{value}).setAndOr(OR));

return this;

}

public QueryRule orLessThan(String propertyName, Object value) {

this.ruleList.add(new Rule(LT, propertyName, new Object[]{value}).setAndOr(OR));

return this;

}

public QueryRule orLessEqual(String propertyName, Object value) {

this.ruleList.add(new Rule(LE, propertyName, new Object[]{value}).setAndOr(OR));

return this;

}

public List getRuleList() {

return this.ruleList;

}

public List getQueryRuleList() {

return this.queryRuleList;

}

public String getPropertyName() {

return this.propertyName;

}

protected class Rule implements Serializable {

private static final long serialVersionUID = 1L;

private int type; //规则的类型

private String property_name;

private Object[] values;

private int andOr = AND;

public Rule(int paramInt, String paramString) {

this.property_name = paramString;

this.type = paramInt;

}

public Rule(int paramInt, String paramString,

Object[] paramArrayOfObject) {

this.property_name = paramString;

this.values = paramArrayOfObject;

this.type = paramInt;

}

public Rule setAndOr(int andOr) {

this.andOr = andOr;

return this;

}

public int getAndOr() {

return this.andOr;

}

public Object[] getValues() {

return this.values;

}

public int getType() {

return this.type;

}

public String getPropertyName() {

return this.property_name;

}

}

}

然后创建 QueryRuleSqlBuilder 类,代码如下:

import builder.QueryRule.Rule;

import org.apache.commons.lang3.ArrayUtils;

import org.springframework.util.StringUtils;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/**

* 根据QueryRule自动构建sql语句

*/

public class QueryRuleSqlBuilder {

private int CURR_INDEX = 0; //记录参数所在的位置

private List properties; //保存列名列表

private List values; //保存参数值列表

private List orders; //保存排序规则列表

private String whereSql = "";

private String orderSql = "";

private Object[] valueArr = new Object[]{};

private Map valueMap = new HashMap();

/**

* 或得查询条件

*

* @return

*/

private String getWhereSql() {

return this.whereSql;

}

/**

* 获得排序条件

*

* @return

*/

private String getOrderSql() {

return this.orderSql;

}

/**

* 获得参数值列表

*

* @return

*/

public Object[] getValues() {

return this.valueArr;

}

/**

* 获取参数列表

*

* @return

*/

private Map getValueMap() {

return this.valueMap;

}

/**

* 创建SQL构造器

*

* @param queryRule

*/

public QueryRuleSqlBuilder(QueryRule queryRule) {

CURR_INDEX = 0;

properties = new ArrayList();

values = new ArrayList();

orders = new ArrayList();

for (QueryRule.Rule rule : queryRule.getRuleList()) {

switch (rule.getType()) {

case QueryRule.BETWEEN:

processBetween(rule);

break;

case QueryRule.EQ:

processEqual(rule);

break;

case QueryRule.LIKE:

processLike(rule);

break;

case QueryRule.NOTEQ:

processNotEqual(rule);

break;

case QueryRule.GT:

processGreaterThen(rule);

break;

case QueryRule.GE:

processGreaterEqual(rule);

break;

case QueryRule.LT:

processLessThen(rule);

break;

case QueryRule.LE:

processLessEqual(rule);

break;

case QueryRule.IN:

processIN(rule);

break;

case QueryRule.NOTIN:

processNotIN(rule);

break;

case QueryRule.ISNULL:

processIsNull(rule);

break;

case QueryRule.ISNOTNULL:

processIsNotNull(rule);

break;

case QueryRule.ISEMPTY:

processIsEmpty(rule);

break;

case QueryRule.ISNOTEMPTY:

processIsNotEmpty(rule);

break;

case QueryRule.ASC_ORDER:

processOrder(rule);

break;

case QueryRule.DESC_ORDER:

processOrder(rule);

break;

default:

throw new IllegalArgumentException("type " + rule.getType() + " not supported.");

}

}

//拼装where语句

appendWhereSql();

//拼装排序语句

appendOrderSql();

//拼装参数值

appendValues();

}

/**

* 去掉order

*

* @param sql

* @return

*/

private String removeOrders(String sql) {

Pattern p = Pattern.compile("order\\s*by[\\w|\\W|\\s|\\S]*", Pattern.CASE_INSENSITIVE);

Matcher m = p.matcher(sql);

StringBuffer sb = new StringBuffer();

while (m.find()) {

m.appendReplacement(sb, "");

}

m.appendTail(sb);

return sb.toString();

}

/**

* 去掉select

*

* @param sql

* @return

*/

private String removeSelect(String sql) {

if (sql.toLowerCase().matches("from\\s+")) {

int beginPos = sql.toLowerCase().indexOf("from");

return sql.substring(beginPos);

} else {

return sql;

}

}

/**

* 处理like

*

* @param rule

*/

private void processLike(QueryRule.Rule rule) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

Object obj = rule.getValues()[0];

if (obj != null) {

String value = obj.toString();

if (!StringUtils.isEmpty(value)) {

value = value.replace('*', '%');

obj = value;

}

}

add(rule.getAndOr(), rule.getPropertyName(), "like", "%" + rule.getValues()[0] + "%");

}

/**

* 处理between

*

* @param rule

*/

private void processBetween(QueryRule.Rule rule) {

if ((ArrayUtils.isEmpty(rule.getValues()))

|| (rule.getValues().length < 2)) {

return;

}

add(rule.getAndOr(), rule.getPropertyName(), "", "between", rule.getValues()[0], "and");

add(0, "", "", "", rule.getValues()[1], "");

}

/**

* 处理 =

*

* @param rule

*/

private void processEqual(QueryRule.Rule rule) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

add(rule.getAndOr(), rule.getPropertyName(), "=", rule.getValues()[0]);

}

/**

* 处理 <>

*

* @param rule

*/

private void processNotEqual(QueryRule.Rule rule) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

add(rule.getAndOr(), rule.getPropertyName(), "<>", rule.getValues()[0]);

}

/**

* 处理 >

*

* @param rule

*/

private void processGreaterThen(

QueryRule.Rule rule) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

add(rule.getAndOr(), rule.getPropertyName(), ">", rule.getValues()[0]);

}

/**

* 处理>=

*

* @param rule

*/

private void processGreaterEqual(

QueryRule.Rule rule) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

add(rule.getAndOr(), rule.getPropertyName(), ">=", rule.getValues()[0]);

}

/**

* 处理<

*

* @param rule

*/

private void processLessThen(QueryRule.Rule rule) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

add(rule.getAndOr(), rule.getPropertyName(), "

}

/**

* 处理<=

*

* @param rule

*/

private void processLessEqual(

QueryRule.Rule rule) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

add(rule.getAndOr(), rule.getPropertyName(), "<=", rule.getValues()[0]);

}

/**

* 处理 is null

*

* @param rule

*/

private void processIsNull(QueryRule.Rule rule) {

add(rule.getAndOr(), rule.getPropertyName(), "is null", null);

}

/**

* 处理 is not null

*

* @param rule

*/

private void processIsNotNull(QueryRule.Rule rule) {

add(rule.getAndOr(), rule.getPropertyName(), "is not null", null);

}

/**

* 处理 <>''

*

* @param rule

*/

private void processIsNotEmpty(QueryRule.Rule rule) {

add(rule.getAndOr(), rule.getPropertyName(), "<>", "''");

}

/**

* 处理 =''

*

* @param rule

*/

private void processIsEmpty(QueryRule.Rule rule) {

add(rule.getAndOr(), rule.getPropertyName(), "=", "''");

}

/**

* 处理in和not in

*

* @param rule

* @param name

*/

private void inAndNotIn(QueryRule.Rule rule, String name) {

if (ArrayUtils.isEmpty(rule.getValues())) {

return;

}

if ((rule.getValues().length == 1) && (rule.getValues()[0] != null)

&& (rule.getValues()[0] instanceof List)) {

List list = (List) rule.getValues()[0];

if ((list != null) && (list.size() > 0)) {

for (int i = 0; i < list.size(); i++) {

if (i == 0 && i == list.size() - 1) {

add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list.get(i), ")");

} else if (i == 0 && i < list.size() - 1) {

add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list.get(i), "");

}

if (i > 0 && i < list.size() - 1) {

add(0, "", ",", "", list.get(i), "");

}

if (i == list.size() - 1 && i != 0) {

add(0, "", ",", "", list.get(i), ")");

}

}

}

} else {

Object[] list = rule.getValues();

for (int i = 0; i < list.length; i++) {

if (i == 0 && i == list.length - 1) {

add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list[i], ")");

} else if (i == 0 && i < list.length - 1) {

add(rule.getAndOr(), rule.getPropertyName(), "", name + " (", list[i], "");

}

if (i > 0 && i < list.length - 1) {

add(0, "", ",", "", list[i], "");

}

if (i == list.length - 1 && i != 0) {

add(0, "", ",", "", list[i], ")");

}

}

}

}

/**

* 处理 not in

*

* @param rule

*/

private void processNotIN(QueryRule.Rule rule) {

inAndNotIn(rule, "not in");

}

/**

* 处理 in

*

* @param rule

*/

private void processIN(QueryRule.Rule rule) {

inAndNotIn(rule, "in");

}

/**

* 处理 order by

*

* @param rule 查询规则

*/

private void processOrder(Rule rule) {

switch (rule.getType()) {

case QueryRule.ASC_ORDER:

// propertyName非空

if (!StringUtils.isEmpty(rule.getPropertyName())) {

orders.add(Order.asc(rule.getPropertyName()));

}

break;

case QueryRule.DESC_ORDER:

// propertyName非空

if (!StringUtils.isEmpty(rule.getPropertyName())) {

orders.add(Order.desc(rule.getPropertyName()));

}

break;

default:

break;

}

}

/**

* 加入到sql查询规则队列

*

* @param andOr and 或者 or

* @param key 列名

* @param split 列名与值之间的间隔

* @param value 值

*/

private void add(int andOr, String key, String split, Object value) {

add(andOr, key, split, "", value, "");

}

/**

* 加入到sql查询规则队列

*

* @param andOr and 或则 or

* @param key 列名

* @param split 列名与值之间的间隔

* @param prefix 值前缀

* @param value 值

* @param suffix 值后缀

*/

private void add(int andOr, String key, String split, String prefix, Object value, String suffix) {

String andOrStr = (0 == andOr ? "" : (QueryRule.AND == andOr ? " and " : " or "));

properties.add(CURR_INDEX, andOrStr + key + " " + split + prefix + (null != value ? " ? " : " ") + suffix);

if (null != value) {

values.add(CURR_INDEX, value);

CURR_INDEX++;

}

}

/**

* 拼装 where 语句

*/

private void appendWhereSql() {

StringBuffer whereSql = new StringBuffer();

for (String p : properties) {

whereSql.append(p);

}

this.whereSql = removeSelect(removeOrders(whereSql.toString()));

}

/**

* 拼装排序语句

*/

private void appendOrderSql() {

StringBuffer orderSql = new StringBuffer();

for (int i = 0; i < orders.size(); i++) {

if (i > 0 && i < orders.size()) {

orderSql.append(",");

}

orderSql.append(orders.get(i).toString());

}

this.orderSql = removeSelect(removeOrders(orderSql.toString()));

}

/**

* 拼装参数值

*/

private void appendValues() {

Object[] val = new Object[values.size()];

for (int i = 0; i < values.size(); i++) {

val[i] = values.get(i);

valueMap.put(i, values.get(i));

}

this.valueArr = val;

}

public String builder(String tableName) {

String ws = removeFirstAnd(this.getWhereSql());

String whereSql = ("".equals(ws) ? ws : (" where " + ws));

String sql = "select * from " + tableName + whereSql;

Object[] values = this.getValues();

String orderSql = this.getOrderSql();

orderSql = (StringUtils.isEmpty(orderSql) ? " " : (" order by " + orderSql));

sql += orderSql;

return sql;

}

private String removeFirstAnd(String sql) {

if (StringUtils.isEmpty(sql)) {

return sql;

}

return sql.trim().toLowerCase().replaceAll("^\\s*and", "") + " ";

}

}

接着创建 Order 类,代码如下:

/**

* sql排序组件

*/

public class Order {

private boolean ascending; //升序还是降序

private String propertyName; //哪个字段升序,哪个字段降序

public String toString() {

return propertyName + ' ' + (ascending ? "asc" : "desc");

}

/**

* Constructor for Order.

*/

protected Order(String propertyName, boolean ascending) {

this.propertyName = propertyName;

this.ascending = ascending;

}

/**

* Ascending order

*

* @param propertyName

* @return Order

*/

public static Order asc(String propertyName) {

return new Order(propertyName, true);

}

/**

* Descending order

*

* @param propertyName

* @return Order

*/

public static Order desc(String propertyName) {

return new Order(propertyName, false);

}

}

最后编写客户端测试代码,如下:

/**

* Created by C语言中文网.

*/

public class Test {

public static void main(String[] args) {

QueryRule queryRule = QueryRule.getInstance();

queryRule.addAscOrder("age")

.andEqual("addr", "HeBei")

.andLike("name", "C语言中文网")

.andGreaterEqual("age", 18);

QueryRuleSqlBuilder builder = new QueryRuleSqlBuilder(queryRule);

System.out.println(builder.builder("t_member"));

System.out.println("Params: " + Arrays.toString(builder.getValues()));

}

}

这样一来,客户端代码就非常清楚了,运行结果如下所示:

select * from t_member where addr = ? and name like ? order by age asc

Params: [HeBei, %C语言中文网%]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值