手把手教你寫一個java的orm(五)


生成sql:where

上一篇里我們實現了生成insert的sql,下面要開始實現updatedeleteselect的sql語句了。但是這些語句有一個比較麻煩的地方是:它們一般后面都會有where條件,因為在執行的時候不能把表里所有的數據都進行操作。

所以這里我們需要先生成條件的sql。大概是這樣的:

WHERE id = ? AND name != ? OR age >= ? 

where 后面的參數繼續用 “?” 代替。值就放在一個有序的集合中就好了。類似上一篇提到的insertColumnValues

思路

  1. 條件都是一個一個組成的,我們可以寫一個類用來描述一個條件。
  2. 寫一個工具類來快速的創建條件。
  3. 將多個條件中間用 and 或者 or 組合起來,並在最前方添加 where 就是一個完整的條件。
  4. 最后將這個條件轉成一個字符串,並用一個集合將條件中的值存起來就好了。

實現

第一步

我們實現第一步,在這之前我們先看一下一個條件是有什么組成的,例如:

1: id = ? AND
2: name != ? OR
3: age >= ? 

這里通過觀察可以發現,每一個條件都是由一個 字段名稱一個判斷一個占位符 "?"和后面用於連接條件的 AND 或者 OR 所構成。這樣我們可以編寫一個類用來保存這些信息:

Where.java


import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * where條件 默認使用 and 連接多個條件
 *
 * @author hjx
 */
public class Where {

    protected static final String PLACEHOLDER = "#{COLUMN}";

    static final String AND = "AND ";

    static final String OR = "OR ";

    private String sql;

    private String column;

    private String connect = AND;

    private List<Object> values;

    /**
     * 是否有值(null 也代表有值)
     */
    private boolean hasValue;

    /**
     * @param column 被操作的列
     * @param sql    操作的sql
     */
    public Where(String column, String sql) {
        this.column = column;
        this.sql = sql;
        this.hasValue = false;
        this.values = new ArrayList<>();
    }

    /**
     * @param column 被操作的列
     * @param sql    操作的sql
     * @param value  sql的參數
     */
    public Where(String column, String sql, Object value) {
        this.sql = sql;
        this.column = column;
        this.values = new ArrayList<>();
        this.values.add(value);
        this.hasValue = true;
    }

    /**
     * @param column 被操作的列
     * @param sql    操作的sql
     * @param values sql的參數
     */
    public Where(String column, String sql, Object[] values) {
        this.sql = sql;
        this.column = column;
        this.values = Arrays.asList(values);
        this.hasValue = true;
    }

    public Where or() {
        this.connect = OR;
        return this;
    }

    public Where and() {
        this.connect = AND;
        return this;
    }

    /**
     * 獲取本次條件的連接符
     *
     * @return
     */
    public String getConnect() {
        return connect;
    }

    protected String getSql() {
        return sql;
    }

    protected boolean isHasValue() {
        return hasValue;
    }

    protected List<Object> getValues() {
        return values;
    }

    public String getColumn() {
        return column;
    }
}

上面中的常量 PLACEHOLDER 是作為一個占位符使用的,下面會說道。

這樣,一個用於保存單個條件的類就寫好了,在一個sql中有多個條件的話,只需要用一個ArrayList保存這些條件,並按照一定的條件拼裝成sql就好了。

第二步

sql中還有一些比較常用的判斷,比如:!= , = , <= , >= 等等,我們在這里可以創建一個工具類來快速的生成Where 這個類,可以這樣寫:

Wheres.java


import java.util.Arrays;

/**
 * 查詢條件
 * @author hjx
 */
public class Wheres {
    
    public static Where equal(final String columnName, final Object value) {
        return new Where(columnName, Where.PLACEHOLDER + " = ? ", value);
    }

    public static Where notEqual(final String columnName, final Object value) {
        return new Where(columnName, Where.PLACEHOLDER + " != ? ", value);
    }

    public static Where not(final String columnName, final Object value) {
        return new Where(columnName, Where.PLACEHOLDER + " <> ? ", value);
    }

    public static Where isNotNull(final String columnName) {
        return new Where(columnName, Where.PLACEHOLDER + " IS NOT NULL ");
    }

    public static Where isNull(final String columnName) {
        return new Where(columnName, Where.PLACEHOLDER + " IS NULL ");
    }

