第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

MyBatis 類型處理器

1. 前言

MyBatis 提供了諸多類型處理器,但是相較于豐富的數(shù)據(jù)庫(kù)類型仍然略顯不足,比如 MyBatis 只能將 JSON 數(shù)據(jù)類型當(dāng)成普通的字符串處理。因此 MyBatis 提供了類型處理器接口,讓開發(fā)者可以根據(jù)具體的業(yè)務(wù)需求來(lái)自定義適合的類型處理器。

本小節(jié),我們將以 JSON 類型處理器作為落腳點(diǎn),來(lái)介紹類型處理器,并自定義 JSON 類型處理器。

2. JSON 數(shù)據(jù)類型

首先,我們需要為 MyBatis 內(nèi)置類型處理器增加一個(gè)它無(wú)法處理的數(shù)據(jù)類型,這里我們選擇 MySQL5.7 中新增的 JSON 數(shù)據(jù)類型,這也是大家普遍使用的一個(gè)數(shù)據(jù)類型。在可用的數(shù)據(jù)庫(kù)環(huán)境中,我們運(yùn)行如下腳本:

DROP TABLE IF EXISTS blog;
CREATE TABLE blog
(
  id   int(11) unsigned primary key auto_increment,
  info json,
  tags json
);
INSERT INTO blog(info, tags)
VALUES ('{"title": "世界更大", "content": "世界更大的內(nèi)容", "rank": 1}', '["世界觀"]'),
       ('{"title": "人生更短", "content": "人生更短的內(nèi)容", "rank": 2}', '["人文"]');

在這個(gè)腳本中,我們新建了一個(gè) blog 數(shù)據(jù)表,blog 數(shù)據(jù)表除 id 外有 info 和 tags 兩個(gè)字段,這兩個(gè)字段都是 JSON 類型,并通過(guò) insert 語(yǔ)句添加了兩條記錄。

3. 類型處理器

MyBatis 默認(rèn)是無(wú)法很好處理 info 和 tags 這兩個(gè)字段的,只能將它們當(dāng)成字符串類型來(lái)處理,但顯然這不是我們想要的效果。我們希望新增 json 類型處理器來(lái)處理好這兩個(gè)字段。

MyBatis 提供了 TypeHandler 接口,自定義類型處理器需要實(shí)現(xiàn)了這個(gè)接口才能工作。考慮到很多開發(fā)者不夠熟練,MyBatis 還提供了一個(gè) BaseTypeHandler 抽象類來(lái)幫助我們做自定義類型處理器,只需繼承這個(gè)基類,然后實(shí)現(xiàn)它的方法即可。

3.1 JsonObject 處理器

JSON 可分為 object 和 array 兩大類,分別對(duì)應(yīng) info 和 tags 字段,這兩類需要分別實(shí)現(xiàn)類型處理器。由于需要對(duì) JSON 進(jìn)行處理,我們?cè)?pom.xml 文件中添加上對(duì)應(yīng)的依賴。

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.60</version>
</dependency>

這里,我們使用阿里巴巴開源的 fastjson庫(kù)。

在 com.imooc.mybatis 包下新建 handler 包,并向 handler 包中添加上 json object 的類型處理器 JsonObjectTypeHandler。如下:

package com.imooc.mybatis.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.ibatis.type.*;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@MappedJdbcTypes(JdbcType.VARCHAR) // 對(duì)應(yīng)jdbc 類型
@MappedTypes({JSONObject.class}) // 對(duì)應(yīng)處理后類型
public class JsonObjectTypeHandler extends BaseTypeHandler<JSONObject> {
  // 當(dāng)為 PreparedStatement 參數(shù)時(shí),如何處理對(duì)象
  @Override
  public void setNonNullParameter(PreparedStatement preparedStatement, int i, JSONObject o, JdbcType jdbcType) throws SQLException {
    preparedStatement.setString(i, JSON.toJSONString(o));
  }

  // 當(dāng)通過(guò)名稱從結(jié)果中取json字段時(shí)如何處理
  @Override
  public JSONObject getNullableResult(ResultSet resultSet, String s) throws SQLException {
    String t = resultSet.getString(s);
    return JSON.parseObject(t);
  }

  // 當(dāng)通過(guò)序列號(hào)從結(jié)果中取json字段時(shí)如何處理
  @Override
  public JSONObject getNullableResult(ResultSet resultSet, int i) throws SQLException {
    String t = resultSet.getString(i);
    return JSON.parseObject(t);
  }

  // 當(dāng)通過(guò)序列號(hào)從 CallableStatement 中取json字段時(shí)如何處理
  @Override
  public JSONObject getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
    String t = callableStatement.getString(i);
    return JSON.parseObject(t);
  }
}

