主頁 > 資料庫 > 一文掌握MyBatis的動態SQL使用與原理

一文掌握MyBatis的動態SQL使用與原理

2022-12-24 07:06:33 資料庫

摘要:使用動態 SQL 并非一件易事,但借助可用于任何 SQL 映射陳述句中的強大的動態 SQL 語言,MyBatis 顯著地提升了這一特性的易用性,

本文分享自華為云社區《MyBatis詳解 - 動態SQL使用與原理》,作者:龍哥手記 ,

動態 SQL 是 MyBatis 的強大特性之一,如果你使用過 JDBC 或其它類似的框架,你應該能理解根據不同條件拼接 SQL 陳述句有多痛苦,例如拼接時要確保不能忘記添加必要的空格,還要注意去掉串列最后一個列名的逗號,利用動態 SQL,可以徹底擺脫這種痛苦,

使用動態 SQL 并非一件易事,但借助可用于任何 SQL 映射陳述句中的強大的動態 SQL 語言,MyBatis 顯著地提升了這一特性的易用性,

如果你之前用過 JSTL 或任何基于類 XML 語言的文本處理器,你對動態 SQL 元素可能會感覺似曾相識,在 MyBatis 之前的版本中,需要花時間了解大量的元素,借助功能強大的基于 OGNL 的運算式,MyBatis 3 替換了之前的大部分元素,大大精簡了元素種類,現在要學習的元素種類比原來的一半還要少,

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

if

使用動態 SQL 最常見情景是根據條件包含 where 子句的一部分,比如:

<select id="findActiveBlogWithTitleLike"
 resultType="Blog">
  SELECT * FROM BLOG
  WHERE state = ‘ACTIVE’
 <if test="title != null">
    AND title like #{title}
 </if>
</select>

這條陳述句提供了可選的查找文本功能,如果不傳入 “title”,那么所有處于 “ACTIVE” 狀態的 BLOG 都會回傳;如果傳入了 “title” 引數,那么就會對 “title” 一列進行模糊查找并回傳對應的 BLOG 結果(細心的讀者可能會發現,“title” 的引數值需要包含查找掩碼或通配符字符),

如果希望通過 “title” 和 “author” 兩個引數進行可選搜索該怎么辦呢?首先,我想先將陳述句名稱修改成更名副其實的名稱;接下來,只需要加入另一個條件即可,

<select id="findActiveBlogLike"
 resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
 <if test="title != null">
    AND title like #{title}
 </if>
 <if test="author != null and author.name != null">
    AND author_name like #{author.name}
 </if>
</select>

choose、when、otherwise

有時候,我們不想使用所有的條件,而只是想從多個條件中選擇一個使用,針對這種情況,MyBatis 提供了 choose 元素,它有點像 Java 中的 switch 陳述句,

還是上面的例子,但是策略變為:傳入了 “title” 就按 “title” 查找,傳入了 “author” 就按 “author” 查找的情形,若兩者都沒有傳入,就回傳標記為 featured 的 BLOG(這可能是管理員認為,與其回傳大量的無意義隨機 Blog,還不如回傳一些由管理員挑選的 Blog),

<select id="findActiveBlogLike"
 resultType="Blog">
  SELECT * FROM BLOG WHERE state = ‘ACTIVE’
 <choose>
 <when test="title != null">
      AND title like #{title}
 </when>
 <when test="author != null and author.name != null">
      AND author_name like #{author.name}
 </when>
 <otherwise>
      AND featured = 1
 </otherwise>
 </choose>
</select>

trim、where、set

前面幾個例子已經合宜地解決了一個臭名昭著的動態 SQL 問題,現在回到之前的 “if” 示例,這次我們將 “state = ‘ACTIVE’” 設定成動態條件,看看會發生什么,

<select id="findActiveBlogLike"
 resultType="Blog">
  SELECT * FROM BLOG
  WHERE
 <if test="state != null">
    state = #{state}
 </if>
 <if test="title != null">
    AND title like #{title}
 </if>
 <if test="author != null and author.name != null">
    AND author_name like #{author.name}
 </if>
