mybatis從使用到了解(五)_mybatis類型映射(TypeHandler)

mybatis的TypeHandler類型轉(zhuǎn)換

java有java的數(shù)據(jù)類型鞋诗,數(shù)據(jù)哭有數(shù)據(jù)庫的類型峭跳,當我們把java數(shù)據(jù)插入數(shù)據(jù)庫的時候,需要講java數(shù)據(jù)類型轉(zhuǎn)化為數(shù)據(jù)庫數(shù)據(jù)類型稀颁;當我們從數(shù)據(jù)庫讀取數(shù)據(jù)的時候吹菱,需要把數(shù)據(jù)庫類型轉(zhuǎn)化為java類型來處理。這中間的轉(zhuǎn)化吱韭,mybatis中是通過TypeHandler類型處理器來處理的吆豹。

我們先通過一個例子來了解TypeHandler的實現(xiàn)機制

在這個例子中講java字符數(shù)組String[]轉(zhuǎn)化成數(shù)據(jù)庫varchar類型。如:String[] interests = {"movie", "music"}轉(zhuǎn)為”movie,music"理盆,同時也能實現(xiàn)從varchar轉(zhuǎn)化為String[] 數(shù)組痘煤。

  • 自定義類型轉(zhuǎn)化器
@MappedTypes({String[].class})
@MappedJdbcTypes({JdbcType.VARCHAR})
public class StringArrayTypeHandler extends BaseTypeHandler<String[]>{
    /**
     * 把Java類型參數(shù)轉(zhuǎn)換為對應的數(shù)據(jù)庫類型
     * @param ps 當前的PreparedStatement對象
     * @param i 當前參數(shù)位置
     * @param parameter 當前參數(shù)的Java對象
     * @param jdbcType 當前參數(shù)的數(shù)據(jù)庫類型
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, String[] parameter, JdbcType jdbcType) throws SQLException {
        // 由于BaseTypeHandler中已經(jīng)把parameter為null的情況做了處理,所以這里我們就不用在判斷parameter是否為空猿规,直接用就可以了
        StringBuffer result = new StringBuffer();
        for (String value : parameter) {
            result.append(value).append(",");
        }
        result.deleteCharAt(result.length() - 1);
        ps.setString(i, result.toString());
    }

    /**
     * 獲取數(shù)據(jù)結果集時把數(shù)據(jù)庫類型轉(zhuǎn)換為對應的Java類型
     * @param rs 當前的結果集
     * @param columnName 當前的字段名稱
     * @return  轉(zhuǎn)換后的Java對象
     * @throws SQLException
     */
    @Override
    public String[] getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return this.getStringArray(rs.getString(columnName));
    }

    /**
     * 通過字段位置獲取字段數(shù)據(jù)時把數(shù)據(jù)庫類型轉(zhuǎn)換為對應的Java類型
     * @param rs 當前的結果集
     * @param columnIndex 當前字段的位置
     * @return 轉(zhuǎn)換后的Java對象
     * @throws SQLException
     */
    @Override
    public String[] getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return this.getStringArray(rs.getString(columnIndex));
    }

    /**
     * 調(diào)用存儲過程后把數(shù)據(jù)庫類型的數(shù)據(jù)轉(zhuǎn)換為對應的Java類型
     * @param cs  當前的CallableStatement執(zhí)行后的CallableStatement
     * @param columnIndex  當前輸出參數(shù)的位置
     * @return
     * @throws SQLException
     */
    @Override
    public String[] getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return this.getStringArray(cs.getString(columnIndex));
    }

    /**
     * 講”movie,music"轉(zhuǎn)化為數(shù)組對象
     * @param columnValue
     * @return
     */
    private String[] getStringArray(String columnValue) {
        if (columnValue == null)
            return null;
        return columnValue.split(",");
    }
}
  • 配置文件里配置自定義的TypeHandler
<typeHandlers>
    <!--<typeHandler handler="com.yongssu.mybatis.demo1.StringArrayTypeHandler" javaType="[Ljava.lang.String;" jdbcType="VARCHAR"/>-->
    <typeHandler handler="com.yongssu.mybatis.demo1.StringArrayTypeHandler"/>
</typeHandlers>

