文章目录
2、Mybatis中的设计模式
“模式只是指导方针,实际工作中,可以改变模式来适应实际问题。”
2.1、Builder建造者模式
Builder模式的定义是“将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。”
此模式主要用于将复杂对象的构造过程与其表示分离。它将复杂对象的创建过程划分为简单的步骤,并屏蔽复杂对象内部的特定构造细节.
2.1.1、Mybatis源码中使用到的案例有:
在Mybatis环境的初始化过程中,SqlSessionFactoryBuilder会调用XMLConfigBuilder读取所有的MybatisMapConfig.xml和所有的*Mapper.xml文件,构建Mybatis运行的核心对象Configuration对象,然后将该Configuration对象作为参数构建一个SqlSessionFactory对象。
其中XMLConfigBuilder在构建Configuration对象时,也会调用XMLMapperBuilder用于读取*Mapper文件,而XMLMapperBuilder会使用XMLStatementBuilder来读取和build所有的SQL语句。如果是动态SQL则会使用XMLScriptBuilder,为了协助XMLMapperBuilder可能会衍生出中间的助手比如MapperBuilderAssistant,增加缓存CacheBuilder
2.1.2、SQL类比如我们直接使用的原生SQL是构建模式么?
new SQL(){{
SELECT("id,username,password,email,bio").FROM("author").WHERE("id=#{id}");
}}.toString();
可能这里大家说没有增加Builder名称,但是我们看下SQL这个对象内部完成了一个构建SQL的操作,可以组合不同的SQL,再来看此模式主要用于将复杂对象的构造过程与其表示分离。它将复杂对象的创建过程划分为简单的步骤,并屏蔽复杂对象内部的特定构造细节.是否一致呢?答案是一致的。那么我们也可以从源码中证明,现在已经统一抽象到AbstractSQL,由SQL对外暴露实现。
2.1.3、小结
- 对于通常意义来说源码和我们Coding的时候会以Builder结尾来提示,见名知意。
- 使用场景:通常我们在一个函数或者构造器中无法完整的完成某个实例,那么我们可以考虑使用构建器Builder模式
2.2、Factory工厂模式
顾名思义,通常我们有了第一个建造者模式的小结感悟,那么工厂模式,是不是也是如此呢?*Factory.java作为工厂模式呢?答案也是正确的。那么我们熟悉的有哪些呢?DefaultSqlSessionFactory是SqlSessionFactory的实现。
2.2.1、DefaultSqlSessionFactory
public class DefaultSqlSessionFactory implements SqlSessionFactory {
//全局配置
private final Configuration configuration;
...省略本次无关内容...
//打开从数据源的会话
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
...省略本次无关内容...
}
但是从这里看到的是与往常我们看到的工厂模式不太像,比如有条件判断产生不同的对象,是不是有条件这个虽然没有显示用switch或者if判断,但是通过入参数来达成目的了呢?比如不同的参数构建出不同的Session。
2.2.2、LogFactory
public final class LogFactory {
/**
* 被日志实现的类使用
* Marker to be used by logging implementations that support markers.
*/
public static final String MARKER = "MYBATIS";
//日志构造器
private static Constructor<? extends Log> logConstructor;
//静态代码初始化
static {
//SLF4j
tryImplementation(LogFactory::useSlf4jLogging);
//CommonsLog
tryImplementation(LogFactory::useCommonsLogging);
//Log4j2
tryImplementation(LogFactory::useLog4J2Logging);
//Log4j
tryImplementation(LogFactory::useLog4JLogging);
//JdkLog
tryImplementation(LogFactory::useJdkLogging);
//NoLog
tryImplementation(LogFactory::useNoLogging);
}
//阻止外部实例化
private LogFactory() {
// disable construction
}
//根据类获取日志接口
public static Log getLog(Class<?> aClass) {
return getLog(aClass.getName());
}
//根据类名获取Log
public static Log getLog(String logger) {
try {
return logConstructor.newInstance(logger);
} catch (Throwable t) {
throw new LogException("Error creating logger for logger " + logger + ". Cause: " + t, t);
}
}
...省略本次无关内容...
}
这里日志工厂模式是怎么实现的呢?实际上细心会发现Constructor<? extends Log> logConstructor,构造器中他们统一继承了Log类来构造的时候找到具体的类。
2.3、单例模式
单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。
单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。
public class ErrorContext {
//行分割符号
private static final String LINE_SEPARATOR = System.getProperty("line.separator","\n");
//线程本地变量
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>();
//已经存储的错误上下文
private ErrorContext stored;
//资源
private String resource;
//活动
private String activity;
//对象
private String object;
//消息
private String message;
//sql
private String sql;
//抛出异常
private Throwable cause;
//防止外部实例化
private ErrorContext() {
}
//错误上下文实例化---单例模式
public static ErrorContext instance() {
//从线程本地变量获取,保证每个线程不一样
ErrorContext context = LOCAL.get();
if (context == null) {
context = new ErrorContext();
LOCAL.set(context);
}
return context;
}
...省略本次无关内容...
}
ErrorContext全局只有一个上下文错误实例,但是这里巧妙的使用了ThreadLocal LOCAL = new ThreadLocal<>();本来系统只应该有一个错误上下文,通过线程本地变量的形式,完成了每个线程请求有保留一份上下文错误实例。这个非常巧妙的使用了单例模式和线程本地变量相结合。如果有人说为啥不可以构造器创建呢?private ErrorContext()而私有构造器就是为了防止外部创建。然后第二个问题也来了,我们常说的单例模式并发的不安全呢?这里通过线程本地变量也解决了哈哈。
2.4、代理模式
是否还记得我们之前的那个图,Mybatis核心执行图,这里我们提到了动态代理,实际上代理模式就是将我们要直接执行的委托给代理执行,这里常用的代理模式实现方式有2种,jdk的动态代理和cglib动态代理
2.5、模板模式
模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术。通常可以是将多个类通用的函数抽象成公共的复用函数,而这里的思想代码复用其实就是类似模板模式,比如一个抽象类约定了一些模版方法,子类可以根据自己的需要进行实现算法或者业务逻辑。
是否还记得我们跟踪源码的时候提到的执行器,而默认的时候开启缓存的执行器CachingExecutor,时序图中可以看到委托的Executor执行最终实际上是子类SimpleExecutor完成的动作。
2.6、适配器模式
适配器模式(Adapter Pattern) :将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
在Mybatsi的logging包中,有一个Log接口,众所周知我们需要兼容不同的Log实现来满足用户对于一个框架的使用。那么Mybatis框架就需要进行兼容,而这个过程就用到了适配器模式
/**
* 日志接口
*/
public interface Log {
//是否开启debug模式
boolean isDebugEnabled();
//是否开启trace模式
boolean isTraceEnabled();
//输出错误信息
void error(String s, Throwable e);
//输出错误信息
void error(String s);
//输出debug信息
void debug(String s);
//输出trace信息
void trace(String s);
//输出war信息
void warn(String s);
}
让他们统一实现Log接口,外部调用log实现根据需要委托给实现类执行。
2.7、装饰者模式
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。适配器是委托给子类具体实现,用来兼容多种能力的支持。提高扩展性。而装饰者模式属于增强能力,主要是给一个类的增强某些功能,但不是必须的。
2.8、迭代器模式
迭代器(Iterator)模式,又叫做游标(Cursor)模式。GOF给出的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。Java的Iterator就是迭代器模式的接口,只要实现了该接口,就相当于应用了迭代器模式:比如Mybatis的PropertyTokenizer是property包中的重量级类,该类会被reflection包中其他的类频繁的引用到。这个类实现了Iterator接口,在使用时经常被用到的是Iterator接口中的hasNext这个函数。
/**
* 属性标记器
* @author Clinton Begin
*/
public class PropertyTokenizer implements Iterator<PropertyTokenizer> {
//名称
private String name;
//索引名称
private final String indexedName;
//索引
private String index;
//子属性
private final String children;
//根据完整的全名称构造器
public PropertyTokenizer(String fullname) {
int delim = fullname.indexOf('.');
if (delim > -1) {
name = fullname.substring(0, delim);
children = fullname.substring(delim + 1);
} else {
name = fullname;
children = null;
}
indexedName = name;
delim = name.indexOf('[');
if (delim > -1) {
index = name.substring(delim + 1, name.length() - 1);
name = name.substring(0, delim);
}
}
//获取名称
public String getName() {
return name;
}
//获取索引
public String getIndex() {
return index;
}
//获取索引名称
public String getIndexedName() {
return indexedName;
}
//获取子名称
public String getChildren() {
return children;
}
//是否还有下一个属性
@Override
public boolean hasNext() {
return children != null;
}
//遍历下一个属性
@Override
public PropertyTokenizer next() {
return new PropertyTokenizer(children);
}
//移除能力没有
@Override
public void remove() {
throw new UnsupportedOperationException("Remove is not supported, as it has no meaning in the context of properties.");
}
}
2.9、组合模式
组合(Composite)模式的定义:有时又叫作部分-整体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-整体”的关系,使用户对单个对象和组合对象具有一致的访问性。
Mybatis支持动态SQL的强大功能使用到了trim、if等动态元素,可以根据条件来生成不同情况下的SQL;
在DynamicSqlSource.getBoundSql方法里,调用了rootSqlNode.apply(context)方法,apply方法是所有的动态节点都实现的接口:组合模式的简单之处在于,所有的子节点都是同一类节点,可以递归的向下执行。而这个需要用XML标签约束好,否则直接使用会报错。所以XML会校验是否符合dtd语法协议。
/**
* 动态SQL源
* @author Clinton Begin
*/
public class DynamicSqlSource implements SqlSource {
//全局配置
private final Configuration configuration;
//root节点
private final SqlNode rootSqlNode;
//动态sql源
public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) {
this.configuration = configuration;
this.rootSqlNode = rootSqlNode;
}
//获取绑定的SQL
@Override
public BoundSql getBoundSql(Object parameterObject) {
DynamicContext context = new DynamicContext(configuration, parameterObject);
//组合模式的整体root节点,直接获取所有的动态部分SQL节点内容并组合起来
rootSqlNode.apply(context);
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
context.getBindings().forEach(boundSql::setAdditionalParameter);
return boundSql;
}
}
2.10、责任链模式
责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止
在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。
在Mybatis源码中我们经常会根据自己需要来加一些会话拦截操作,而这系列动作就是Mybatis源码中的责任链完成的
/**
* 拦截器链
* @author Clinton Begin
*/
public class InterceptorChain {
//拦截器链
private final List<Interceptor> interceptors = new ArrayList<>();
//所有的拦截器
public Object pluginAll(Object target) {
for (Interceptor interceptor : interceptors) {
target = interceptor.plugin(target);
}
return target;
}
//添加拦截器
public void addInterceptor(Interceptor interceptor) {
interceptors.add(interceptor);
}
//获取只读拦截器
public List<Interceptor> getInterceptors() {
return Collections.unmodifiableList(interceptors);
}
}
2.11、策略模式
策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。比如Mybatis源码中的AbstractSQL核心类中的内部类的SQLStatement内部枚举类LimitingRowsStrategy,根据不同数据库策略来执行不同的分页SQL语法。
public abstract class AbstractSQL<T> {
//私有属性 And
private static final String AND = ") \nAND (";
//私有属性 or
private static final String OR = ") \nOR (";
//私有SQL声明
private final SQLStatement sql = new SQLStatement();
public abstract T getSelf();
//更新函数
public T UPDATE(String table) {
sql().statementType = SQLStatement.StatementType.UPDATE;
sql().tables.add(table);
return getSelf();
}
//set字段
public T SET(String sets) {
sql().sets.add(sets);
return getSelf();
}
/**
* set字段
* @since 3.4.2
*/
public T SET(String... sets) {
sql().sets.addAll(Arrays.asList(sets));
return getSelf();
}
//insert函数
public T INSERT_INTO(String tableName) {
sql().statementType = SQLStatement.StatementType.INSERT;
sql().tables.add(tableName);
return getSelf();
}
//插入VALUES关键字
public T VALUES(String columns, String values) {
INTO_COLUMNS(columns);
INTO_VALUES(values);
return getSelf();
}
/**
* 插入field列
* @since 3.4.2
*/
public T INTO_COLUMNS(String... columns) {
sql().columns.addAll(Arrays.asList(columns));
return getSelf();
}
/**
* 插入字段
* @since 3.4.2
*/
public T INTO_VALUES(String... values) {
List<String> list = sql().valuesList.get(sql().valuesList.size() - 1);
Collections.addAll(list, values);
return getSelf();
}
//查询SQL函数
public T SELECT(String columns) {
sql().statementType = SQLStatement.StatementType.SELECT;
sql().select.add(columns);
return getSelf();
}
/**
* //查询SQL函数
* @since 3.4.2
*/
public T SELECT(String... columns) {
sql().statementType = SQLStatement.StatementType.SELECT;
sql().select.addAll(Arrays.asList(columns));
return getSelf();
}
//去重字段
public T SELECT_DISTINCT(String columns) {
sql().distinct = true;
SELECT(columns);
return getSelf();
}
/**
* 去重字段
* @since 3.4.2
*/
public T SELECT_DISTINCT(String... columns) {
sql().distinct = true;
SELECT(columns);
return getSelf();
}
//删除表
public T DELETE_FROM(String table) {
sql().statementType = SQLStatement.StatementType.DELETE;
sql().tables.add(table);
return getSelf();
}
//from表追加
public T FROM(String table) {
sql().tables.add(table);
return getSelf();
}
/**
* from表追加
* @since 3.4.2
*/
public T FROM(String... tables) {
sql().tables.addAll(Arrays.asList(tables));
return getSelf();
}
//连表
public T JOIN(String join) {
sql().join.add(join);
return getSelf();
}
/**
* 连表
* @since 3.4.2
*/
public T JOIN(String... joins) {
sql().join.addAll(Arrays.asList(joins));
return getSelf();
}
//内连
public T INNER_JOIN(String join) {
sql().innerJoin.add(join);
return getSelf();
}
/**
* 内连表
* @since 3.4.2
*/
public T INNER_JOIN(String... joins) {
sql().innerJoin.addAll(Arrays.asList(joins));
return getSelf();
}
//左连表
public T LEFT_OUTER_JOIN(String join) {
sql().leftOuterJoin.add(join);
return getSelf();
}
/**
* 左连表
* @since 3.4.2
*/
public T LEFT_OUTER_JOIN(String... joins) {
sql().leftOuterJoin.addAll(Arrays.asList(joins));
return getSelf();
}
//右连表
public T RIGHT_OUTER_JOIN(String join) {
sql().rightOuterJoin.add(join);
return getSelf();
}
/**
* 右连表
* @since 3.4.2
*/
public T RIGHT_OUTER_JOIN(String... joins) {
sql().rightOuterJoin.addAll(Arrays.asList(joins));
return getSelf();
}
//外连表
public T OUTER_JOIN(String join) {
sql().outerJoin.add(join);
return getSelf();
}
/**
* 外连表
* @since 3.4.2
*/
public T OUTER_JOIN(String... joins) {
sql().outerJoin.addAll(Arrays.asList(joins));
return getSelf();
}
//追加where条件
public T WHERE(String conditions) {
sql().where.add(conditions);
sql().lastList = sql().where;
return getSelf();
}
/**
* 追加where条件
* @since 3.4.2
*/
public T WHERE(String... conditions) {
sql().where.addAll(Arrays.asList(conditions));
sql().lastList = sql().where;
return getSelf();
}
//追加or
public T OR() {
sql().lastList.add(OR);
return getSelf();
}
//追加and
public T AND() {
sql().lastList.add(AND);
return getSelf();
}
//给group by增加一列属性
public T GROUP_BY(String columns) {
sql().groupBy.add(columns);
return getSelf();
}
/**
* 给group by增加多列排序
* @since 3.4.2
*/
public T GROUP_BY(String... columns) {
sql().groupBy.addAll(Arrays.asList(columns));
return getSelf();
}
//给having增加单独条件属性
public T HAVING(String conditions) {
sql().having.add(conditions);
sql().lastList = sql().having;
return getSelf();
}
/**
* 给having增加条件
* @since 3.4.2
*/
public T HAVING(String... conditions) {
sql().having.addAll(Arrays.asList(conditions));
sql().lastList = sql().having;
return getSelf();
}
//给order by增加一列属性
public T ORDER_BY(String columns) {
sql().orderBy.add(columns);
return getSelf();
}
/**
* 给order by增加列字段属性
* @since 3.4.2
*/
public T ORDER_BY(String... columns) {
sql().orderBy.addAll(Arrays.asList(columns));
return getSelf();
}
/**
* 给#{limit}赋值内容
* Set the limit variable string(e.g. {@code "#{limit}"}).
*
* @param variable a limit variable string
* @return a self instance
* @see #OFFSET(String)
* @since 3.5.2
*/
public T LIMIT(String variable) {
sql().limit = variable;
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT;
return getSelf();
}
/**
* 设置limit值
* Set the limit value.
*
* @param value an offset value
* @return a self instance
* @see #OFFSET(long)
* @since 3.5.2
*/
public T LIMIT(int value) {
return LIMIT(String.valueOf(value));
}
/**
* 给游标#{offset}赋值内容
* Set the offset variable string(e.g. {@code "#{offset}"}).
*
* @param variable a offset variable string
* @return a self instance
* @see #LIMIT(String)
* @since 3.5.2
*/
public T OFFSET(String variable) {
sql().offset = variable;
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.OFFSET_LIMIT;
return getSelf();
}
/**
* 设置游标值
* Set the offset value.
*
* @param value an offset value
* @return a self instance
* @see #LIMIT(int)
* @since 3.5.2
*/
public T OFFSET(long value) {
return OFFSET(String.valueOf(value));
}
/**
* Set the fetch first rows variable string(e.g. {@code "#{fetchFirstRows}"}).
* 给fetchFirstRows变量赋值
* @param variable a fetch first rows variable string
* @return a self instance
* @see #OFFSET_ROWS(String)
* @since 3.5.2
*/
public T FETCH_FIRST_ROWS_ONLY(String variable) {
sql().limit = variable;
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO;
return getSelf();
}
/**
* 用于DB2数据库的分页查询返回值
* Set the fetch first rows value.
*
* @param value a fetch first rows value
* @return a self instance
* @see #OFFSET_ROWS(long)
* @since 3.5.2
*/
public T FETCH_FIRST_ROWS_ONLY(int value) {
return FETCH_FIRST_ROWS_ONLY(String.valueOf(value));
}
/**
* 用于DB2数据库的分页下标查询
* Set the offset rows variable string(e.g. {@code "#{offset}"}).
*
* @param variable a offset rows variable string
* @return a self instance
* @see #FETCH_FIRST_ROWS_ONLY(String)
* @since 3.5.2
*/
public T OFFSET_ROWS(String variable) {
sql().offset = variable;
sql().limitingRowsStrategy = SQLStatement.LimitingRowsStrategy.ISO;
return getSelf();
}
/**
* 设置行数查询的下标
* Set the offset rows value.
*
* @param value an offset rows value
* @return a self instance
* @see #FETCH_FIRST_ROWS_ONLY(int)
* @since 3.5.2
*/
public T OFFSET_ROWS(long value) {
return OFFSET_ROWS(String.valueOf(value));
}
/*
* used to add a new inserted row while do multi-row insert.
* 用于多行插入的时候,多添加一行SQL
* @since 3.5.2
*/
public T ADD_ROW() {
sql().valuesList.add(new ArrayList<>());
return getSelf();
}
private SQLStatement sql() {
return sql;
}
//使用usingAppender函数返回原对象
public <A extends Appendable> A usingAppender(A a) {
sql().sql(a);
return a;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sql().sql(sb);
return sb.toString();
}
//静态内部安全可扩展类,
private static class SafeAppendable {
//来源jdk,并非线程安全类,由继承者或者实现者来保护接口的安全性
private final Appendable a;
private boolean empty = true;
//实现了SafeAppendable创建时候,封装的内部为Appendable接口对象
public SafeAppendable(Appendable a) {
super();
this.a = a;
}
//追加字符串
public SafeAppendable append(CharSequence s) {
try {
if (empty && s.length() > 0) {
empty = false;
}
a.append(s);
} catch (IOException e) {
throw new RuntimeException(e);
}
return this;
}
//判断是否为空对象
public boolean isEmpty() {
return empty;
}
}
//静态内部私有类
private static class SQLStatement {
//定义内部枚举类声明关键字DML操作
public enum StatementType {
DELETE, INSERT, SELECT, UPDATE
}
//私有枚举类限制函数策略
private enum LimitingRowsStrategy {
//不需要分页或者适用于SQLServer数据库
NOP {
@Override
protected void appendClause(SafeAppendable builder, String offset, String limit) {
// NOP
}
},
//处理DB2数据库
ISO {
@Override
protected void appendClause(SafeAppendable builder, String offset, String limit) {
if (offset != null) {
builder.append(" OFFSET ").append(offset).append(" ROWS");
}
if (limit != null) {
builder.append(" FETCH FIRST ").append(limit).append(" ROWS ONLY");
}
}
},
//处理mysql
OFFSET_LIMIT {
@Override
protected void appendClause(SafeAppendable builder, String offset, String limit) {
if (limit != null) {
builder.append(" LIMIT ").append(limit);
}
if (offset != null) {
builder.append(" OFFSET ").append(offset);
}
}
};
protected abstract void appendClause(SafeAppendable builder, String offset, String limit);
}
//DML关键字类型声明
StatementType statementType;
//set字段集合
List<String> sets = new ArrayList<>();
//select字段集合
List<String> select = new ArrayList<>();
//tables集合
List<String> tables = new ArrayList<>();
//join集合
List<String> join = new ArrayList<>();
//内连join集合
List<String> innerJoin = new ArrayList<>();
//外连join集合
List<String> outerJoin = new ArrayList<>();
//左连join集合
List<String> leftOuterJoin = new ArrayList<>();
//右连join集合
List<String> rightOuterJoin = new ArrayList<>();
//where集合
List<String> where = new ArrayList<>();
//having集合
List<String> having = new ArrayList<>();
//groupBy集合
List<String> groupBy = new ArrayList<>();
//orderBy集合
List<String> orderBy = new ArrayList<>();
//
List<String> lastList = new ArrayList<>();
//字段列集合
List<String> columns = new ArrayList<>();
//字段值集合
List<List<String>> valuesList = new ArrayList<>();
//区别boolean值
boolean distinct;
//下标
String offset;
//行数
String limit;
//限制行策略默认不限制
LimitingRowsStrategy limitingRowsStrategy = LimitingRowsStrategy.NOP;
//空构造函数初始化字段值
public SQLStatement() {
// Prevent Synthetic Access
valuesList.add(new ArrayList<>());
}
//sql约定条款处理builder内容
private void sqlClause(SafeAppendable builder, String keyword, List<String> parts, String open, String close,
String conjunction) {
//如果关键字不为空
if (!parts.isEmpty()) {
//如果构建关键字不为空则追加换行
if (!builder.isEmpty()) {
builder.append("\n");
}
//构建器追加DML的关键字
builder.append(keyword);
//追加空格区分sql语句
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);
}
}
//selectSQL
private String selectSQL(SafeAppendable builder) {
//如果去重则select拼接去重逻辑
if (distinct) {
sqlClause(builder, "SELECT DISTINCT", select, "", "", ", ");
} else {
sqlClause(builder, "SELECT", select, "", "", ", ");
}
//from拼接
sqlClause(builder, "FROM", tables, "", "", ", ");
//连表拼接
joins(builder);
//where连接
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
//group by连接
sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
//having 连接
sqlClause(builder, "HAVING", having, "(", ")", " AND ");
//order by连接
sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
//限制行数策略
limitingRowsStrategy.appendClause(builder, offset, limit);
//返回SQL拼接
return builder.toString();
}
//封装连表查询的内容
private void joins(SafeAppendable builder) {
sqlClause(builder, "JOIN", join, "", "", "\nJOIN ");
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 ");
}
//插入SQL语句的封装
private String insertSQL(SafeAppendable builder) {
sqlClause(builder, "INSERT INTO", tables, "", "", "");
sqlClause(builder, "", columns, "(", ")", ", ");
for (int i = 0; i < valuesList.size(); i++) {
sqlClause(builder, i > 0 ? "," : "VALUES", valuesList.get(i), "(", ")", ", ");
}
return builder.toString();
}
//删除SQL语句的封装
private String deleteSQL(SafeAppendable builder) {
sqlClause(builder, "DELETE FROM", tables, "", "", "");
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
limitingRowsStrategy.appendClause(builder, null, limit);
return builder.toString();
}
//更新SQL语句的封装
private String updateSQL(SafeAppendable builder) {
sqlClause(builder, "UPDATE", tables, "", "", "");
joins(builder);
sqlClause(builder, "SET", sets, "", "", ", ");
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
limitingRowsStrategy.appendClause(builder, null, limit);
return builder.toString();
}
//将SQL对象转化为String的SQL语句
public String sql(Appendable a) {
SafeAppendable builder = new SafeAppendable(a);
if (statementType == null) {
return null;
}
String answer;
switch (statementType) {
case DELETE:
answer = deleteSQL(builder);
break;
case INSERT:
answer = insertSQL(builder);
break;
case SELECT:
answer = selectSQL(builder);
break;
case UPDATE:
answer = updateSQL(builder);
break;
default:
answer = null;
}
return answer;
}
}
}