</select>

如果沒有匹配的條件會怎么樣?最終這條 SQL 會變成這樣:

SELECT * FROM BLOG
WHERE

這會導致查詢失敗,如果匹配的只是第二個條件又會怎樣?這條 SQL 會是這樣:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

這個查詢也會失敗,這個問題不能簡單地用條件元素來解決,這個問題是如此的難以解決,以至于解決過的人不會再想碰到這種問題,

MyBatis 有一個簡單且適合大多數場景的解決辦法,而在其他場景中,可以對其進行自定義以符合需求,而這,只需要一處簡單的改動:

<select id="findActiveBlogLike"
 resultType="Blog">
  SELECT * FROM BLOG
 <where>
 <if test="state != null">
         state = #{state}
 </if>
 <if test="title != null">
        AND title like #{title}
 </if>
 <if test="author != null and author.name != null">
        AND author_name like #{author.name}
 </if>
 </where>
</select>

where 元素只會在子元素回傳任何內容的情況下才插入 “WHERE” 子句,而且,若子句的開頭為 “AND” 或 “OR”,where 元素也會將它們去除,

如果 where 元素與你期望的不太一樣,你也可以通過自定義 trim 元素來定制 where 元素的功能,比如,和 where 元素等價的自定義 trim 元素為:

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

prefixOverrides 屬性會忽略通過管道符分隔的文本序列(注意此例中的空格是必要的),上述例子會移除所有 prefixOverrides 屬性中指定的內容,并且插入 prefix 屬性中指定的內容,

用于動態更新陳述句的類似解決方案叫做 set,set 元素可以用于動態包含需要更新的列,忽略其它不更新的列,比如:

<update id="updateAuthorIfNecessary">
  update Author
 <set>
 <if test="username != null">username=#{username},</if>
 <if test="password != null">password=#{password},</if>
 <if test="email != null">email=#{email},</if>
 <if test="bio != null">bio=#{bio}</if>
 </set>
  where id=#{id}
</update>

這個例子中,set 元素會動態地在行首插入 SET 關鍵字,并會刪掉額外的逗號(這些逗號是在使用條件陳述句給列賦值時引入的),

來看看與 set 元素等價的自定義 trim 元素吧:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

注意,我們覆寫了后綴值設定,并且自定義了前綴值,

foreach

動態 SQL 的另一個常見使用場景是對集合進行遍歷(尤其是在構建 IN 條件陳述句的時候),比如:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
 <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
 </foreach>
</select>

foreach 元素的功能非常強大,它允許你指定一個集合,宣告可以在元素體內使用的集合項(item)和索引(index)變數,它也允許你指定開頭與結尾的字串以及集合項迭代之間的分隔符,這個元素也不會錯誤地添加多余的分隔符,看它多智能!

提示:你可以將任何可迭代物件(如 List、Set 等)、Map 物件或者陣列物件作為集合引數傳遞給 foreach,當使用可迭代物件或者陣列時,index 是當前迭代的序號,item 的值是本次迭代獲取到的元素,當使用 Map 物件(或者 Map.Entry 物件的集合)時,index 是鍵,item 是值,

至此,我們已經完成了與 XML 配置及映射檔案相關的討論,下一章將詳細探討 Java API,以便你能充分利用已經創建的映射配置,

script

要在帶注解的映射器介面類中使用動態 SQL,可以使用 script 元素,比如:

 @Update({"<script>",
 "update Author",
 "  <set>",
 "    <if test='username != null'>username=#{username},</if>",
 "    <if test='password != null'>password=#{password},</if>",
 "    <if test='email != null'>email=#{email},</if>",
 "    <if test='bio != null'>bio=#{bio}</if>",
 "  </set>",
 "where id=#{id}",
 "</script>"})
 void updateAuthorValues(Author author);

bind

bind 元素允許你在 OGNL 運算式以外創建一個變數,并將其系結到當前的背景關系,比如:

