- 浏览: 234836 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
清林小篆:
引用[/col[size=xx-small][/size]or ...
tomcat ssl配置以及CAS单点登录探究 -
cyxy99:
u012534143 写道我用同样的方法,同样的节点关系,为什 ...
PageRank算法java实现版本 -
cyxy99:
schaha123 写道楼主还有一个问题想请教一下,下面这2段 ...
PageRank算法java实现版本 -
njthnet:
Participle 和 IkParticiple 这2个类找 ...
贝叶斯文本分类 java实现 -
u012534143:
我用同样的方法,同样的节点关系,为什么的得到的结果与您不一样呢 ...
PageRank算法java实现版本
Mybatis的这个类比较精巧,适合被“拿来用”,还是稍微分析下,也许能有点收获。
Mybatis中的SqlBuilder是用来处理java程序动态拼接sql操作的,把我们从以前需要注意空格或者or,and,where等关键字处理中解脱出来,这个类设计的比较精巧,而且不依赖其他的类或者包,很适合移植到自己的项目中去,所以分离出来对其源码进行解读和改造。
首先,它用一个Threadlocal对象来存储SQL对象(表达sql的实体对象),这个东西我觉得表明:你可以以函数工具的方式操作它,同时,你也可以用你的dao来继承这个类,并不用担心线程安全的问题。
这个类里面定义了一个私有静态类 SQL,这个类有一个StatementType的枚举对象,如下:
然后有以下类型语句集合,存储不同sql语句段,如下
你肯定想象的到,会有selectSQL,insertSQL,deleteSQL,updateSQL这四个方法,分别为你返回对应的sql语句。这几个等会会详细讲解
还有一个sql()方法,通过StatementType枚举来返回你想要的xxxxSql()。
最后还有个比较重要的方法,sqlClause,这个方法通过你传入的语句/类型,为你构造sql,代码如下:
这个方法参数意思如下:
其实从参数就可以看出此方法的设计意图了。
首先builder拼接关键字,然后拼接闭合(开头)字符,在拼接第二个开始,判断是
否是AND 和OR关键字,这两个关键字在SqlBuilder上面会有定义成静态变量
private static final String AND = ") \nAND (";
private static final String OR = ") \nOR (";
假如是,则直接拼接,不是,则拼接多项分隔符。
最后,拼接闭合(结尾)字符,返回。
下面我们看看那四个方法(selectSQL,insertSQL,deleteSQL,updateSQL)是怎样调用他们的,以SelectSQL为例:如下
这个SQL静态类最终是为SqlBuilder来提供服务的,而SqlBuilder则暴露出我们需要的接口,提供传值的入口,我们以调用者的角度来看看SqlBuilder是怎样工作的。
一般来说,我们程序里是这样调用的:
Begin的时候会new一个SQL()对象放入当前线程变量ThreadLocal,
在select,from,where,orderby这些操作的时候会调用SQL对象的相关List来进行add动作,构造List。最后从当前线程变量中取出SQL对象,调用sql方法,返回。
假如值需要构造select语句,那么还有个精简版的SelectBuilder可以选择。
一点思考,
By 阿飞哥 转载请说明
腾讯微博:http://t.qq.com/duyunfeiRoom
新浪微博:http://weibo.com/u/1766094735
你下载mybatis的源码之后就有啊。
Mybatis中的SqlBuilder是用来处理java程序动态拼接sql操作的,把我们从以前需要注意空格或者or,and,where等关键字处理中解脱出来,这个类设计的比较精巧,而且不依赖其他的类或者包,很适合移植到自己的项目中去,所以分离出来对其源码进行解读和改造。
首先,它用一个Threadlocal对象来存储SQL对象(表达sql的实体对象),这个东西我觉得表明:你可以以函数工具的方式操作它,同时,你也可以用你的dao来继承这个类,并不用担心线程安全的问题。
这个类里面定义了一个私有静态类 SQL,这个类有一个StatementType的枚举对象,如下:
public enum StatementType { DELETE, INSERT, SELECT, UPDATE }分别表示增删改查操作。
然后有以下类型语句集合,存储不同sql语句段,如下
List<String> sets = new ArrayList<String>(); List<String> select = new ArrayList<String>(); List<String> tables = new ArrayList<String>(); List<String> join = new ArrayList<String>(); List<String> innerJoin = new ArrayList<String>(); List<String> outerJoin = new ArrayList<String>(); List<String> leftOuterJoin = new ArrayList<String>(); List<String> rightOuterJoin = new ArrayList<String>(); List<String> where = new ArrayList<String>(); List<String> having = new ArrayList<String>(); List<String> groupBy = new ArrayList<String>(); List<String> orderBy = new ArrayList<String>(); List<String> lastList = new ArrayList<String>(); List<String> columns = new ArrayList<String>(); List<String> values = new ArrayList<String>(); boolean distinct;包含了几乎所有的sql关键字
你肯定想象的到,会有selectSQL,insertSQL,deleteSQL,updateSQL这四个方法,分别为你返回对应的sql语句。这几个等会会详细讲解
还有一个sql()方法,通过StatementType枚举来返回你想要的xxxxSql()。
最后还有个比较重要的方法,sqlClause,这个方法通过你传入的语句/类型,为你构造sql,代码如下:
private void sqlClause(StringBuilder builder, String keyword, List<String> parts, String open, String close, String conjunction) { if (!parts.isEmpty()) { if (builder.length() > 0) builder.append("\n"); builder.append(keyword); builder.append(" "); builder.append(open); String last = "________"; for (int i = 0, n = parts.size(); i < n; i++) { String part = parts.get(i); if (i > 0 && !part.equals(AND) && !part.equals(OR) && !last.equals(AND) && !last.equals(OR)) { builder.append(conjunction); } builder.append(part); last = part; } builder.append(close); } }
这个方法参数意思如下:
- builder:当前待拼接的sql语句。
- Keyword:关键字,如select,from,join,inner join,having,where等等这些。
- Parts:就是相对应的上面的那些List对象,比如select,join等等,传递你需要拼接的实际sql内容。
- Open,close:就是此语句开始和结尾的闭合字符,比如select,form,join等这个肯定都是“”,而where和having这个肯定就是“(”和“)”
- Conjunction:多个关键字语句中间的连接串,比如说select,from,group by,order by这些的多个语句块都是“, ”连接的,比如select a.name,a.pid ,order by a.id,b.id等。
- 而join多个表肯定是有多个join,left out join 后面肯定也会是left out join,where 多个肯定是 and 连接的(这里不考虑or,因为已经有Or这个关键方法来表示)。
其实从参数就可以看出此方法的设计意图了。
首先builder拼接关键字,然后拼接闭合(开头)字符,在拼接第二个开始,判断是
否是AND 和OR关键字,这两个关键字在SqlBuilder上面会有定义成静态变量
private static final String AND = ") \nAND (";
private static final String OR = ") \nOR (";
假如是,则直接拼接,不是,则拼接多项分隔符。
最后,拼接闭合(结尾)字符,返回。
下面我们看看那四个方法(selectSQL,insertSQL,deleteSQL,updateSQL)是怎样调用他们的,以SelectSQL为例:如下
private String selectSQL() { StringBuilder builder = new StringBuilder(); if (distinct) { sqlClause(builder, "SELECT DISTINCT", select, "", "", ", "); } else { sqlClause(builder, "SELECT", select, "", "", ", "); } sqlClause(builder, "FROM", tables, "", "", ", "); sqlClause(builder, "JOIN", join, "", "", "JOIN"); sqlClause(builder, "INNER JOIN", innerJoin, "", "", "\nINNER JOIN "); sqlClause(builder, "OUTER JOIN", outerJoin, "", "", "\nOUTER JOIN "); sqlClause(builder, "LEFT OUTER JOIN", leftOuterJoin, "", "", "\nLEFT OUTER JOIN "); sqlClause(builder, "RIGHT OUTER JOIN", rightOuterJoin, "", "", "\nRIGHT OUTER JOIN "); sqlClause(builder, "WHERE", where, "(", ")", " AND "); sqlClause(builder, "GROUP BY", groupBy, "", "", ", "); sqlClause(builder, "HAVING", having, "(", ")", " AND "); sqlClause(builder, "ORDER BY", orderBy, "", "", ", "); return builder.toString(); }
这个SQL静态类最终是为SqlBuilder来提供服务的,而SqlBuilder则暴露出我们需要的接口,提供传值的入口,我们以调用者的角度来看看SqlBuilder是怎样工作的。
一般来说,我们程序里是这样调用的:
public String selectByPro() { BEGIN(); SELECT("p.id,p.username,p.password"); SELECT("p.createDate,p.modifyDate"); FROM("person p"); FROM("account a"); INNER_JOIN("dept d on d.id=p.id"); INNER_JOIN("company c on c.id=d.id"); WHERE("p.id=a.id"); WHERE("p.name like '%afei%'"); OR(); WHERE("p.sex = '1'"); GROUP_BY("p.id"); HAVING("p.age > 20"); ORDER_BY("p.id"); ORDER_BY("p.name"); return SQL(); }
Begin的时候会new一个SQL()对象放入当前线程变量ThreadLocal,
在select,from,where,orderby这些操作的时候会调用SQL对象的相关List来进行add动作,构造List。最后从当前线程变量中取出SQL对象,调用sql方法,返回。
假如值需要构造select语句,那么还有个精简版的SelectBuilder可以选择。
一点思考,
- 1, 你可以把这些方法或属性放入你的基础DAO里面,不用担心线程安全的问题,这是最佳实践。
- 2, 当作工具类来用,但是这样影响代码的可读性。
- 3, 这个类里面的方法都不是同步的,而是操作了一个线程安全的变量,这样可以避免多线程在调用这个类的不同方法时被迫同步的情况。
By 阿飞哥 转载请说明
腾讯微博:http://t.qq.com/duyunfeiRoom
新浪微博:http://weibo.com/u/1766094735
评论
2 楼
AngelAndAngel
2011-09-13
giianhui 写道
希望能附上源码,谢谢!
你下载mybatis的源码之后就有啊。
package org.apache.ibatis.jdbc; import java.util.ArrayList; import java.util.List; public class SqlBuilder { private static final String AND = ") \nAND ("; private static final String OR = ") \nOR ("; private static final ThreadLocal<SQL> localSQL = new ThreadLocal<SQL>(); public static void BEGIN() { RESET(); } public static void RESET() { localSQL.set(new SQL()); } public static void UPDATE(String table) { sql().statementType = SQL.StatementType.UPDATE; sql().tables.add(table); } public static void SET(String sets) { sql().sets.add(sets); } public static String SQL() { try { return sql().sql(); } finally { RESET(); } } public static void INSERT_INTO(String tableName) { sql().statementType = SQL.StatementType.INSERT; sql().tables.add(tableName); } public static void VALUES(String columns, String values) { sql().columns.add(columns); sql().values.add(values); } public static void SELECT(String columns) { sql().statementType = SQL.StatementType.SELECT; sql().select.add(columns); } public static void SELECT_DISTINCT(String columns) { sql().distinct = true; SELECT(columns); } public static void DELETE_FROM(String table) { sql().statementType = SQL.StatementType.DELETE; sql().tables.add(table); } public static void FROM(String table) { sql().tables.add(table); } public static void JOIN(String join) { sql().join.add(join); } public static void INNER_JOIN(String join) { sql().innerJoin.add(join); } public static void LEFT_OUTER_JOIN(String join) { sql().leftOuterJoin.add(join); } public static void RIGHT_OUTER_JOIN(String join) { sql().rightOuterJoin.add(join); } public static void OUTER_JOIN(String join) { sql().outerJoin.add(join); } public static void WHERE(String conditions) { sql().where.add(conditions); sql().lastList = sql().where; } public static void OR() { sql().lastList.add(OR); } public static void AND() { sql().lastList.add(AND); } public static void GROUP_BY(String columns) { sql().groupBy.add(columns); } public static void HAVING(String conditions) { sql().having.add(conditions); sql().lastList = sql().having; } public static void ORDER_BY(String columns) { sql().orderBy.add(columns); } private static SQL sql() { SQL sql = localSQL.get(); if (sql == null) { RESET(); sql = localSQL.get(); } return sql; } private static class SQL { public enum StatementType { DELETE, INSERT, SELECT, UPDATE } StatementType statementType; List<String> sets = new ArrayList<String>(); List<String> select = new ArrayList<String>(); List<String> tables = new ArrayList<String>(); List<String> join = new ArrayList<String>(); List<String> innerJoin = new ArrayList<String>(); List<String> outerJoin = new ArrayList<String>(); List<String> leftOuterJoin = new ArrayList<String>(); List<String> rightOuterJoin = new ArrayList<String>(); List<String> where = new ArrayList<String>(); List<String> having = new ArrayList<String>(); List<String> groupBy = new ArrayList<String>(); List<String> orderBy = new ArrayList<String>(); List<String> lastList = new ArrayList<String>(); List<String> columns = new ArrayList<String>(); List<String> values = new ArrayList<String>(); boolean distinct; private void sqlClause(StringBuilder builder, String keyword, List<String> parts, String open, String close, String conjunction) { if (!parts.isEmpty()) { if (builder.length() > 0) builder.append("\n"); builder.append(keyword); builder.append(" "); builder.append(open); String last = "________"; for (int i = 0, n = parts.size(); i < n; i++) { String part = parts.get(i); if (i > 0 && !part.equals(AND) && !part.equals(OR) && !last.equals(AND) && !last.equals(OR)) { builder.append(conjunction); } builder.append(part); last = part; } builder.append(close); } } private String selectSQL() { StringBuilder builder = new StringBuilder(); if (distinct) { sqlClause(builder, "SELECT DISTINCT", select, "", "", ", "); } else { sqlClause(builder, "SELECT", select, "", "", ", "); } sqlClause(builder, "FROM", tables, "", "", ", "); sqlClause(builder, "JOIN", join, "", "", "JOIN"); sqlClause(builder, "INNER JOIN", innerJoin, "", "", "\nINNER JOIN "); sqlClause(builder, "OUTER JOIN", outerJoin, "", "", "\nOUTER JOIN "); sqlClause(builder, "LEFT OUTER JOIN", leftOuterJoin, "", "", "\nLEFT OUTER JOIN "); sqlClause(builder, "RIGHT OUTER JOIN", rightOuterJoin, "", "", "\nRIGHT OUTER JOIN "); sqlClause(builder, "WHERE", where, "(", ")", " AND "); sqlClause(builder, "GROUP BY", groupBy, "", "", ", "); sqlClause(builder, "HAVING", having, "(", ")", " AND "); sqlClause(builder, "ORDER BY", orderBy, "", "", ", "); return builder.toString(); } private String insertSQL() { StringBuilder builder = new StringBuilder(); sqlClause(builder, "INSERT INTO", tables, "", "", ""); sqlClause(builder, "", columns, "(", ")", ", "); sqlClause(builder, "VALUES", values, "(", ")", ", "); return builder.toString(); } private String deleteSQL() { StringBuilder builder = new StringBuilder(); sqlClause(builder, "DELETE FROM", tables, "", "", ""); sqlClause(builder, "WHERE", where, "(", ")", " AND "); return builder.toString(); } private String updateSQL() { StringBuilder builder = new StringBuilder(); sqlClause(builder, "UPDATE", tables, "", "", ""); sqlClause(builder, "SET", sets, "", "", ", "); sqlClause(builder, "WHERE", where, "(", ")", " AND "); return builder.toString(); } public String sql() { if (statementType == null) { return null; } String answer; switch (statementType) { case DELETE: answer = deleteSQL(); break; case INSERT: answer = insertSQL(); break; case SELECT: answer = selectSQL(); break; case UPDATE: answer = updateSQL(); break; default: answer = null; } return answer; } } }
1 楼
giianhui
2011-09-13
希望能附上源码,谢谢!
发表评论
-
招Java培训老师(还是论坛招人靠谱)
2015-05-10 13:39 556好久没来坛子了,一来就搞这么有目的的事儿。。。 好吧, ... -
动手开发自己的mvc-3----容器该帮我们做什么?(非常的重点)
2013-01-22 13:55 1824注解注入 我们知道,Spring只有一个角色:工厂。这个工厂可 ... -
动手开发自己的mvc-2----完善控制层,提供自动注入和注解上传等功能
2013-01-22 13:44 2586当表单提交的内容过多 ,让懒惰的程序员一个个getPara ... -
动手开发自己的mvc-1----实现初步的控制层,实现各种配置和资源获取
2013-01-22 13:28 2821mvc框架最基础的功能就是跳转,struts2支持注 ... -
动手开发自己的mvc (系列)
2013-01-22 14:08 1934到年尾了,整理了一下我Evernote藏的各种文档,打算把ys ... -
整合了一个小的爬取流程框架
2013-01-08 13:04 1312弄了一个小的爬取流程框架,把之前工作中用到的一些小经验 ... -
Mahout各种推荐器的主要特点
2012-12-06 15:17 2996Mahout有很多推荐的实现,各有特点,在这里一并记录 ... -
怎样通过词频得到这个词频的排序?
2012-12-03 14:35 2070在大规模检索中,我们怎样通过已经的词频得到词频的排序 ... -
drools实现自定义业务规则
2012-10-12 11:49 2851最近做财务相关的积分规则,由于这个功能以后涉及到方方面面 ... -
贝叶斯文本分类 java实现
2012-09-25 15:15 12688昨天实现了一个基于贝叶斯定理的的文本分类,贝叶斯定理假 ... -
前段时间做了一个小型的MVC
2012-07-20 13:23 0前端时间做了一个小型的MVC,麻雀虽小,五脏俱全,目前实现的功 ... -
聚类算法之MST算法 java实现版本
2012-07-17 14:20 2805在介绍最小生成树算法(MST)之前,简单说一下平均链接算 ... -
聚类算法之单链接算法java实现
2012-07-05 10:09 4310聚类算法中基于链接的算法大致有三种:单链接算法(s ... -
朴素贝叶斯分类器
2012-05-20 15:25 0NaiveBayes分类器的优点是能得到已知Y的条件下X的 ... -
PageRank算法java实现版本
2012-05-16 16:03 17475PageRank算法是Google的核心搜索算法,在所有 ... -
聚类算法之kmeans算法java版本
2012-04-22 21:34 20905聚类的意思很明确,物以类聚,把类似的事物放在一起。 ... -
昨天做了个小工具DB转pojo,html,sql
2012-03-21 13:15 1778做dbutils时为了方便就做了个小工具,省点小事儿吧。 -
我这儿的讨论(项目小组)区可以进来了
2012-02-28 10:38 150java项目小组群,前几天清了几个破坏气氛者,和不发言 ... -
智能web探究群组建立了
2011-11-24 12:10 1632最近群组已申请成功 ,地址是http://web.gr ... -
Cas https方式改为http方式
2011-09-24 13:02 2351最近项目要测试,来不及申请等待证书,所以先把项目改为http的 ...
相关推荐
mybatis SQL日志解析;查看日志时mybatis打印的日志查询条件以及参数不是拼接好的,想复制对应sql在本地执行时比较麻烦,通过前端编写页面进行日志解析,拼接sql中的问号以及参数变课轻松实现
MyBatis是一款基于Java的持久层框架,提供了强大的数据库访问能力,能够与多种数据库管理系统集成,包括MySQL、Oracle、SQL Server等。MyBatis的主要特点是使用XML文件或注解来定义数据库访问的映射关系,从而屏蔽了...
《MyBatis源码详解学习》是一份专为对MyBatis源码感兴趣的开发者准备的资料,它旨在帮助读者深入理解这个流行持久层框架的工作原理。MyBatis作为一个轻量级的ORM(对象关系映射)框架,因其简单易用、高度可定制化的...
总结起来,MyBatis源码分析涵盖了从配置加载到数据库操作的全过程,涉及到了配置解析、SQL执行、结果映射等多个关键环节,以及Executor、StatementHandler等核心组件。通过深入学习MyBatis的源码,开发者不仅可以...
标题 "mybatissql_mybatis解决sql注入" 暗示了我们正在讨论MyBatis框架如何处理SQL注入问题。SQL注入是一种常见的安全漏洞,攻击者可以通过恶意输入篡改SQL查询,获取、修改或删除数据库中的敏感数据。MyBatis,作为...
在MyBatis-Plus源码中,我们可以看到如何实现这些功能,例如,条件构造器是如何通过反射和OGNL表达式解析来动态构建SQL的,BaseMapper和BaseService是如何协同工作的,以及如何通过AutoFillMetaObjectHandler自动...
MyBatis 源码解析:通过源码深入理解 SQL 的执行过程 抓下来打包成了HTML文件, 方便离线观看
该工具可以将mybatis输出的sql日志提取出来,并将其格式化为可以直接执行的sql语句,节约开发人员时间
Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)SSM源码Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)SSM源码Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)SSM源码Java EE企业级应用...
mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码mybatis核心源码...
MyBatis分页插件的工作原理是动态插入SQL,它会在执行查询语句之前,根据数据库类型(如MySQL或Oracle)动态生成合适的分页SQL。例如,对于MySQL,它会将原SQL语句转换为带有LIMIT和OFFSET的分页SQL;对于Oracle,...
MyBatis是一个优秀的Java持久层框架,它支持定制化SQL、存储过程以及高级映射。在深入探讨MyBatis 3.4.1的源码之前,先了解一下MyBatis的基本概念和工作原理。 MyBatis的核心是SqlSessionFactory,它是通过...
MyBatis-SQL-Dialect是MyBatis框架的一个扩展,主要目的是为了支持不同数据库系统之间的SQL方言差异。MyBatis是一个流行的Java持久层框架,它允许开发者将SQL语句直接集成到XML或Java代码中,提供了灵活的数据访问层...
通过阅读源码,我们可以了解到MyBatis-Plus是如何将用户操作转化为SQL语句的,以及它是如何处理各种数据库交互细节的。这对于理解框架的工作原理、优化数据库操作和进行二次开发都具有重要的参考价值。同时,学习...
MyBatis是一个优秀的Java持久层框架,它支持定制化SQL、存储过程以及高级映射。在3.0.4版本中,MyBatis提供了一系列关键功能,帮助开发者更高效地处理数据库操作。以下是对`mybatis-3.0.4源码`的详细解析。 一、...
标题中的“Spring+SpringMVC+Mybatis框架整合源码”指的是一个基于Java的Web开发项目,它结合了三个主流的开源框架:Spring、SpringMVC和Mybatis,以实现高效且灵活的企业级应用开发。这三种框架在Java世界中扮演着...
MyBatis是一款优秀的Java持久层框架,它支持定制化SQL、存储过程以及高级映射,极大地简化了传统Java开发中的数据库操作。SQLServer是微软公司推出的关系型数据库管理系统,广泛应用于企业级应用开发。本教程将通过...
MyBatis For .NET 源码 开源项目iBATIS一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2001年发起的开放源代码项目。最初侧重于密码软件的开发,现在是一个基于Java的持久层框架。iBATIS提供的...
SpringMVC、Mybatis和SQLServer是Java Web开发中常见的技术栈,它们分别负责不同的职责。SpringMVC作为Spring框架的一部分,是用于构建Web应用程序的模型-视图-控制器(MVC)架构。Mybatis是一个轻量级的持久层框架...
MyBatis是一个优秀的Java持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以使用简单的XML或注解来配置和映射原生信息,将接口和Java...