有了 BaseTypeHandler 作為基礎(chǔ)后,實(shí)現(xiàn)一個(gè)類型處理器就比較簡(jiǎn)單了,我們只需要為其中 4 個(gè)方法添加上對(duì)應(yīng)的實(shí)現(xiàn)即可。

類型處理器有兩個(gè)作用,第一處理 Java 對(duì)象到 JdbcType 類型的轉(zhuǎn)換,對(duì)應(yīng) setNonNullParameter 方法;第二處理 JdbcType 類型到 Java 類型的轉(zhuǎn)換,對(duì)應(yīng) getNullableResult 方法,getNullableResult 有 3 個(gè)重載方法。下面我們依次來(lái)說(shuō)明這四個(gè)方法的作用:

  • setNonNullParameter:處理 PreparedStatement 中的 JSONObject 參數(shù),當(dāng)調(diào)用 PreparedStatement 執(zhí)行 SQL 語(yǔ)句時(shí),調(diào)用該處理 JSONObject 類型的參數(shù),這里我們通過(guò) fastjson 的JSON.toJSONString(o)函數(shù)將 JSONObject 轉(zhuǎn)化為字符串類型即可。
  • getNullableResult:從結(jié)果集中獲取字段,這里 CallableStatement 和 ResultSet 分別對(duì)應(yīng)不同的執(zhí)行方式,對(duì)于 JDBC 而言 JSON 類型也會(huì)當(dāng)做字符串來(lái)處理,因此這里我們需要將字符串類型轉(zhuǎn)化為 JSONObject 類型,對(duì)應(yīng) JSON.parseObject(t)代碼。

3.2 JsonArray 處理器

與 JsonObjectTypeHandler 一樣,在 handler 包下新建 JsonArrayTypeHandler 類,繼承 BaseTypeHandler 類,并將具體方法的實(shí)現(xiàn)從 JSON.parseObject 改變?yōu)?JSON.parseArray,如下:

@MappedJdbcTypes(JdbcType.VARCHAR)
@MappedTypes({JSONArray.class})
public class JsonArrayTypeHandler extends BaseTypeHandler<JSONArray> {
  @Override
  public void setNonNullParameter(PreparedStatement preparedStatement, int i, JSONArray o, JdbcType jdbcType) throws SQLException {
    preparedStatement.setString(i, JSON.toJSONString(o));
  }

  @Override
  public JSONArray getNullableResult(ResultSet resultSet, String s) throws SQLException {
    String t = resultSet.getString(s);
    // // 變成了 parseArray
    return JSON.parseArray(t);
  }

  @Override
  public JSONArray getNullableResult(ResultSet resultSet, int i) throws SQLException {
    String t = resultSet.getString(i);
    // // 變成了 parseArray
    return JSON.parseArray(t);
  }

  @Override
  public JSONArray getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
    String t = callableStatement.getString(i);
    // 變成了 parseArray
    return JSON.parseArray(t);
  }
}

4. 注冊(cè)類型處理器

自定義類型處理器無(wú)法直接被 MyBatis 加載,我們需要增加相關(guān)的配置告訴 MyBatis 加載類型處理器。

4.1 全局注冊(cè)

在全局配置配置文件中可通過(guò) typeHandlers 屬性來(lái)注冊(cè)類型處理器。如下:

<typeHandlers>
  <package name="com.imooc.mybatis.handler"/>
</typeHandlers>

通過(guò) package 項(xiàng)來(lái)指定類型處理器所在的包路徑,這樣 handler 包中的所有類型處理器都會(huì)注冊(cè)到全局。

當(dāng)然如果你的類型處理器分散在其它地方,也可以通過(guò)如下方式來(lái)注冊(cè)。

<typeHandlers>
  <typeHandler handler="com.imooc.mybatis.handler.JsonArrayTypeHandler"/>
</typeHandlers>

全局注冊(cè)的類型處理器會(huì)自動(dòng)被 MyBatis 用來(lái)處理所有符合類型的參數(shù)。如 JsonArrayTypeHandler 通過(guò) MappedJdbcTypes 注解表明了自己將會(huì)處理 JdbcType.VARCHAR 類型,MyBatis 會(huì)自動(dòng)將字符串類型的參數(shù)交給 JsonArrayTypeHandler 來(lái)進(jìn)行處理。

但是,這樣顯然有問(wèn)題,因?yàn)?JsonObjectTypeHandler 注冊(cè)的類型也是 JdbcType.VARCHAR 類型,所以全局注冊(cè)是不推薦的,除非你需要對(duì)所有參數(shù)都做類型轉(zhuǎn)換。

