mybatis執行長難sql語句-通過反射替換mybatis綁定的sql語句

終於接觸一點mybatis高階一點的用法了 真實知識是個浩瀚無垠的海洋啊

正文

今天遇到的業務場景是這樣的。兩個數據庫,主庫和從庫,希望通過springboot項目把主庫中的表結構同步到從庫中。也就是在從庫中建表,但表結構不確定。因此不能使用統一的sql語句,需要根據不同表拼接sql。

  • 所以主要學習了一下mybatis的進階知識;
  • 看過技術文獻後我的解決辦法主要是通過反射把要執行的sql語句替換成自己已經拼接好的。

我主要看的文檔是這個 <mybatis技術文檔鏈接>
以及通過idea看一點源碼;
重新把自己的感悟寫一下

mybatis

數據庫接口層

這個是和數據庫打交道,直接對數據庫增刪改查。主要涉及到的執行類爲SqlSession
SqlSessionFactory—>SqlSession
SqlSession 可以直接執行相應的statement,也可以通過Mapper接口執行;

sql綁定與結果解析

主要涉及到了

  • BoundSql綁定具體sql語句;
  • SqlSource 構建BoundSql對象;
  • MappedStatement 每個註解或者xml中的sql函數對應一個MappedStatement
  • Configuration mybatis外部配置類
  • ResultMap 具體查詢結果與java中類的轉換

所以,看到這些後我主要想到:把BoundSql中的sql語句綁定成我自己的就好了。

框架支撐

  • 註解配置sql語句
  • xml配置sql語句

我的動態sql語句生成類:

public List<String> createTableSql(DbTableInfo dbTableInfo) {
		List<String> sqls = Collections.emptyList();
		
		if (dbTableInfo != null && dbTableInfo.getTableStructure() != null
				&& !dbTableInfo.getTableStructure().isEmpty()) {
			sqls = dbTableInfo.getTableStructure().entrySet().stream().map(e -> {
				StringBuilder sb = new StringBuilder();
				sb.append("CREATE TABLE `" + e.getKey() + "` (");
				List<RowInfo> rows = e.getValue();
				for (RowInfo row : rows) {
					sb.append("`" + row.getFieldName() + "` ");
					sb.append(row.getFieldType() + " COMMENT '" + row.getFieldComment() + "',");
				}
				String tempSql = sb.toString();
				String sql = tempSql.substring(0, tempSql.length() - 1) + ");";
				return sql;
			}).collect(Collectors.toList());
		}
		return sqls;
	}

通過反射獲得具體feild,並將對象的feild重新設置:

private void dynamicReplaceSqlStatementIfNecessary(String sql, String sqlStatementId) {
		if (StringUtils.hasText(sql)) {
			Configuration configuration = sqlSessionFactory.getConfiguration();
			MappedStatement mappedStatement = configuration.getMappedStatement(sqlStatementId);
			SqlSource sqlSource = mappedStatement.getSqlSource();
			if (sqlSource instanceof StaticSqlSource && sqlSource.getBoundSql(null).getSql().equalsIgnoreCase(sql)) {
				return;
			}
			try {
				Field sqlSourceField = mappedStatement.getClass().getDeclaredField("sqlSource");//反射
				sqlSourceField.setAccessible(true);
				sqlSourceField.set(mappedStatement, new StaticSqlSource(mappedStatement.getConfiguration(), sql));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

還是要多看源碼,多看大神總結的文章啊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章