<select id="selectBlogsLike" resultType="Blog">
 <bind name="pattern" value=https://www.cnblogs.com/huaweiyun/archive/2022/12/23/"'%' + _parameter.getTitle() + '%'" />
  SELECT * FROM BLOG
  WHERE title LIKE #{pattern}
</select>

多資料庫支持

如果配置了 databaseIdProvider,你就可以在動態代碼中使用名為 “_databaseId” 的變數來為不同的資料庫構建特定的陳述句,比如下面的例子:

<insert id="insert">
 <selectKey keyProperty="id" resultType="int" order="BEFORE">
 <if test="_databaseId == 'oracle'">
      select seq_users.nextval from dual
 </if>
 <if test="_databaseId == 'db2'">
      select nextval for seq_users from sysibm.sysdummy1"
 </if>
 </selectKey>
  insert into users values (#{id}, #{name})
</insert>

動態 SQL 中的插入腳本語言

MyBatis 從 3.2 版本開始支持插入腳本語言,這允許你插入一種語言驅動,并基于這種語言來撰寫動態 SQL 查詢陳述句,

可以通過實作以下介面來插入一種語言:

public interface LanguageDriver {
 ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
 SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
 SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
}

實作自定義語言驅動后,你就可以在 mybatis-config.xml 檔案中將它設定為默認語言:

<typeAliases>
 <typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
</typeAliases>
<settings>
 <setting name="defaultScriptingLanguage" value=https://www.cnblogs.com/huaweiyun/archive/2022/12/23/"myLanguage"/>
</settings>

或者,你也可以使用 lang 屬性為特定的陳述句指定語言:

<select id="selectBlog" lang="myLanguage">
  SELECT * FROM BLOG
</select>

或者,在你的 mapper 介面上添加 @Lang 注解:

public interface Mapper {
 @Lang(MyLanguageDriver.class)
 @Select("SELECT * FROM BLOG")
 List<Blog> selectBlog();
}
提示:可以使用 Apache Velocity 作為動態語言,更多細節請參考 MyBatis-Velocity 專案,

你前面看到的所有 xml 標簽都由默認 MyBatis 語言提供,而它由語言驅動 org.apache.ibatis.scripting.xmltags.XmlLanguageDriver(別名為 xml)所提供,

動態SQL決議原理

我們在使用mybatis的時候,會在xml中撰寫sql陳述句,比如這段動態sql代碼:

<update id="update" parameterType="org.format.dynamicproxy.mybatis.bean.User">
    UPDATE users
 <trim prefix="SET" prefixOverrides=",">
 <if test="name != null and name != ''">
            name = #{name}
 </if>
 <if test="age != null and age != ''">
            , age = #{age}
 </if>
 <if test="birthday != null and birthday != ''">
            , birthday = #{birthday}
 </if>
 </trim>
    where id = ${id}
</update>

mybatis底層是如何構造這段sql的?下面帶著這個疑問,我們一步一步分析,

關于動態SQL的介面和類

SqlNode介面,簡單理解就是xml中的每個標簽,比如上述sql的update,trim,if標簽:

public interface SqlNode {
 boolean apply(DynamicContext context);
}

SqlSource Sql源介面,代表從xml檔案或注解映射的sql內容,主要就是用于創建BoundSql,有實作類DynamicSqlSource(動態Sql源),StaticSqlSource(靜態Sql源)等:

public interface SqlSource {
 BoundSql getBoundSql(Object parameterObject);
}

BoundSql類,封裝mybatis最終產生sql的類,包括sql陳述句,引數,引數源資料等引數:

XNode,一個Dom API中的Node介面的擴展類:

BaseBuilder介面及其實作類(屬性,方法省略了,大家有興趣的自己看),這些Builder的作用就是用于構造sql:

下面我們簡單分析下其中4個Builder:

  • XMLConfigBuilder:決議mybatis中configLocation屬性中的全域xml檔案,內部會使用XMLMapperBuilder決議各個xml檔案,
  • XMLMapperBuilder:遍歷mybatis中mapperLocations屬性中的xml檔案中每個節點的Builder,比如user.xml,內部會使用XMLStatementBuilder處理xml中的每個節點,
  • XMLStatementBuilder:決議xml檔案中各個節點,比如select,insert,update,delete節點,內部會使用XMLScriptBuilder處理節點的sql部分,遍歷產生的資料會丟到Configuration的mappedStatements中,
  • XMLScriptBuilder:決議xml中各個節點sql部分的Builder,

LanguageDriver介面及其實作類(屬性,方法省略了,大家有興趣的自己看),該介面主要的作用就是構造sql:

簡單分析下XMLLanguageDriver(處理xml中的sql,RawLanguageDriver處理靜態sql):XMLLanguageDriver內部會使用XMLScriptBuilder決議xml中的sql部分,

原始碼分析走起

Spring與Mybatis整合的時候需要配置SqlSessionFactoryBean,該配置會加入資料源和mybatis xml組態檔路徑等資訊:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 <property name="dataSource" ref="dataSource"/>
 <property name="configLocation" value=https://www.cnblogs.com/huaweiyun/archive/2022/12/23/"classpath:mybatisConfig.xml"/>
 <property name="mapperLocations" value=https://www.cnblogs.com/huaweiyun/archive/2022/12/23/"classpath*:org/format/dao/*.xml"/>
</bean>

我們就分析這一段配置背后的細節:

SqlSessionFactoryBean實作了Spring的InitializingBean介面,InitializingBean介面的afterPropertiesSet方法中會呼叫buildSqlSessionFactory方法 該方法內部會使用XMLConfigBuilder決議屬性configLocation中配置的路徑,還會使用XMLMapperBuilder屬性決議mapperLocations屬性中的各個xml檔案,部分原始碼如下:

由于XMLConfigBuilder內部也是使用XMLMapperBuilder,我們就看看XMLMapperBuilder的決議細節:

我們關注一下,增刪改查節點的決議:

XMLStatementBuilder的決議:

默認會使用XMLLanguageDriver創建SqlSource(Configuration建構式中設定),

XMLLanguageDriver創建SqlSource:

XMLScriptBuilder決議sql:

得到SqlSource之后,會放到Configuration中,有了SqlSource,就能拿BoundSql了,BoundSql可以得到最終的sql,

實體分析

以下面的xml決議大概說下parseDynamicTags的決議程序:

<update id="update" parameterType="org.format.dynamicproxy.mybatis.bean.User">
    UPDATE users
 <trim prefix="SET" prefixOverrides=",">
 <if test="name != null and name != ''">
            name = #{name}
 </if>
 <if test="age != null and age != ''">
            , age = #{age}
 </if>
 <if test="birthday != null and birthday != ''">
            , birthday = #{birthday}
 </if>
 </trim>
    where id = ${id}
</update>

parseDynamicTags方法的回傳值是一個List,也就是一個Sql節點集合,SqlNode本文一開始已經介紹,分析完決議程序之后會說一下各個SqlNode型別的作用,

首先根據update節點(Node)得到所有的子節點,分別是3個子節點:

  • 文本節點 \n UPDATE users
  • trim子節點 ...
  • 文本節點 \n where id = #

遍歷各個子節點:

  • 如果節點型別是文本或者CDATA,構造一個TextSqlNode或StaticTextSqlNode;
  • 如果節點型別是元素,說明該update節點是個動態sql,然后會使用NodeHandler處理各個型別的子節點,這里的NodeHandler是XMLScriptBuilder的一個內部介面,其實作類包括TrimHandler、WhereHandler、SetHandler、IfHandler、ChooseHandler等,看類名也就明白了這個Handler的作用,比如我們分析的trim節點,對應的是TrimHandler;if節點,對應的是IfHandler...這里子節點trim被TrimHandler處理,TrimHandler內部也使用parseDynamicTags方法決議節點,

遇到子節點是元素的話,重復以上步驟:

trim子節點內部有7個子節點,分別是文本節點、if節點、是文本節點、if節點、是文本節點、if節點、文本節點,文本節點跟之前一樣處理,if節點使用IfHandler處理,遍歷步驟如上所示,下面我們看下幾個Handler的實作細節,

IfHandler處理方法也是使用parseDynamicTags方法,然后加上if標簽必要的屬性:

private class IfHandler implements NodeHandler {
 public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
 List<SqlNode> contents = parseDynamicTags(nodeToHandle);
 MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
 String test = nodeToHandle.getStringAttribute("test");
 IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
 targetContents.add(ifSqlNode);
 }
}

