1. 程式人生 > 其它 >Power Apps 中修改 SharePoint Online 資料

Power Apps 中修改 SharePoint Online 資料

1、#{}和${}的區別是什麼?

注:面試官真題。

⭐參考閱讀一篇寫得非常好的文章:#{}與${}的區別

#{}是預編譯處理,${}是字串替換。

  • #{}
    • mybatis在處理#{}時,會將sql中的#{}替換為?號,呼叫PreparedStatementsetString(int parameterIndex, String x)方法來賦值,這個方法會將使用者輸入的單引號'加上轉義字元\,以起到阻止惡意sql注入的問題;
    • 同時對#{}會有預編譯的機制。
      • 預編譯是提前對SQL語句進行預編譯,而其後注入的引數將不會再進行SQL編譯。我們知道,SQL注入是發生在編譯的過程中,因為惡意注入了某些特殊字元,最後被編譯成了惡意的執行操作。而預編譯機制則可以很好的防止SQL注入。
      • 也就是說,編譯之後SQL語句的結構不會再發生變化,#{}指代的位置也僅僅作為字串填入,因此惡意SQL字串不會再改變SQL語句的結構。

⭐關於PreparedStatement推薦閱讀:java中PreparedStatement和Statement詳細講解
其中講到一個例子:
sql語句:**SELECT * FROM admin WHERE username = '韋小寶' AND password = ?**
如此呼叫**PreparedStatement.setString**方法時:
**parepaerStatement.setString(2, "222' OR '8'='8'"**


也就是想將第二個引數password變為**222' OR '8'='8'**,想使得整句是
**SELECT * FROM admin WHERE username = '韋小寶' AND password = 222' OR '8'='8'**,注入**'8'='8'**這個恆為真的條件判斷,起到繞過密碼認證的過程。這就是sql注入。
**PreparedStatement.setString**會起到作用,使得實際上的sql語句變成:
**SELECT * FROM admin WHERE username = '韋小寶' AND password = '222\' OR \'8\'=\'8'**
,將'給轉義成了普通字元,而沒有了斷開字元的功能,從而阻止了sql注入。

  • ${}
    • mybatis在處理 ${}時,就是把 ${}替換成變數的值。
    • 也就是說,惡意SQL語句還是可以改變原本SQL語句的結構,無法阻止SQL注入。

使用 #{} 可以有效的防止SQL注入,提高系統安全性。

2、XML對映檔案中,除了常見的 select|insert|update|delete 標籤之外,還有哪些標籤?

注:京東面試。
答:還有很多其他的標籤,

  • <resultMap>:
    resultMap是Mybatis最強大的元素,它可以將查詢到的複雜資料(比如查詢到幾個表中資料)對映到一個結果集當中。
<resultMap id="唯一的標識" type="對映的pojo物件">
  <id column="表的主鍵欄位,或者可以為查詢語句中的別名欄位" jdbcType="欄位型別" property="對映pojo物件的主鍵屬性" />
  <result column="表的一個欄位(可以為任意表的一個欄位)" jdbcType="欄位型別" property="對映到pojo物件的一個屬性(須為type定義的pojo物件中的一個屬性)"/>
  <result column=... .../>
  <result column=... .../>
  ...
  <!--POJO的物件屬性-->
  <association property="pojo的一個物件屬性" javaType="pojo關聯的pojo物件">
    <id column="關聯pojo物件對應表的主鍵欄位" jdbcType="欄位型別" property="關聯pojo物件的主席屬性"/>
    <result  column="任意表的欄位" jdbcType="欄位型別" property="關聯pojo物件的屬性"/>
  </association>
  <association property=.../>
  <association property=.../>
  ...
  <!-- 集合中的property須為oftype定義的pojo物件的屬性-->
  <collection property="pojo的集合屬性" ofType="集合中的pojo物件">
    <id column="集合中pojo物件對應的表的主鍵欄位" jdbcType="欄位型別" property="集合中pojo物件的主鍵屬性" />
    <result column="可以為任意表的欄位" jdbcType="欄位型別" property="集合中的pojo物件的屬性" />  
  </collection>
  <collection .../>
  <collection .../>
  ...
</resultMap>

⭐參考:Mybatis:resultMap的使用總結

  • ~~<parameterMap>~~(已棄用, 改用內聯引數對映和 parameterType 屬性)
  • <sql>
    • 使用sql標籤減少重複的sql語句,不僅可以減少我們的程式碼量,還更加方便我們檢視!

⭐參考:

  • <include>
  • <selectKey>
    • <selectKey>在Mybatis中是為了解決Insert資料時不支援主鍵自動生成的問題, 將<selectKey>放在<insert>之後,通過LAST_INSERT_ID() 獲得剛插入的自動增長的id的值。
    • Mybatis 示例之 SelectKey
  • 加上動態 的 9 個標籤,trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中 <sql> 為 sql 片段標籤,通過 <include> 標籤引入 sql 片段, <selectKey>不支援自增的主鍵生成策略標籤

3、最佳實踐中,通常一個 Xml 對映檔案,都會寫一個 Dao 介面與之對應,請問,這個 Dao 介面的工作原理是什麼?Dao 接口裡的方法,引數不同時,方法能過載嗎?

注:京東面試。
答:Dao 介面,就是人們常說的 Mapper 介面

  • 介面的全限名,就是對映檔案中的 namespace 的值
<mapper namespace="com.project.module.dao.PojoDao">
  ...
  • 介面的方法名,就是對映檔案中 MappedStatement 的 id 值
<select id="getXXXX" resultType="java.util.Map">
  ...
</select>
  • 介面方法內的引數,就是傳遞給 sql 的引數。 Mapper 介面是沒有實現類的,當呼叫介面方法時,介面全限名+方法名拼接字串作為 key 值,可唯一定位一個 MappedStatement ,舉例: com.mybatis3.mappers.StudentDao.findStudentById ,可以唯一找到 namespacecom.mybatis3.mappers.StudentDao 下面 id = findStudentByIdMappedStatement
  • 在 MyBatis 中,每一個 <select><insert><update><delete> 標籤,都會被解析為一個 MappedStatement 物件。

Dao 接口裡的方法可以過載,但是 Mybatis 的 XML 裡面的 ID 不允許重複, 但是可以用動態sql的方式實現
比如:
Mapper:

/**
 * Mapper接口裡面方法過載
 */
public interface StuMapper {

	List<Student> getAllStu();

	List<Student> getAllStu(@Param("id") Integer id);
}

xml檔案:

	<select id="getAllStu" resultType="com.pojo.Student">
 		select * from student
		<where>
			<if test="id != null">
				id = #{id}
			</if>
		</where>
 	</select>

能正常執行,並能得到相應的結果,這樣就實現了在 Dao 介面中寫過載方法。
Mybatis 的 Dao 介面可以有多個過載方法,但是多個介面對應的對映必須只有一個,否則啟動會報錯。

Dao 介面方法可以過載,但是需要滿足以下條件:

  1. 僅有一個無參方法和一個有參方法
  2. 多個有參方法時,引數數量必須一致。且使用相同的 @Param ,或者使用 param1這種, 不一致時取最長的引數數量,其他數量不符合的方法報錯。

測試如下:
PersonDao.java

Person queryById();

Person queryById(@Param("id") Long id);

Person queryById(@Param("id") Long id, @Param("name") String name);

PersonMapper.xml

<select id="queryById" resultMap="PersonMap">
    select
      id, name, age, address
    from person
    <where>
        <if test="id != null">
            id = #{id}
        </if>
        <if test="name != null and name != ''">
            name = #{name}
        </if>
    </where>
    limit 1
</select>

  • queryById()方法執行時,無引數,動態 sql 可以正常執行。
  • queryById(1L,"1")方法執行時,引數id和name屬性都可以獲取到,動態 sql 正常執行
  • queryById(1L)方法執行時,只有一個引數,報錯。

4、MyBatis 是如何進行分頁的?分頁外掛的原理是什麼?

答:

  1. MyBatis 使用 RowBounds 物件進行分頁,它是針對 ResultSet 結果集執行的記憶體分頁,而非物理分頁;
    1. mybatis之RowBounds分頁程式碼實現
  2. 可以在 sql 內直接書寫帶有物理分頁的引數來完成物理分頁功能(Limit)
  3. 也可以使用分頁外掛來完成物理分頁。

分頁外掛的基本原理是使用 MyBatis 提供的外掛介面,實現自定義外掛,在外掛的攔截方法內攔截待執行的 sql,然後重寫 sql,根據 dialect 方言,新增對應的物理分頁語句和物理分頁引數。
舉例: select _ from student ,攔截 sql 後重寫為: select t._ from (select \* from student)t limit 0,10

10、MyBatis 是否支援延遲載入?如果支援,它的實現原理是什麼?
答:MyBatis 僅支援 association 關聯物件和 collection 關聯集合物件的延遲載入,association 指的就是一對一collection 指的就是一對多查詢。在 MyBatis 配置檔案中,可以配置是否啟用延遲載入 lazyLoadingEnabled=true|false

⭐推薦閱讀:Mybatis延遲載入的實現以及使用場景

它的原理是,使用 CGLIB 建立目標物件的代理物件,當呼叫目標方法時,進入攔截器方法,
比如呼叫 a.getB().getName() ,攔截器 invoke() 方法發現 a.getB()null 值,那麼就會單獨傳送事先儲存好的查詢關聯 B 物件的 sql,把 B 查詢上來,然後呼叫 a.setB(b),於是 a 的物件 b 屬性就有值了,接著完成 a.getB().getName() 方法的呼叫。這就是延遲載入的基本原理。
當然了,不光是 MyBatis,幾乎所有的包括 Hibernate,支援延遲載入的原理都是一樣的。

參考:MyBatis 常見面試總結