如果在自定義類型轉(zhuǎn)化器時通過注解標注了對應的javaType以及jdbcType衷快,則在配置文件中不需要再次聲明;如果沒有姨俩,則需要在配置文件中說明avaType和jdbcType蘸拔。

  • 聲明包含String[]數(shù)組的學生類
public class Student {
    private int student_id;
    private String student_name;
    private int student_age;
    private String student_phone;
    private String[] interests;
    public Student() {
        super();
    }
    public int getStudent_id() {
        return student_id;
    }
    public void setStudent_id(int student_id) {
        this.student_id = student_id;
    }
    public String getStudent_name() {
        return student_name;
    }
    public void setStudent_name(String student_name) {
        this.student_name = student_name;
    }
    public int getStudent_age() {
        return student_age;
    }
    public void setStudent_age(int student_age) {
        this.student_age = student_age;
    }
    public String getStudent_phone() {
        return student_phone;
    }
    public void setStudent_phone(String student_phone) {
        this.student_phone = student_phone;
    }
    public String[] getInterests() {
        return interests;
    }
    public void setInterests(String[] interests) {
        this.interests = interests;
    }
    @Override
    public String toString() {
        return "Student{" +
                "student_id=" + student_id +
                ", student_name='" + student_name + '\'' +
                ", student_age=" + student_age +
                ", student_phone='" + student_phone + '\'' +
                ", interests=" + Arrays.toString(interests) +
                '}';
    }
}
  • 在stutent.xml中增加sql語句
<resultMap id="studentResult" type="Student">
    <id column="student_id" property="student_id"/>
    <result column="student_name" property="student_name"/>
    <result column="student_age" property="student_age"/>
    <result column="student_phone" property="student_phone"/>
    <result column="interests" property="interests"/>
</resultMap>

<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true" keyColumn="id">
    insert into student (student_name,student_age,student_phone,interests) values
    (#{student_name},#{student_age},#{student_phone},#{interests,javaType=[Ljava.lang.String;,jdbcType=VARCHAR})
</insert>

<select id="findById" parameterType="int" resultMap="studentResult">
    select * from student where student_id = #{id}
</select>
  • 測試類
/**
 * 方式4
 * @throws IOException
 */
public static void test04() throws IOException {
    // 讀取配置文件
    Reader reader = Resources.getResourceAsReader("config.xml");
    // 創(chuàng)建SqlSeessionFactory工廠
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    Student student = new Student();
    String[] interests = {"movie", "music"};
    student.setInterests(interests);
    student.setStudent_age(12);
    student.setStudent_name("yongsheng.su");
    student.setStudent_phone("123456");
    // 執(zhí)行sql
    SqlSession session = sqlSessionFactory.openSession();
    try {
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        int result = mapper.insertStudent(student);
        System.out.println(result);
        session.commit();
    } finally {
        session.close();
    }
}

public static void test05() throws IOException {
    // 讀取配置文件
    Reader reader = Resources.getResourceAsReader("config.xml");
    // 創(chuàng)建SqlSeessionFactory工廠
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);

    Student student = null;
    // 執(zhí)行sql
    SqlSession session = sqlSessionFactory.openSession();
    try {
        StudentMapper mapper = session.getMapper(StudentMapper.class);
        student = mapper.selectStudent(7);
        System.out.println(student);
        session.commit();
    } finally {
        session.close();
    }
    System.out.println(student);
}

mybatis類型映射實現(xiàn)說明

通過上面的例子师郑,可以發(fā)現(xiàn)要實現(xiàn)自定義TypeHandler,只需要繼承BaseTypeHandler调窍,然后實現(xiàn)相應的轉(zhuǎn)換規(guī)則就可以宝冕。其實除了繼承BaseTypeHadler以外,還可以自己實現(xiàn)TypeHandler邓萨。通過下面代碼地梨,可以發(fā)現(xiàn),BaseHandler也是繼承自TypeHandler先誉,并提供了一些默認的實現(xiàn)湿刽,對null值做了一些處理,這樣我們繼承BaseTypeHandler時就不需要對null值做處理了褐耳。

  • TypeHandler接口
