手把手教你写一个java的orm(五)
生成sql:where
上一篇里我们实现了生成insert的sql,下面要开始实现update,delete,select的sql语句了。但是这些语句有一个比较麻烦的地方是:它们一般后面都会有where条件,因为在执行的时候不能把表里所有的数据都进行操作。
所以这里我们需要先生成条件的sql。大概是这样的:
where id = ? and name != ? or age >= ?
where 后面的参数继续用 “?” 代替。值就放在一个有序的集合中就好了。类似上一篇提到的insertcolumnvalues。
思路
- 条件都是一个一个组成的,我们可以写一个类用来描述一个条件。
- 写一个工具类来快速的创建条件。
- 将多个条件中间用 and 或者 or 组合起来,并在最前方添加 where 就是一个完整的条件。
- 最后将这个条件转成一个字符串,并用一个集合将条件中的值存起来就好了。
实现
第一步
我们实现第一步,在这之前我们先看一下一个条件是有什么组成的,例如:
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就写好了,并且也可以拿到条件中的参数了。
剩下的就是后面的单独生成update,delete,select 类型sql的操作了。
我下一篇再写~
上一篇: 本是同根生,相煎何太急
下一篇: 轮椅王