TrimHandler處理方法也是使用parseDynamicTags方法,然后加上trim標簽必要的屬性:

private class TrimHandler implements NodeHandler {
 public void handleNode(XNode nodeToHandle, List<SqlNode> targetContents) {
 List<SqlNode> contents = parseDynamicTags(nodeToHandle);
 MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
 String prefix = nodeToHandle.getStringAttribute("prefix");
 String prefixOverrides = nodeToHandle.getStringAttribute("prefixOverrides");
 String suffix = nodeToHandle.getStringAttribute("suffix");
 String suffixOverrides = nodeToHandle.getStringAttribute("suffixOverrides");
 TrimSqlNode trim = new TrimSqlNode(configuration, mixedSqlNode, prefix, prefixOverrides, suffix, suffixOverrides);
 targetContents.add(trim);
 }
}

以上update方法最終通過parseDynamicTags方法得到的SqlNode集合如下:

trim節點:

由于這個update方法是個動態節點,因此構造出了DynamicSqlSource,DynamicSqlSource內部就可以構造sql了:

DynamicSqlSource內部的SqlNode屬性是一個MixedSqlNode,然后我們看看各個SqlNode實作類的apply方法,下面分析一下各個SqlNode實作類的apply方法實作:

MixedSqlNode:MixedSqlNode會遍歷呼叫內部各個sqlNode的apply方法,

