ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

APIJSON 博客3 AbstractSQLConfig 第三篇

2021-10-16 20:05:30  阅读:176  来源: 互联网

标签:APIJSON 第三篇 false AbstractSQLConfig CACHE boolean SQL schema String


2021SC@SDUSC

这一篇博客来分析一下SQLConfig,方便进行后续对AbstractSQLConfig的分析

	String DATABASE_MYSQL = "MYSQL";
	String DATABASE_POSTGRESQL = "POSTGRESQL";
	String DATABASE_SQLSERVER = "SQLSERVER";
	String DATABASE_ORACLE = "ORACLE";
	String DATABASE_DB2 = "DB2";
	String DATABASE_CLICKHOUSE = "CLICKHOUSE";

	String SCHEMA_INFORMATION = "information_schema";  //MySQL, PostgreSQL, SQL Server 都有的系统模式
	String SCHEMA_SYS = "sys";  //SQL Server 系统模式
	String TABLE_SCHEMA = "table_schema";
	String TABLE_NAME = "table_name";

首先是定义了要用到的一些字符串名称,用DATABASE_MYSQL代指字符串MYSQL,方便后续使用,这是一个很好的方式,在需要用的特定字符串上,这样就添加了备注信息。

	int TYPE_CHILD = 0;
	int TYPE_ITEM = 1;
	int TYPE_ITEM_CHILD_0 = 2;

	boolean isMySQL();
	boolean isPostgreSQL();
	boolean isSQLServer();
	boolean isOracle();
	boolean isDb2();
	boolean isClickHouse();

    boolean limitSQLCount(); //用来给 Table, Column 等系统属性表来绕过 MAX_SQL_COUNT 等限制 

接下来定义了一些boolean函数

在SQLConfig中,定义的方法由以下代码实现。

代码分析

boolean limitSQLCount(); //用来给 Table, Column 等系统属性表来绕过 MAX_SQL_COUNT 等限制 

    @Override
    public boolean limitSQLCount() {
        return Log.DEBUG == false || AbstractVerifier.SYSTEM_ACCESS_MAP.containsKey(getTable()) == false;
    }

这里AbstractSQLConfig重写了limitSQLCount()

用到了 apijson.Log 里面的 Log.DEBUG和AbstractVerifier.SYSTEM_ACCESS_MAP.containsKey(getTable())

进行判断后返回他们的或结果

后面同样是重写了SQLConfig的方法,后面三百到六百行都是对SQLConfig方法的重写,这里选出重写比较复杂的代码进行解析。

	public AbstractSQLConfig setSchema(String schema) {
		if (schema != null) {
			String quote = getQuote();
			String s = schema.startsWith(quote) && schema.endsWith(quote) ? schema.substring(1, schema.length() - 1) : schema;
			if (StringUtil.isEmpty(s, true) == false && StringUtil.isName(s) == false) {
				throw new IllegalArgumentException("@schema:value 中value必须是1个单词!");
			}
		}
		this.schema = schema;
		return this;
	}

schema是表所在的数据库名,这里调用了apijson.StringUtil这个类,加入了一个对库名的判断是否为空,调用apijson.StringUtil中的方法解决可能的报错。

另一处较为复杂的是对getgroupString()的重写

@JSONField(serialize = false)
	public String getGroupString(boolean hasPrefix) {
		//加上子表的 group
		String joinGroup = "";
		if (joinList != null) {
			SQLConfig cfg;
			String c;
			boolean first = true;
			for (Join j : joinList) {
				if (j.isAppJoin()) {
					continue;
				}

				cfg = j.isLeftOrRightJoin() ? j.getOuterConfig() : j.getJoinConfig();
				if (StringUtil.isEmpty(cfg.getAlias(), true)) {
					cfg.setAlias(cfg.getTable());
				}

				c = ((AbstractSQLConfig) cfg).getGroupString(false);
				if (StringUtil.isEmpty(c, true) == false) {
					joinGroup += (first ? "" : ", ") + c;
					first = false;
				}

			}
		}


		group = StringUtil.getTrimedString(group);
		String[] keys = StringUtil.split(group);
		if (keys == null || keys.length <= 0) {
			return StringUtil.isEmpty(joinGroup, true) ? "" : (hasPrefix ? " GROUP BY " : "") + joinGroup;
		}

		for (int i = 0; i < keys.length; i++) {
			if (isPrepared()) { //不能通过 ? 来代替,因为SQLExecutor statement.setString后 GROUP BY 'userId' 有单引号,只能返回一条数据,必须去掉单引号才行!
				if (StringUtil.isName(keys[i]) == false) {
					throw new IllegalArgumentException("@group:value 中 value里面用 , 分割的每一项都必须是1个单词!并且不要有空格!");
				}
			}

			keys[i] = getKey(keys[i]);
		}

		return (hasPrefix ? " GROUP BY " : "") + StringUtil.concat(StringUtil.getString(keys), joinGroup, ", ");
	}

首先参数是前缀Prefix,joinList 不为空时,对cfg进行判断,用到了j.isLeftOrRightJoin() ? j.getOuterConfig() : j.getJoinConfig();这里涉及到了StringUtil中的方法,从return中我们可以得知,返回的内容是判断了GROUP BY,返回了SQL中关于分组判断的信息。

下一组比较复杂的方法是String getHavingString(boolean hasPrefix)

知识学习

String getHavingString(boolean hasPrefix)和getgroupString()都用到了下面这个引用

com.alibaba.fastjson.annotation.JSONField

使用场景:字段和方法

1、字段:根据@JSONField(name=“XXX”) 中的name 对string转换为类时name中的描述就是转换后的字段名称

