在大學寫web應用的時候經常會遇到這么個問題,當我要插入一條數據,某個數據是Date類型,數據庫中卻是VARCHAR類型,這個時候可能會傻乎乎的先把這個數據自己手動轉換成String類型再插入到數據庫中,其實大可不必。MyBatis為我們提供了更好的方法即是TypeHandler來應對Java和jdbc字段類型不匹配的情況。MyBatis中內置了不少的TypeHandler,如果我們想要自己自定義一個TypeHandler可以實現TypeHandler接口,也可以繼承BaseTypeHandler類。下面我們實現一個將Java中的Date類型利用我們自定義的ExampleTypeHandler來轉換為JDBC的VARCHAR類型。
我們對MyBatis的介紹先局限在使用,在會使用過后我們再究其原理、源碼。
1 package day_8_mybatis.util; 2 3 import java.sql.CallableStatement; 4 import java.sql.PreparedStatement; 5 import java.sql.ResultSet; 6 import java.sql.SQLException; 7 import java.util.Date; 8 9 import org.apache.ibatis.type.BaseTypeHandler; 10 import org.apache.ibatis.type.JdbcType; 11 12 /** 13 * 注意在引入Date所在的包時,是java.util.Date,而不是java.sql.Date,這一點不要搞錯。 14 * @author turbo 15 * 16 * 2016年10月23日 17 */ 18 public class ExampleTypeHandler extends BaseTypeHandler<Date> { 19 20 /* 根據列名,獲取可以為空的結果 21 * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.ResultSet, java.lang.String) 22 */ 23 @Override 24 public Date getNullableResult(ResultSet rs, String columnName) 25 throws SQLException { 26 String sqlTimetamp = rs.getString(columnName); 27 if (null != sqlTimetamp){ 28 return new Date(Long.valueOf(sqlTimetamp)); 29 } 30 return null; 31 } 32 33 /* 根據列索引,獲取可以為空的結果 34 * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.ResultSet, int) 35 */ 36 @Override 37 public Date getNullableResult(ResultSet rs, int columnIndex) 38 throws SQLException { 39 String sqlTimetamp = rs.getString(columnIndex); 40 if (null != sqlTimetamp){ 41 return new Date(Long.valueOf(sqlTimetamp)); 42 } 43 return null; 44 } 45 46 /*47 * @see org.apache.ibatis.type.BaseTypeHandler#getNullableResult(java.sql.CallableStatement, int) 48 */ 49 @Override 50 public Date getNullableResult(CallableStatement cs, int columnIndex) 51 throws SQLException { 52 String sqlTimetamp = cs.getString(columnIndex); 53 if (null != sqlTimetamp){ 54 return new Date(Long.valueOf(sqlTimetamp)); 55 } 56 return null; 57 } 58 59 /* 設置非空參數 60 * @see org.apache.ibatis.type.BaseTypeHandler#setNonNullParameter(java.sql.PreparedStatement, int, java.lang.Object, org.apache.ibatis.type.JdbcType) 61 */ 62 @Override 63 public void setNonNullParameter(PreparedStatement ps, int i, Date parameter, 64 JdbcType jdbcType) throws SQLException { 65 ps.setString(i, String.valueOf(parameter.getTime())); 66 } 67 68 69 70 }
我們已經自定義了一個TypeHandler,接着我們要在mybatis-config.xml中注冊。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE configuration 3 PUBLIC "-//mybatis.org//DTD Config 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-config.dtd"> 5 6 <configuration> 7 <!-- 注意configuration中各個屬性配置的順序應為:properties,settings,typeAliases,typeHandlers,objectFactory,objectWrapperFactory,reflectorFactory,plugins,environments,databaseIdProvider,mappers)--> 8 <properties> 9 <property name="driver" value="com.mysql.jdbc.Driver"/> 10 <property name="url" value="jdbc:mysql://localhost:3306/test"/> 11 <property name="username" value="root"/> 12 <property name="password" value="0000"/> 13 </properties> 14 <typeHandlers> 15 <typeHandler handler="day_8_mybatis.util.ExampleTypeHandler" javaType="java.util.Date" jdbcType="VARCHAR"/> 16 </typeHandlers> 17 18 <environments default="development"> 19 <environment id="development"> 20 <transactionManager type="JDBC" /> 21 <dataSource type="POOLED"> 22 <property name="driver" value="${driver}"/> 23 <property name="url" value="${url}"/> 24 <property name="username" value="${username}"/> 25 <property name="password" value="${password}"/> 26 </dataSource> 27 </environment> 28 </environments> 29 <mappers> 30 <mapper resource="day_8_mybatis/mapper/UserMapper.xml"/> 31 <mapper resource="day_8_mybatis/mapper/NoteMapper.xml"/> 32 </mappers> 33 34 </configuration> 35 36
注意各個屬性配置有順序之分,不能隨意穿插。
准備工作已經做完了,我們接着按部就班的實現POJO類 Note里面包含id和date字段。
1 package day_8_mybatis.pojo; 2 3 import java.util.Date; 4 5 /** 6 * @author turbo 7 * 8 * 2016年10月23日 9 */ 10 public class Note { 11 private int id; 12 private Date date; 13 public int getId() { 14 return id; 15 } 16 public void setId(int id) { 17 this.id = id; 18 } 19 public Date getDate() { 20 return date; 21 } 22 public void setDate(Date date) { 23 this.date = date; 24 } 25 }
接着是負責與數據庫交互Dao層的NoteMapper接口,我們只舉例查詢和插入。
1 package day_8_mybatis.mapper; 2 3 import day_8_mybatis.pojo.Note; 4 5 /** 6 * @author turbo 7 * 8 * 2016年10月23日 9 */ 10 public interface NoteMapper { 11 Note queryNote(int id); 12 void insertNote(Note note); 13 }
我們再來看看在NoteMapper.xml中是如何利用我們剛才自定義的TypeHandler。
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE mapper 3 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 4 "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> 5 <mapper namespace="day_8_mybatis.mapper.NoteMapper"> 6 <resultMap type="day_8_mybatis.pojo.Note" id="note-base"> 7 <result property="id" column="id"/> 8 <result property="date" column="date" typeHandler="day_8_mybatis.util.ExampleTypeHandler"/> 9 </resultMap> 10 11 <select id="queryNote" parameterType="int" resultMap="note-base"> 12 select * from note where id = #{id} 13 </select> 14 <insert id="insertNote" parameterType="day_8_mybatis.pojo.Note"> 15 insert into note (id, date) values(#{id}, #{date, typeHandler=day_8_mybatis.util.ExampleTypeHandler}) <!--使用我們自定義的TypeHandler--> 16 </insert> 17 </mapper>
最后我們在客戶端測試一下。
1 package day_8_mybatis; 2 3 import java.io.IOException; 4 import java.util.Date; 5 6 import org.apache.ibatis.session.SqlSession; 7 8 import day_8_mybatis.mapper.NoteMapper; 9 import day_8_mybatis.pojo.Note; 10 import day_8_mybatis.util.SessionFactory; 11 12 /** 13 * 客戶端 14 * @author turbo 15 * 16 * 2016年9月11日 17 */ 18 public class Main { 19 20 /** 21 * @param args 22 * @throws IOException 23 */ 24 public static void main(String[] args) throws Exception { 25 String resource = "day_8_mybatis/mybatis-config.xml"; //獲取mybatis配置文件路徑 26 SqlSession sqlSession = SessionFactory.getSqlSession(resource); //通過SessionFactory工具類(此工具類為自己構造即util包中的SessionFactory)構造SqlSession 27 28 NoteMapper noteMapper = sqlSession.getMapper(NoteMapper.class); 29 30 Note note = new Note(); 31 note.setId(1); 32 note.setDate(new Date()); 33 noteMapper.insertNote(note); //插入 34 sqlSession.commit(); //注意需要手動提交事務 35 36 note = noteMapper.queryNote(2); //查詢 37 System.out.println(note.getDate()); 38 } 39 40 }
注意在34行代碼,需要手動提交事務,默認是關閉自動提交的,所以必須手動提交。開始沒有提交事務,無論怎么都沒辦法插入到數據庫,后來debug單步調試的時候發現了autoCommit=false,才想起來在以前大學的時候也遇到過這個這個問題所以一下就定位問題在哪兒了。
數據庫中只有一個note表,字段為id類型為int,date字段為varchar。
至此我們就完成了自定義的TypeHandler,其實MyBatis為我們提供的TypeHandler已經不少了,不過我們還是自己試驗一把,先把MyBatis學會使用,再究其原理。
這是一個能給程序員加buff的公眾號