public boolean apply(DynamicContext context) {
 for (SqlNode sqlNode : contents) {
 sqlNode.apply(context);
 }
 return true;
}

StaticTextSqlNode:直接append sql文本,

public boolean apply(DynamicContext context) {
 context.appendSql(text);
 return true;
}

IfSqlNode:這里的evaluator是一個ExpressionEvaluator型別的實體,內部使用了OGNL處理運算式邏輯,

public boolean apply(DynamicContext context) {
 if (evaluator.evaluateBoolean(test, context.getBindings())) {
 contents.apply(context);
 return true;
 }
 return false;
}

TrimSqlNode:

public boolean apply(DynamicContext context) {
 FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
 boolean result = contents.apply(filteredDynamicContext);
 filteredDynamicContext.applyAll();
 return result;
}
public void applyAll() {
 sqlBuffer = new StringBuilder(sqlBuffer.toString().trim());
 String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(Locale.ENGLISH);
 if (trimmedUppercaseSql.length() > 0) {
 applyPrefix(sqlBuffer, trimmedUppercaseSql);
 applySuffix(sqlBuffer, trimmedUppercaseSql);
 }
 delegate.appendSql(sqlBuffer.toString());
}
private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) {
 if (!prefixApplied) {
 prefixApplied = true;
 if (prefixesToOverride != null) {
 for (String toRemove : prefixesToOverride) {
 if (trimmedUppercaseSql.startsWith(toRemove)) {
 sql.delete(0, toRemove.trim().length());
 break;
 }
 }
 }
 if (prefix != null) {
 sql.insert(0, " ");
 sql.insert(0, prefix);
 }
 }
}

TrimSqlNode的apply方法也是呼叫屬性contents(一般都是MixedSqlNode)的apply方法,按照實體也就是7個SqlNode,都是StaticTextSqlNode和IfSqlNode, 最后會使用FilteredDynamicContext過濾掉prefix和suffix,

 

點擊關注,第一時間了解華為云新鮮技術~

轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/540662.html

標籤:其他

上一篇:CloudCanal實戰-五分鐘搞定Oracle到StarRocks資料遷移與同步

