1. 程式人生 > >MyBatis中自定義typeHandler

MyBatis中自定義typeHandler

 

Mybatis中的TypeHandler是什麼?

  無論是 MyBatis 在預處理語句(PreparedStatement)中設定一個引數時,還是從結果集中取出一個值時,都會用型別處理器將獲取的值以合適的方式轉換成 Java 型別。Mybatis預設為我們實現了許多TypeHandler, 當我們沒有配置指定TypeHandler時,Mybatis會根據引數或者返回結果的不同,預設為我們選擇合適的TypeHandler處理。

typeHandlers

無論是 MyBatis 在預處理語句(PreparedStatement)中設定一個引數時,還是從結果集中取出一個值時, 都會用型別處理器將獲取的值以合適的方式轉換成 Java 型別。下表描述了一些預設的型別處理器。

提示 從 3.4.5 開始,MyBatis 預設支援 JSR-310(日期和時間 API) 。

 

 

使用場景:mybatis在預處理語句(PreparedStatement)中設定一個引數時,或者從結果集(ResultSet)中取出一個值時,都會用到TypeHandler。它的作用就是將java型別(javaType)轉化為jdbc型別(jdbcType),或者將jdbc型別(jdbcType)轉化為java型別(javaType)。

 

 

 

 

需求一:

自定義列舉型別的TypeHandler,我們通過User類中有一個屬性性別(Sex)型別,來實現資料庫存sexcode, 取資料出來是sexname

 

需求二:

User類中有一個屬性叫做interest,這個屬性用來描述使用者的愛好,它的資料型別是一個List集合,那麼我想在把這個List集合存入資料庫的時候能夠自動的變成{XXX,XXX,XXX}這樣一個字串然後存起來,當我從資料庫讀取的時候也是讀取到這樣一個字串,讀取成功之後再自動的將之轉為一個List集合,

系統提供的typeHandler能夠滿足我們日常開發中的大部分需求,如上這兩種特殊的需求就需要我們自己去定義typeHandler了

1、自定義Sex列舉型別(需求一)

public enum SexEnum {
	MALE(1,"男"),
	FMALE(0,"女");
	
	private int sexCode;
	private String sexName;
	
	private SexEnum(int sexCode, String sexName) {
		this.sexCode = sexCode;
		this.sexName = sexName;
	}
	//通過SexCode的值來獲取Sex列舉型別
	public static SexEnum getSexEnumFromCode(int sexCode) {
		if(sexCode == 1) {
			return MALE;
		}else if(sexCode == 0) {
			return FMALE;
		}
		return null;
	}
//get set
}

2、 自定義列舉型別的TypeHandler

      自定義typeHandler我們有兩種方式,一種是實現TypeHandler介面,還有一種就是繼承自BaseTypeHandler類。

    

     @MappedJdbcTypes() 定義的是JdbcType型別,這裡的型別不可自己隨意定義,必須要是列舉類org.apache.ibatis.type.JdbcType所列舉的資料型別。 
     @MappedTypes()  定義的是JavaType的資料型別,描述了哪些Java型別可被攔截。

 
     在我們啟用了我們自定義的這個TypeHandler之後,資料的讀寫都會被這個類所過濾 
     在setNonNullParameter / setParameter方法中,我們重新定義要寫往資料庫的資料。 
     另外三個方法中我們將從資料庫讀出的資料型別進行轉換

    採用註解 或者  sql對映檔案指定 JdbcType 和 JavaType 都可以

 

   1) sex屬性型別用自定義Sex列舉型別的TypeHandler(需求一)

public class MySexTypeHandler implements TypeHandler<SexEnum>{

	@Override
	public void setParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
		ps.setInt(i, parameter.getSexCode());
		
	}

	@Override
	public SexEnum getResult(ResultSet rs, String columnName) throws SQLException {
		int sexCode = rs.getInt(columnName);
		return SexEnum.getSexEnumFromCode(sexCode);
	}

	@Override
	public SexEnum getResult(ResultSet rs, int columnIndex) throws SQLException {
		int sexCode = rs.getInt(columnIndex);
		return SexEnum.getSexEnumFromCode(sexCode);
	}

	@Override
	public SexEnum getResult(CallableStatement cs, int columnIndex) throws SQLException {
		int sexCode = cs.getInt(columnIndex);
		return SexEnum.getSexEnumFromCode(sexCode);
	}

}

2)interest屬性型別用自定義List型別的TypeHandler(需求二) 採用註釋