    public static Where greater(final String columnName, final Object value, final boolean andEquals) {
        if (andEquals) {
            return new Where(columnName, Where.PLACEHOLDER + " >= ? ", value);
        }
        return new Where(columnName, Where.PLACEHOLDER + " > ? ", value);
    }

    public static Where less(final String columnName, final Object value, final boolean andEquals) {
        if (andEquals) {
            return new Where(columnName, Where.PLACEHOLDER + " <= ? ", value);
        }
        return new Where(columnName, Where.PLACEHOLDER + " < ? ", value);
    }

    public static Where like(final String columnName, final Object value) {
        return new Where(columnName, Where.PLACEHOLDER + " like ? ", value);
    }

    public static Where betweenAnd(final String columnName, final Object value1st, final Object value2nd) {
        return new Where(columnName, Where.PLACEHOLDER + " between ? and ? ", new Object[]{value1st, value2nd});
    }

    public static Where in(final String columnName, final Object[] values) {
        Object[] sqlVal = values;
        if (sqlVal.length == 0) {
            sqlVal = new Object[]{null};
        }
        StringBuffer inSql = new StringBuffer();
        inSql.append(Where.PLACEHOLDER);
        inSql.append(" IN ( ");
        String[] strings = StringUtils.repeat("?", sqlVal.length);
        inSql.append(StringUtils.join(Arrays.asList(strings), ", "));
        inSql.append(" ) ");
        return new Where(columnName, inSql.toString(), sqlVal);
    }

}

這里只是簡單的列出了一些常用的判斷條件,如果有特殊需要的自己再加進去就好了。

關於常量 PLACEHOLDER 是這么一回事:

在生成sql 的時候,我需要做一些字段上的驗證。這里在sql中使用一個占位符放進sql中,真正參與條件的字段放在另外一個屬性中保存。這樣在真正生成sql的時候可以驗證條件中的字段在不在表中,如果存在的話將字段和占位符進行替換就好了。並且如果使用的是屬性名稱的話,也可以根據名稱找到對應的表的字段名。

第三步

通過上面的代碼,我們可以很方便的創建條件了。現在我們將這些條件組裝成我們需要的完整的sql。

注意:這里的代碼可能和我的github上的不太一樣,因為這里只講一下思路,具體的怎么將所有的代碼組裝起來讓它成為一個完整的項目,每個人都不一樣。所以~~~ 嘿嘿。

現在開始:

我們還是以之前寫的User.java為例子

List<Where> wheres = Arrays.asList(
        Wheres.equal("name", "李叔叔"),
        Wheres.notEqual("status", 1),
        Wheres.in("age", new Integer[]{1, 2, 3, 4, 5}),
        Wheres.greater("age", 20, true)
);
List<Object> sqlValue = new ArrayList<>();
StringBuilder sql = new StringBuilder();
if (wheres.size() != 0) {
    sql.append("WHERE ");
    for (int i = 0; i < wheres.size(); i++) {
        Where where = wheres.get(i);
        if (i != 0) {
            sql.append(where.getConnect());
        }
        String column = where.getColumn();
        String whereSql = where.getSql();
        sql.append(
            //這里獲取真實sql
            whereSql.replace(Where.PLACEHOLDER, getColumnName(column))
        );
        //因為有些條件中的參數可能是有多個
        List<Object> values = where.getValues();
        for (int j = 0; j < values.size(); j++) {
            sqlValue.add(values.get(j));
        }
    }
}
System.out.println(sql.toString());
System.out.println(sqlValue.toString());

這里說明一下:getColumnName(String name) ,這個方法是根據參數獲取真正的字段名稱的方法。因為這個條件中可能傳入的是java屬性的名稱而不是表的字段名稱,需要轉換成為真正的表的字段名。這一步也是從之前生成的映射中獲取的。順便還能驗證一下表中有沒有這個字段。這個方法我就不貼出來了,github上有。

輸出結果:

WHERE name = ? AND status != ? AND age IN ( ?, ?, ?, ?, ? ) AND age >= ? 
[李叔叔, 1, 1, 2, 3, 4, 5, 20]

這里一個where就寫好了,並且也可以拿到條件中的參數了。

剩下的就是后面的單獨生成updatedeleteselect 類型sql的操作了。

我下一篇再寫~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM