代码分析(五)

2021SC@SDUSC

SQLConfig接口–配置SQL

首先就是对各个不同的数据库进行全部划分,以便于后面对于不同数据库的匹配

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";

然后就是给出的接口方法:


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

作用就是去判断当前使用的数据库是什么类型,以便于进行后续操作

boolean limitSQLCount(); 

下面是一些限制:

最大单个数据库大小 不限
最大数据单表大小 32 TB
单条记录最大 1.6 TB
单字段最大允许 1 GB
单表允许最大记录数 不限
单表最大字段数 250 - 1600 (取决于字段类型)
单表最大索引数 不限

当然,实际上没有真正的无限制,还是要受系统可用磁盘空间、可用内存/交换区的制约。 事实上,当上述这些数值变得异常地大时,系统性能也会受很大影响。而我们的这个limitSQLCount方法就是用来给 Table, Column 等系统属性表来绕过 MAX_SQL_COUNT 等限制

然后就是具体的一些操作

String getDBVersion();

	String getDBUri();
	String getDBAccount();
	String getDBPassword();
	String getSQL(boolean prepared) throws Exception;

首先就是获取数据库版本号,可通过判断版本号解决一些 JDBC 驱动连接数据库的兼容问题比如 MYSQL: 8.0, 5.7, 5.6 等; PostgreSQL: 11, 10, 9.6 等
然后就是获取数据库地址
在之后获取数据库账号
获取数据库密码
获取SQL语句

接下来是一些get/set方法,这些都是作者设置的一些规则,设置的时候的类型为SQLConfig类型,get的时候就是他们本身各自的属性类型

boolean isTest();
	SQLConfig setTest(boolean test);

	int getType();
	SQLConfig setType(int type);

	int getCount();
	SQLConfig setCount(int count);

	int getPage();
	SQLConfig setPage(int page);

	int getQuery();
	SQLConfig setQuery(int query);

	int getPosition();
	SQLConfig setPosition(int position);

	int getCache();
	SQLConfig setCache(int cache);

	boolean isExplain();
	SQLConfig setExplain(boolean explain);

    List<Join> getJoinList();

	SQLConfig setJoinList(List<Join> joinList);

比如其中的setJoinList方法的作用:
在分析过的AbstractSQLConfig类里面有它的具体应用:

首先看一下JOIN类型的具体数据

private String path;

	private String originKey;
	private String originValue;

	private String joinType; // "@" - APP, "<" - LEFT, ">" - RIGHT, "*" - CROSS, "&" - INNER, "|" - FULL, "!" - OUTER, "^" - SIDE, "(" - ANTI, ")" - FOREIGN
	private String relateType; // "" - 一对一, "{}" - 一对多, "<>" - 多对一
	private JSONObject request; // { "id@":"/Moment/userId" }
	private String table; //User
	private String alias; //owner
	private String key; //id
	private String targetTable; // Moment
	private String targetAlias; //main
	private String targetKey; // userId

	private JSONObject outter;

	private SQLConfig joinConfig;
	private SQLConfig cacheConfig;
	private SQLConfig outterConfig;

这个是JOIN类型具体含有的各项属性。
然后看一下它的具体实现:

	public static SQLConfig parseJoin(RequestMethod method, SQLConfig config, List<Join> joinList, Callback callback) throws Exception {
		boolean isQuery = RequestMethod.isQueryMethod(method);
		config.setKeyPrefix(isQuery && config.isMain() == false);

		if (joinList == null || joinList.isEmpty() || RequestMethod.isQueryMethod(method) == false) {
			return config;
		}
		String table;
		String alias;
		for (Join j : joinList) {
			table = j.getTable();
			alias = j.getAlias();
			//JOIN子查询不能设置LIMIT,因为ON关系是在子查询后处理的,会导致结果会错误
			SQLConfig joinConfig = newSQLConfig(method, table, alias, j.getRequest(), null, false, callback);
			SQLConfig cacheConfig = j.canCacheViceTable() == false ? null : newSQLConfig(method, table, alias, j.getRequest(), null, false, callback).setCount(1);

			if (j.isAppJoin() == false) { //除了 @ APP JOIN,其它都是 SQL JOIN,则副表要这样配置
				if (joinConfig.getDatabase() == null) {
					joinConfig.setDatabase(config.getDatabase()); //解决主表 JOIN 副表,引号不一致
				}
				else if (joinConfig.getDatabase().equals(config.getDatabase()) == false) {
					throw new IllegalArgumentException("主表 " + config.getTable() + " 的 @database:" + config.getDatabase() + " 和它 SQL JOIN 的副表 " + table + " 的 @database:" + joinConfig.getDatabase() + " 不一致!");
				}
				if (joinConfig.getSchema() == null) {
					joinConfig.setSchema(config.getSchema()); //主表 JOIN 副表,默认 schema 一致
				}
				
				if (cacheConfig != null) {
					cacheConfig.setDatabase(joinConfig.getDatabase()).setSchema(joinConfig.getSchema()); //解决主表 JOIN 副表,引号不一致
				}


				if (isQuery) {
					config.setKeyPrefix(true);
				}

				joinConfig.setMain(false).setKeyPrefix(true);

				if (j.isLeftOrRightJoin()) {
					SQLConfig outterConfig = newSQLConfig(method, table, alias, j.getOuter(), null, false, callback);
					outterConfig.setMain(false).setKeyPrefix(true).setDatabase(joinConfig.getDatabase()).setSchema(joinConfig.getSchema()); //解决主表 JOIN 副表,引号不一致
					j.setOuterConfig(outterConfig);
				}
			}

			//解决 query: 1/2 查数量时报错  
			/* SELECT  count(*)  AS count  FROM sys.Moment AS Moment  
			   LEFT JOIN ( SELECT count(*)  AS count FROM sys.Comment ) AS Comment ON Comment.momentId = Moment.id LIMIT 1 OFFSET 0 */
			if (RequestMethod.isHeadMethod(method, true)) {
				joinConfig.setMethod(GET); //子查询不能为 SELECT count(*) ,而应该是 SELECT momentId
				joinConfig.setColumn(Arrays.asList(j.getKey())); //优化性能,不取非必要的字段

				if (cacheConfig != null) {
					cacheConfig.setMethod(GET); //子查询不能为 SELECT count(*) ,而应该是 SELECT momentId
					cacheConfig.setColumn(Arrays.asList(j.getKey())); //优化性能,不取非必要的字段
				}
			}

			j.setJoinConfig(joinConfig);
			j.setCacheConfig(cacheConfig);
		}

		config.setJoinList(joinList);

		return config;
	}

方法首先是解析出 SQLConfig 再合并 column, order, group 等,在这里然后是对JoinList进行判断后,再对JoinList进行一顿循环遍历后,将其中的每个join都进行分别的处理,然后获取到每个join里面的数据,并加入到我们的SQLConfig里面,之后将config的JoinList设置为此JoinList然后返回config。这里面它是进行了一个性能的优化:

    joinConfig.setColumn(Arrays.asList(j.getKey())); 

	cacheConfig.setColumn(Arrays.asList(j.getKey()));

其实这种优化的手段是很常见的,就是预设值,也就使得相当于我们的动态规划,怎么讲呢?就是说,我么你在实际获取的时候是会先进行一次内部值的判断,如果已经存在,那么便不用再耗费性能去查询,也就优化了实际的性能。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值