public interface TypeHandler<T> {
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  T getResult(ResultSet rs, String columnName) throws SQLException;
  T getResult(ResultSet rs, int columnIndex) throws SQLException;
  T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
  • BaseTypeHandler類實現(xiàn)
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {
  protected Configuration configuration;
  public void setConfiguration(Configuration c) {
    this.configuration = c;
  }
  @Override
  public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
    if (parameter == null) {
      if (jdbcType == null) {
        throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
      }
      try {
        ps.setNull(i, jdbcType.TYPE_CODE);
      } catch (SQLException e) {
        throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
                "Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
                "Cause: " + e, e);
      }
    } else {
      try {
        setNonNullParameter(ps, i, parameter, jdbcType);
      } catch (Exception e) {
        throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
                "Try setting a different JdbcType for this parameter or a different configuration property. " +
                "Cause: " + e, e);
      }
    }
  }
  @Override
  public T getResult(ResultSet rs, String columnName) throws SQLException {
    T result;
    try {
      result = getNullableResult(rs, columnName);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set.  Cause: " + e, e);
    }
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }
  @Override
  public T getResult(ResultSet rs, int columnIndex) throws SQLException {
    T result;
    try {
      result = getNullableResult(rs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from result set.  Cause: " + e, e);
    }
    if (rs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }
  @Override
  public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
    T result;
    try {
      result = getNullableResult(cs, columnIndex);
    } catch (Exception e) {
      throw new ResultMapException("Error attempting to get column #" + columnIndex+ " from callable statement.  Cause: " + e, e);
    }
    if (cs.wasNull()) {
      return null;
    } else {
      return result;
    }
  }

  public abstract void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
  public abstract T getNullableResult(ResultSet rs, String columnName) throws SQLException;
  public abstract T getNullableResult(ResultSet rs, int columnIndex) throws SQLException;
  public abstract T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException;
}

mybatis提供的默認類型

對于一些常用的java類型,mybatis已經(jīng)提供了相應的TypeHandler,并且會自動注冊他們渴庆。mybatis提供了以下集中類型轉(zhuǎn)換器铃芦。