2、方法:在set方法前和在get方法前

当JSON.parseObject(str,class)方法被调用时,set方法被调用,方法上面的@JSONField(name="XXX")中的XXX属性,将json中的XXXkey被赋值到set方法描述的属性中。

当JSON.toJSONString(dto)方法被调用时,get方法被调用,方法上面的@JSONField(name="XXX")中的XXX属性,就是得到的jsonString中的属性的key。

 在String getHavingString(boolean hasPrefix)中,前半段跟getgroupString()相同,后面增加了额外的判断机制,用来判断SQL请求中不合法情况的错误。

包括 

1.expression.length() > 50 长度过长情况

2.isPrepared() && PATTERN_FUNCTION.matcher(expression).matches() == false 不符合正则表达式情况

3.start >= end value 中 value 里的 SQL函数必须为 function(arg0,arg1,...) 这种格式

4.StringUtil.isName(method) == false 必须符合小写英文单词的 SQL 函数名格式

5.SQL_FUNCTION_MAP.containsKey(method) == false function 必须符合小写英文单词的 SQL 函数名格式,且必须是后端允许调用的 SQL 函数

6.isPrepared() && (((String) suffix).contains("--") || ((String) suffix).contains("/*") || PATTERN_RANGE.matcher((String) suffix).matches() == false) 必须符合正则表达式且不包含连续减号 -- 或注释符 /* !不允许多余的空格

7.origin.startsWith("_") || origin.contains("--") || PATTERN_FUNCTION.matcher(origin).matches() == false 所有 column, arg 都必须是1个不以 _ 开头的单词 或者 符合正则表达式且不包含连续减号 -- !不允许多余的空格

最后正确return一个Having语句。

下面840-1030行同样是一些override,都是调用了this方法,所以我们不进行过多赘述

以下是一个请求方法的错误判断

public String getColumnString(boolean inSQLJoin) throws Exception

return isMain() && isDistinct() ? PREFFIX_DISTINCT + c : c;

其中的判断方法与上述的错误类型大致相同,写明了各种错误类型的判断。

	public static int getCache(String cache) {
		int cache2;
		if (cache == null) {
			cache2 = JSONRequest.CACHE_ALL;
		}
		else {
			//			if (isSubquery) {
			//				throw new IllegalArgumentException("子查询内不支持传 " + JSONRequest.KEY_CACHE + "!");
			//			}

			switch (cache) {
			case "0":
			case JSONRequest.CACHE_ALL_STRING:
				cache2 = JSONRequest.CACHE_ALL;
				break;
			case "1":
			case JSONRequest.CACHE_ROM_STRING:
				cache2 = JSONRequest.CACHE_ROM;
				break;
			case "2":
			case JSONRequest.CACHE_RAM_STRING:
				cache2 = JSONRequest.CACHE_RAM;
				break;
			default:
				throw new IllegalArgumentException(JSONRequest.KEY_CACHE + ":value 中 value 的值不合法!必须在 [0,1,2] 或 [ALL, ROM, RAM] 内 !");
			}
		}
		return cache2;
	}

这是一个getCache方法,用到了JSONRequest,而JSONRequest又extends JSONObject,所以我们能看到的JSONRequest.CACHE_ALL_STRING等都来自JSONObject

    public static final int CACHE_ALL = 0;
    public static final int CACHE_ROM = 1;
    public static final int CACHE_RAM = 2;

    public static final String CACHE_ALL_STRING = "ALL";
    public static final String CACHE_ROM_STRING = "ROM";
    public static final String CACHE_RAM_STRING = "RAM";

这些是在JSONObject中定义好的变量

知识学习

MySQL缓存机制即缓存sql 文本及缓存结果,用KV形式保存再服务器内存中,如果运行相同的sql,服务器直接从缓存中去获取结果,不需要再去解析、优化、执行sql

  1. 服务器接收SQL,以SQL和一些其他条件为key查找缓存表
  2. 如果缓存命中,则直接返回缓存
  3. 如果缓存没有命中,则执行SQL查询,包括SQL解析、优化等。
  4. 执行完SQL查询结果以后,将SQL查询结果写入缓存表
  • MySQL缓存机制会在内存中开辟一块内存(query_cache_size)区来维护缓存数据,其中大概有40K的空间是用来维护缓存数据的元数据的,例如空间内存、数据表和查询结果的映射,SQL和查询结果的映射。
  • MySQL缓存机制将大内存块分为小内存块(query_cache_min_res_unit),每个小块中存储自身的类型、大小和查询结果数据,还有前后内存块的指针。
  • MySQL缓存机制会在SQL查询开始(还未得到结果)时就去申请一块内存空间,所以即使缓存数据没有达到这个大小也需要占用申请的内存块空间(like linux filesystem’s block)。如果超出申请内存块的大小,则需要再申请一个内存块。当查询完成发现申请的内存有富余,则会将富余的内存空间释放掉,因而可能会造成内存碎片。

小结:AbstractSQLConfig重写了其他类的方法,定义了一些方法,与其它类的关系繁杂,所以分析是往往要先去看他引用到的类,而引用到的类又会引用其他类,所以 AbstractSQLConfig是和其它类的关系都是合作完成,这让我真正的一个项目不是单单的先后顺序,而是复杂的交织关系,有不同的类共同完成任务。

以上就是本周对APIJSON项目中AbstractSQLConfig的分析

记录位置为1462行

 

 

标签:APIJSON,第三篇,false,AbstractSQLConfig,CACHE,boolean,SQL,schema,String
来源: https://blog.csdn.net/csascscascd/article/details/120772001

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有