下一篇:搭建基于lvs+nginx的負載均衡服務集群

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • GPU虛擬機創建時間深度優化

    **?桔妹導讀:**GPU虛擬機實體創建速度慢是公有云面臨的普遍問題,由于通常情況下創建虛擬機屬于低頻操作而未引起業界的重視,實際生產中還是存在對GPU實體創建時間有苛刻要求的業務場景。本文將介紹滴滴云在解決該問題時的思路、方法、并展示最終的優化成果。 從公有云服務商那里購買過虛擬主機的資深用戶,一 ......

    uj5u.com 2020-09-10 06:09:13 more
  • 可編程網卡芯片在滴滴云網路的應用實踐

    **?桔妹導讀:**隨著云規模不斷擴大以及業務層面對延遲、帶寬的要求越來越高,采用DPDK 加速網路報文處理的方式在橫向縱向擴展都出現了局限性。可編程芯片成為業界熱點。本文主要講述了可編程網卡芯片在滴滴云網路中的應用實踐,遇到的問題、帶來的收益以及開源社區貢獻。 #1. 資料中心面臨的問題 隨著滴滴 ......

    uj5u.com 2020-09-10 06:10:21 more
  • 滴滴資料通道服務演進之路

    **?桔妹導讀:**滴滴資料通道引擎承載著全公司的資料同步,為下游實時和離線場景提供了必不可少的源資料。隨著任務量的不斷增加,資料通道的整體架構也隨之發生改變。本文介紹了滴滴資料通道的發展歷程,遇到的問題以及今后的規劃。 #1. 背景 資料,對于任何一家互聯網公司來說都是非常重要的資產,公司的大資料 ......

    uj5u.com 2020-09-10 06:11:05 more
  • 滴滴AI Labs斬獲國際機器翻譯大賽中譯英方向世界第三

    **桔妹導讀:**深耕人工智能領域,致力于探索AI讓出行更美好的滴滴AI Labs再次斬獲國際大獎,這次獲獎的專案是什么呢?一起來看看詳細報道吧! 近日,由國際計算語言學協會ACL(The Association for Computational Linguistics)舉辦的世界最具影響力的機器 ......

    uj5u.com 2020-09-10 06:11:29 more
  • MPP (Massively Parallel Processing)大規模并行處理

    1、什么是mpp? MPP (Massively Parallel Processing),即大規模并行處理,在資料庫非共享集群中,每個節點都有獨立的磁盤存盤系統和記憶體系統,業務資料根據資料庫模型和應用特點劃分到各個節點上,每臺資料節點通過專用網路或者商業通用網路互相連接,彼此協同計算,作為整體提供 ......

    uj5u.com 2020-09-10 06:11:41 more
  • 滴滴資料倉庫指標體系建設實踐

    **桔妹導讀:**指標體系是什么?如何使用OSM模型和AARRR模型搭建指標體系?如何統一流程、規范化、工具化管理指標體系?本文會對建設的方法論結合滴滴資料指標體系建設實踐進行解答分析。 #1. 什么是指標體系 ##1.1 指標體系定義 指標體系是將零散單點的具有相互聯系的指標,系統化的組織起來,通 ......

    uj5u.com 2020-09-10 06:12:52 more
  • 單表千萬行資料庫 LIKE 搜索優化手記

    我們經常在資料庫中使用 LIKE 運算子來完成對資料的模糊搜索,LIKE 運算子用于在 WHERE 子句中搜索列中的指定模式。 如果需要查找客戶表中所有姓氏是“張”的資料,可以使用下面的 SQL 陳述句: SELECT * FROM Customer WHERE Name LIKE '張%' 如果需要 ......

    uj5u.com 2020-09-10 06:13:25 more
  • 滴滴Ceph分布式存盤系統優化之鎖優化

    **桔妹導讀:**Ceph是國際知名的開源分布式存盤系統,在工業界和學術界都有著重要的影響。Ceph的架構和演算法設計發表在國際系統領域頂級會議OSDI、SOSP、SC等上。Ceph社區得到Red Hat、SUSE、Intel等大公司的大力支持。Ceph是國際云計算領域應用最廣泛的開源分布式存盤系統, ......

    uj5u.com 2020-09-10 06:14:51 more
  • es~通過ElasticsearchTemplate進行聚合~嵌套聚合

    之前寫過《es~通過ElasticsearchTemplate進行聚合操作》的文章,這一次主要寫一個嵌套的聚合,例如先對sex集合,再對desc聚合,最后再對age求和,共三層嵌套。 Aggregations的部分特性類似于SQL語言中的group by,avg,sum等函式,Aggregation ......

    uj5u.com 2020-09-10 06:14:59 more
  • 爬蟲日志監控 -- Elastc Stack(ELK)部署

    傻瓜式部署,只需替換IP與用戶 導讀: 現ELK四大組件分別為:Elasticsearch(核心)、logstash(處理)、filebeat(采集)、kibana(可視化) 下載均在https://www.elastic.co/cn/downloads/下tar包,各組件版本最好一致,配合fdm會 ......

    uj5u.com 2020-09-10 06:15:05 more