register(Boolean.class, new BooleanTypeHandler());
register(boolean.class, new BooleanTypeHandler());
register(JdbcType.BOOLEAN, new BooleanTypeHandler());
register(JdbcType.BIT, new BooleanTypeHandler());
register(Byte.class, new ByteTypeHandler());
register(byte.class, new ByteTypeHandler());
register(JdbcType.TINYINT, new ByteTypeHandler());
register(Short.class, new ShortTypeHandler());
register(short.class, new ShortTypeHandler());
register(JdbcType.SMALLINT, new ShortTypeHandler());
register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());
register(Long.class, new LongTypeHandler());
register(long.class, new LongTypeHandler());
register(Float.class, new FloatTypeHandler());
register(float.class, new FloatTypeHandler());
register(JdbcType.FLOAT, new FloatTypeHandler());
register(Double.class, new DoubleTypeHandler());
register(double.class, new DoubleTypeHandler());
register(JdbcType.DOUBLE, new DoubleTypeHandler());
register(Reader.class, new ClobReaderTypeHandler());
register(String.class, new StringTypeHandler());
register(String.class, JdbcType.CHAR, new StringTypeHandler());
register(String.class, JdbcType.CLOB, new ClobTypeHandler());
register(String.class, JdbcType.VARCHAR, new StringTypeHandler());
register(String.class, JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(String.class, JdbcType.NVARCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCHAR, new NStringTypeHandler());
register(String.class, JdbcType.NCLOB, new NClobTypeHandler());
register(JdbcType.CHAR, new StringTypeHandler());
register(JdbcType.VARCHAR, new StringTypeHandler());
register(JdbcType.CLOB, new ClobTypeHandler());
register(JdbcType.LONGVARCHAR, new ClobTypeHandler());
register(JdbcType.NVARCHAR, new NStringTypeHandler());
register(JdbcType.NCHAR, new NStringTypeHandler());
register(JdbcType.NCLOB, new NClobTypeHandler());
register(Object.class, JdbcType.ARRAY, new ArrayTypeHandler());
register(JdbcType.ARRAY, new ArrayTypeHandler());
register(BigInteger.class, new BigIntegerTypeHandler());
register(JdbcType.BIGINT, new LongTypeHandler());
register(BigDecimal.class, new BigDecimalTypeHandler());
register(JdbcType.REAL, new BigDecimalTypeHandler());
register(JdbcType.DECIMAL, new BigDecimalTypeHandler());
register(JdbcType.NUMERIC, new BigDecimalTypeHandler());
register(InputStream.class, new BlobInputStreamTypeHandler());
register(Byte[].class, new ByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.BLOB, new BlobByteObjectArrayTypeHandler());
register(Byte[].class, JdbcType.LONGVARBINARY, new BlobByteObjectArrayTypeHandler());
register(byte[].class, new ByteArrayTypeHandler());
register(byte[].class, JdbcType.BLOB, new BlobTypeHandler());
register(byte[].class, JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.LONGVARBINARY, new BlobTypeHandler());
register(JdbcType.BLOB, new BlobTypeHandler());
register(Object.class, UNKNOWN_TYPE_HANDLER);
register(Object.class, JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(JdbcType.OTHER, UNKNOWN_TYPE_HANDLER);
register(Date.class, new DateTypeHandler());
register(Date.class, JdbcType.DATE, new DateOnlyTypeHandler());
register(Date.class, JdbcType.TIME, new TimeOnlyTypeHandler());
register(JdbcType.TIMESTAMP, new DateTypeHandler());
register(JdbcType.DATE, new DateOnlyTypeHandler());
register(JdbcType.TIME, new TimeOnlyTypeHandler());
register(java.sql.Date.class, new SqlDateTypeHandler());
register(java.sql.Time.class, new SqlTimeTypeHandler());
register(java.sql.Timestamp.class, new SqlTimestampTypeHandler());

參考文章:http://4443915.blog.51cto.com/4433915/1828533

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市襟雷,隨后出現(xiàn)的幾起案子刃滓,更是在濱河造成了極大的恐慌,老刑警劉巖耸弄,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咧虎,死亡現(xiàn)場離奇詭異,居然都是意外死亡计呈,警方通過查閱死者的電腦和手機砰诵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捌显,“玉大人茁彭,你說我怎么就攤上這事》鐾幔” “怎么了理肺?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長善镰。 經(jīng)常有香客問我妹萨,道長,這世上最難降的妖魔是什么炫欺? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任乎完,我火速辦了婚禮,結果婚禮上竣稽,老公的妹妹穿的比我還像新娘囱怕。我一直安慰自己霍弹,他們只是感情好,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布娃弓。 她就那樣靜靜地躺著典格,像睡著了一般。 火紅的嫁衣襯著肌膚如雪台丛。 梳的紋絲不亂的頭發(fā)上耍缴,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機與錄音挽霉,去河邊找鬼防嗡。 笑死,一個胖子當著我的面吹牛侠坎,可吹牛的內(nèi)容都是我干的蚁趁。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼实胸,長吁一口氣:“原來是場噩夢啊……” “哼他嫡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起庐完,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤钢属,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后门躯,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淆党,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年讶凉,在試婚紗的時候發(fā)現(xiàn)自己被綠了染乌。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡缀遍,死狀恐怖慕匠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情域醇,我是刑警寧澤台谊,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站譬挚,受9級特大地震影響锅铅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜减宣,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一盐须、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧漆腌,春花似錦贼邓、人聲如沸阶冈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽女坑。三九已至,卻和暖如春统舀,著一層夾襖步出監(jiān)牢的瞬間匆骗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工誉简, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留碉就,地道東北人。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓闷串,卻偏偏與公主長得像瓮钥,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子窿克,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容

  • 1. 簡介 1.1 什么是 MyBatis 骏庸? MyBatis 是支持定制化 SQL、存儲過程以及高級映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,462評論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理年叮,服務發(fā)現(xiàn),斷路器玻募,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,849評論 25 707
  • 你 是一叢蹙眉的花衣 白日黑夜里 冷冷的嬌艷 俯瞰或仰望 這如流浪者般的孤獨 又如廢墟般的靜寂 是為誰而佇立 你 ...
    三姑娘的開放衣櫥閱讀 236評論 0 1
  • 昨天我們好多同學一起給程程過生日只损,祝程程生日快樂!學習進步七咧!
    晨起1閱讀 94評論 0 0