4.2 局部注冊(cè)

由于全局注冊(cè)會(huì)對(duì)其它類型產(chǎn)生歧義和污染,因此我們選擇更加精準(zhǔn)的局部注冊(cè)。在 BlogMapper 中,我們來(lái)注冊(cè)和使用類型處理器。

在 BlogMapper.xml 文件中,我們添加上如下配置。

<resultMap id="blogMap" type="com.imooc.mybatis.model.Blog">
  <result column="id" property="id"/>
  <result column="info" property="info" typeHandler="com.imooc.mybatis.handler.JsonObjectTypeHandler"/>
  <result column="tags" property="tags" typeHandler="com.imooc.mybatis.handler.JsonArrayTypeHandler"/>
</resultMap>

<select id="selectById" resultMap="blogMap">
  SELECT * FROM blog WHERE id = #{id}
</select>

我們定義了 名為 blogMap 的 resultMap 和名為 selectById 的查詢。在 result 映射中,我們注冊(cè)了相關(guān)的類型處理器,info 字段對(duì)應(yīng)

JsonObjectTypeHandler 類型處理器,tags 字段對(duì)應(yīng) JsonArrayTypeHandler 類型處理器。

這樣自定義的類型處理器不會(huì)污染到其它數(shù)據(jù),blogMap 的類型 com.imooc.mybatis.model.Blog 定義如下:

package com.imooc.mybatis.model;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class Blog {
  private Long id;
  private JSONObject info;
  private JSONArray tags;
  // 省略了 getter 和 setter 方法
}

4.3 處理 JDBC 類型

在對(duì)應(yīng)的 BlogMapper.java 接口上添加上對(duì)應(yīng)的 selectById 方法:

package com.imooc.mybatis.mapper;

import com.imooc.mybatis.model.Blog;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface BlogMapper {
  Blog selectById(Integer id);
}

我們測(cè)試一下 selectById 方法:

BlogMapper blogMapper = session.getMapper(BlogMapper.class);
Blog blog = blogMapper.selectById(1);
System.out.println(blog.toString());
String title = blog.getInfo().getString("title");
System.out.println(title);
String tag = blog.getTags().getString(0);
System.out.println(tag);

輸出結(jié)果如下:

Blog{id=1, info={"rank":1,"title":"世界更大","content":".......****............"}, tags=["世界觀"]}
世界更大
世界觀

從結(jié)果中可以看出,類型處理器成功的處理了查詢的數(shù)據(jù),info 和 tags 字段都能夠通過(guò) fastjson 的 API 來(lái)獲取里面的內(nèi)容。

4.4 處理 JSON 類型

在查詢可以工作的情況下,那么如何通過(guò) insert 插入 JSON 對(duì)象了。

我們?cè)?BlogMapper 中新增一個(gè) insertBlog 方法,如下:

<insert id="insertBlog">
  INSERT INTO blog(info,tags)
  VALUES(#{info,typeHandler=com.imooc.mybatis.handler.JsonObjectTypeHandler},
  #{tags,typeHandler=com.imooc.mybatis.handler.JsonArrayTypeHandler})
</insert>
public interface BlogMapper {
  int insertBlog(@Param("info") JSONObject info, @Param("tags") JSONArray tags);
}

這樣 MyBatis 就可以處理 JSON 類型的參數(shù)了,我們?cè)俅螠y(cè)試一下:

JSONObject info = new JSONObject().fluentPut("title", "測(cè)試案例").fluentPut("rank", 1);
JSONArray tags = new JSONArray().fluentAdd("測(cè)試");
int rows = blogMapper.insertBlog(info, tags);
System.out.println(rows);

輸出結(jié)果:

1

可以看到類型處理器成為了 Java JSON 類型和 JDBC 類型轉(zhuǎn)換橋梁,在查詢的時(shí)候主動(dòng)將數(shù)據(jù)庫(kù)類型轉(zhuǎn)化為了可用的 JSON 類型,而在插入的時(shí)候?qū)?JSON 類型又轉(zhuǎn)化為了數(shù)據(jù)庫(kù)可識(shí)別的字符串類型。

5. 小結(jié)

  • 自定義類型處理器并不難,MyBatis 已經(jīng)幫我們做好了大多數(shù)工作,我們只需在適當(dāng)?shù)奈恢眠m當(dāng)?shù)呐渲镁涂梢粤恕?/li>
  • 數(shù)據(jù)庫(kù) JSON 類型的用處會(huì)越來(lái)越廣泛,在 MyBatis 官方未內(nèi)置處理器之前,我們也可以通過(guò)本小節(jié)的方式來(lái)提早的使用它。