最新发布
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:33:24 more
  • MySQL中binlog備份腳本分享

    關于MySQL的二進制日志(binlog),我們都知道二進制日志(binlog)非常重要,尤其當你需要point to point災難恢復的時侯,所以我們要對其進行備份。關于二進制日志(binlog)的備份,可以基于flush logs方式先切換binlog,然后拷貝&壓縮到到遠程服務器或本地服務器 ......

    uj5u.com 2023-04-20 08:28:06 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:27:27 more
  • 快取與資料庫雙寫一致性幾種策略分析

    本文將對幾種快取與資料庫保證資料一致性的使用方式進行分析。為保證高并發性能,以下分析場景不考慮執行的原子性及加鎖等強一致性要求的場景,僅追求最終一致性。 ......

    uj5u.com 2023-04-20 08:26:48 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:26:35 more
  • 云時代,MySQL到ClickHouse資料同步產品對比推薦

    ClickHouse 在執行分析查詢時的速度優勢很好的彌補了MySQL的不足,但是對于很多開發者和DBA來說,如何將MySQL穩定、高效、簡單的同步到 ClickHouse 卻很困難。本文對比了 NineData、MaterializeMySQL(ClickHouse自帶)、Bifrost 三款產品... ......

    uj5u.com 2023-04-20 08:26:29 more
  • sql陳述句優化

    問題查找及措施 問題查找 需要找到具體的代碼,對其進行一對一優化,而非一直把關注點放在服務器和sql平臺 降低簡化每個事務中處理的問題,盡量不要讓一個事務拖太長的時間 例如檔案上傳時,應將檔案上傳這一步放在事務外面 微軟建議 4.啟動sql定時執行計劃 怎么啟動sqlserver代理服務-百度經驗 ......

    uj5u.com 2023-04-20 08:25:13 more
  • Redis 報”OutOfDirectMemoryError“(堆外記憶體溢位)

    Redis 報錯“OutOfDirectMemoryError(堆外記憶體溢位) ”問題如下: 一、報錯資訊: 使用 Redis 的業務介面 ,產生 OutOfDirectMemoryError(堆外記憶體溢位),如圖: 格式化后的報錯資訊: { "timestamp": "2023-04-17 22: ......

    uj5u.com 2023-04-20 08:24:54 more
  • day02-2-商鋪查詢快取

    功能02-商鋪查詢快取 3.商鋪詳情快取查詢 3.1什么是快取? 快取就是資料交換的緩沖區(稱作Cache),是存盤資料的臨時地方,一般讀寫性能較高。 快取的作用: 降低后端負載 提高讀寫效率,降低回應時間 快取的成本: 資料一致性成本 代碼維護成本 運維成本 3.2需求說明 如下,當我們點擊商店詳 ......

    uj5u.com 2023-04-20 08:24:03 more
  • day02-短信登錄

    功能實作02 2.功能01-短信登錄 2.1基于Session實作登錄 2.1.1思路分析 2.1.2代碼實作 2.1.2.1發送短信驗證碼 發送短信驗證碼: 發送驗證碼的介面為:http://127.0.0.1:8080/api/user/code?phone=xxxxx<手機號> 請求方式:PO ......

    uj5u.com 2023-04-20 08:23:11 more