@MappedTypes(List.class)
@MappedJdbcTypes({JdbcType.VARCHAR})
public class MyListTypeHandler extends BaseTypeHandler<List<String>>{

	@Override
	public void setNonNullParameter(PreparedStatement ps, int i, List<String> parameter, JdbcType jdbcType)
			throws SQLException {
		if(parameter != null) {
			// List集合轉字串
			StringBuffer sbBuffer = new StringBuffer();
			for(String string : parameter) {
				sbBuffer.append(string).append(",");
			}
			ps.setString(i, sbBuffer.toString().substring(0,sbBuffer.toString().length()-1));
		}
	}

	@Override
	public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
		if(rs.getString(columnName) != null) {
			String[] split = rs.getString(columnName).split(",");
			return Arrays.asList(split);
		}
		return null;
	}

	@Override
	public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
		String[] split = rs.getString(columnIndex).split(",");
		return Arrays.asList(split);
	}

	@Override
	public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
		String[] split = cs.getString(columnIndex).split(",");
		return Arrays.asList(split);
	}

}

3、 資料庫 與 java model類

  sex屬性型別用自定義SexEnum 列舉型別

public class User {
    private Integer id;
    private String username;
    private String pazzword;
    private Integer state; 
    private Date regDate;
    private SexEnum sex; // 1:男, 0:女,用列舉
    private List<String> interest; //愛好

...}

  

4、在sql對映檔案中進行配置

 注意: 獲取資料和插入資料 的 配置

  <resultMap id="BaseResultMap" type="cn.jq.mybatis.model.User">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="username" jdbcType="VARCHAR" property="username" />
    <result column="pazzword" jdbcType="VARCHAR" property="pazzword" />
    <result column="state" jdbcType="INTEGER" property="state" />
    <result column="reg_date" jdbcType="TIMESTAMP" property="regDate" />
    <result column="sex" property="sex" 
    		jdbcType="INTEGER" 
    		javaType="cn.jq.mybatis.enums.SexEnum"
    		typeHandler="cn.jq.mybatis.enums.MySexTypeHandler"/>
    <result column="interest" property="interest" 
    		typeHandler="cn.jq.mybatis.enums.MyListTypeHandler"/>
  </resultMap>
  
  <sql id="Base_Column_List">
    id, username, pazzword, state, reg_date, sex, interest
  </sql>
  
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from t_user
    where id = #{id,jdbcType=INTEGER}
  </select>


  	<insert id="insertUser" >
		insert into t_user
			(username,pazzword,state,reg_date,sex,interest) 
		values
			(#{username},#{pazzword},#{state},#{regDate},
			#{sex, jdbcType=INTEGER, javaType=cn.jq.mybatis.enums.SexEnum, typeHandler=cn.jq.mybatis.enums.MySexTypeHandler},
			#{interest, typeHandler=cn.jq.mybatis.enums.MyListTypeHandler})
	</insert>

5、在全域性配置檔案中註冊自定義的typeHandler

    注意標籤配置順序: 在 set 標籤之後

	<typeHandlers>
		<typeHandler handler="cn.jq.mybatis.enums.MyListTypeHandler" />
		<typeHandler handler="cn.jq.mybatis.enums.MySexTypeHandler" />
	</typeHandlers>

6、測試

1)insert資料

			UserMapper userMapper = session.getMapper(UserMapper.class);
			
			List<String> list = new ArrayList<String>();
                        list.add("足球");
                        list.add("排球");
                        list.add("音樂");
			
			User user = new User();
			user.setUsername("ad22");
			user.setPazzword("pass22");
			user.setState(1);
			user.setRegDate(new Date());
			user.setSex(SexEnum.FMALE);
			//user.setInterest(null); //愛好為空,自定義typeHandle做了判斷
			user.setInterest(list);
			userMapper.insertUser(user);
			session.commit();
			System.out.println(user);

  

資料庫:

2)select 資料

			User user1 = userMapper.selectByPrimaryKey(1);
			System.out.println(user1);

 

 

 

 

 

 

 

 

 

 

小結
OK,經過上面的介紹,想必小夥伴對typeHandler的使用已經有一定了解了,總結一下就是讀取時的配置要和插入時的配置分開來做,

讀取時資料轉換我們有兩種配置方式,分別是resultMap和在mybatis配置檔案中配置typeHandlers,

插入時的配置就是在insert節點中進行配置。

 

參考文章: 

https://blog.csdn.net/u012702547/article/details/54572679

https://www.cnblogs.com/dongying/p/4040435.html