手把手教你写一个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的操作了。
我下一篇再写~
手把手教你写一个java的orm(五)的更多相关文章
- 手把手教你写一个java的orm(一)
写之前的说明 其实吧. 这个东西已经写好了,地址在:https://github.com/hjx601496320/JdbcPlus 这系列文章算是我写的过程的总结吧.(恩系列,说明我可能会写好久,╮ ...
- 手把手教你写一个java的orm(二)
创建映射关系 想要实现一个orm的功能,我觉得就是要将class和数据库中的表创建映射关系.把class的名称和表的名称,class属性名称和表的字段名称,属性类型与表的字段类型一一对应起来.可以 ...
- 手把手教你写一个java的orm(完)
生成sql:select 上一篇讲了怎样生成一个sql中where的一部分,之后我们要做事情就简单很多了,就只要像最开始一样的生成各种sql语句就好了,之后只要再加上我们需要的条件,一个完整的sql就 ...
- 手把手教你写一个java的orm(三)
使用反射解析class 上一篇我们完成了class到表映射关系的建立,但是这个并不能被代码正确处理,我们还需要让程序能够正确的识别这些映射关系. 这一篇主要讲的是建立一个从class到表的模型,使我们 ...
- 手把手教你写一个java的orm(四)
开始准备生成sql 在上一篇里,我们已经取到了我们在生成sql语句中所需要的信息,这一篇里我们开始根据class来生成我们需要的sql.在这之前我们先确认几件事情 sql里的参数我们使用占位符的形式. ...
- 只有20行Javascript代码!手把手教你写一个页面模板引擎
http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...
- 手把手教你写一个RPC
1.1 RPC 是什么 定义:RPC(Remote Procedure Call Protocol)--远程过程调用协议 ,RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数 ...
- 让我手把手教你写一个强大、方便使用的 IOC 容器
一.介绍 1.介绍 最近无聊,也没什么事做,没事做总是要给自己找点事情做吧,毕竟人的生活在与折腾.于是,决定自己手动写一个 IOC 的框架.我们知道在 NetCore 的版本里面已经内置了 IOC 容 ...
- 手把手教你写一个SpringMVC框架
一.介绍 在日常的 web 开发中,熟悉 java 的同学一定知道,Spring MVC 可以说是目前最流行的框架,之所以如此的流行,原因很简单:编程简洁.上手简单! 我记得刚开始入行的时候,最先接触 ...
随机推荐
- In file included from adlist.c:34:0: zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录
问题: In file included from adlist.c:34:0:zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录 解决: make ...
- 11-使用EF操作数据库
本篇博客对应视频讲解 回顾 上一篇教程我们讲了XML与JSON的序列化问题,我们可以看到序列化实际上也是不同形式的转换,我们通常要以字节流的形式做中转.同时我们也可以看到,对于序列化这种常见的需求,我 ...
- AJPFX简评:MT5平台
MetaTrader 5全面改进的图表和扩展的功能 MetaTrader软件开发商在MT4获得全球交易商全面好评之后,又再次研发推出了更为先进的MT5交易软件. MT5的主要特征●改进的图表和即时 ...
- mybatis中单个参数的引用
单个参数时在test条件中不能用参数名来引用,可以使用_parameter
- linux,修改文件夹权限
chmod -R 777 dist/ chown windseek:staff dist/ 改变dist的权限到staff组里的windseek用户下 alias ll=`ls -al` ...
- CentOS7搭建FastDFS V5.11分布式文件系统-第三篇
1.测试 前面两篇博文已对FastDFS的安装和配置,做了比较详细的讲解.FastDFS的基础模块都搭好了,现在开始测试下载. 1.1 配置客户端 同样的,需要修改客户端的配置文件: /etc/fdf ...
- webstorm 添加css前缀(兼容)自动添加
Webstorm自动添加css前缀( 兼容) 百度了很多在webstorm中添加css前缀(兼容)自动添加,autoprefixer插件是首选,对于基本的css,还有less都支持,所以就选择了aut ...
- 配置豆瓣镜像作为python 库的下载源
配置豆瓣镜像作为python 库的下载源 Windows 下如下配置:
- 第6章—渲染web视图—使用Thymeleaf
使用Thymeleaf 长期以来,jsp在视图领域有非常重要的地位,随着时间的变迁,出现了一位新的挑战者:Thymeleaf,Thymeleaf是原生的,不依赖于标签库.它能够在接受原始HTML的地方 ...
- Android 中的冷启动和热启动
App的Activity退出之后,应用的进程并不会被杀死,而是保留在那里.当再次打开App的Activity时,会从已有的进程中创建Activity,是为“热启动”.若打开Activity时没有进程, ...