1. The role of TypeHandler and its usage scenarios
When we usually develop and operate databases, querying, inserting data and other operations, sometimes data type mismatch exceptions are reported, and we can know that the data type is not unique and must be a variety of different data types. And we must be clear that java, as a programming language, has its own data types, and databases also have their own data types.
jdbc data type: org.apache.ibatis.type.JdbcType This enumeration is all database support types
Java data types: int, long, string, ...
Be sure to distinguish, for example, java-heavy date data is inserted into the database, it should have been converted into a certain type of database, and it must have nothing to do with java. There are some operations that we can't see in the middle that do data processing.
Assuming that the java type at this time is the same as the database data type, how should the date data in other languages be interpreted when it is inserted into the database, for example, C# operates the database input time type, and C# must have nothing to do with java. So there is a data type relationship between each language and the database.
think:
Because java and the database have their own data types, we cannot see whether there are other operations before storing the java data in the database. Otherwise, how does the java data know which jdbc data type it matches?
Answer: The mybatis framework makes a default relationship correspondence for each data type, and all implementation classes of BaseTypeHandler are here to do these processes.
For example: what type of jdbc is the date in java when it is inserted into the database, and why is it this type? What is the specific operation in the middle?
Answer: DateTypeHandler is to solve the processing of date data type.
2. Use of TypeHandler
When we want to customize the data type conversion between Java and JDBC, we need to implement the TypeHandler interface. The source code of this interface is as follows:
//此接口作用是用于指定jdbc与java的数据类型间对应关系处理。
public interface TypeHandler<T> {
// 保存操作,数据入库之前时数据处理
void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;
//下面三个则是,从数据库加载数据后,vo对象封装前的数据处理
T getResult(ResultSet rs, String columnName) throws SQLException;
T getResult(ResultSet rs, int columnIndex) throws SQLException;
T getResult(CallableStatement cs, int columnIndex) throws SQLException;
}
If it is necessary to convert the list field to varchar before inserting it into the database, that is, list [1,2,3] == "varchar 1,2,3, and automatically convert from the list type when loading from the database to the program, the implementation code is as follows :
1. Write the typehandler implementation class and formulate conversion rules
package com.cjy.mybatis.typehandler;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.apache.ibatis.type.TypeHandler;
import org.apache.log4j.Logger;
@MappedJdbcTypes(JdbcType.VARCHAR) //数据库类型
@MappedTypes({List.class}) //java数据类型
public class ListTypeHandler implements TypeHandler<List<String>>{
private Logger logger = Logger.getLogger(ListTypeHandler.class);
@Override
public void setParameter(PreparedStatement ps, int i,
List<String> parameter, JdbcType jdbcType) throws SQLException {
logger.info("method ====>>> setParameter");
String hobbys = dealListToOneStr(parameter);
ps.setString(i , hobbys);
}
/**
* 集合拼接字符串
* @param parameter
* @return
*/
private String dealListToOneStr(List<String> parameter){
if(parameter == null || parameter.size() <=0)
return null;
String res = "";
for (int i = 0 ;i < parameter.size(); i++) {
if(i == parameter.size()-1){
res+=parameter.get(i);
return res;
}
res+=parameter.get(i)+",";
}
return null;
}
//
@Override
public List<String> getResult(ResultSet rs, String columnName)
throws SQLException {
logger.info("method ====>>> getResult(ResultSet rs, String columnName)");
return Arrays.asList(rs.getString(columnName).split(","));
}
@Override
public List<String> getResult(ResultSet rs, int columnIndex)
throws SQLException {
logger.info("method ====>>> getResult(ResultSet rs, int columnIndex)");
return Arrays.asList(rs.getString(columnIndex).split(","));
}
@Override
public List<String> getResult(CallableStatement cs, int columnIndex) throws SQLException{
logger.info("method ====>>> getResult(CallableStatement cs, int columnIndex)");
String hobbys = cs.getString(columnIndex);
return Arrays.asList(hobbys.split(","));
}
}
2. Configure the mybatis xml file
<typeHandler javaType="list" jdbcType="VARCHAR" handler="com.cjy.mybatis.typehandler.ListTypeHandler"/>
3. Write SQL
<select id="selectEmp" resultType="com.cjy.mybatis.entity.Employee" parameterType="int">
select id,user_name userName,gender,email,hobbys,createtime from employee where id = #{id}
</select>
<insert id="saveEmpOne" parameterType="com.cjy.mybatis.entity.Employee" >
<!-- or parameterMap="parameMap" -->
INSERT INTO employee(user_name,gender,email,createtime,hobbys)
VALUES(#{userName},#{gender},#{email},#{createtime,typeHandler=com.cjy.mybatis.typehandler.MyDateTypeHandler},
#{hobbys,typeHandler=com.cjy.mybatis.typehandler.ListTypeHandler})
<!--数据插入前:对hobbys做数据格式转换。 -->
</insert>
4. Test code
@Test
public void test2(){
SqlSessionFactory sqlSessionFactory = MySqlSessionFacoty.getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
Employee employee = new Employee(null, "yanjiu", "1", "[email protected]", new Date(),Arrays.asList(new String[]{"yuwen","shuxue","yingyu","zhengzhi"}));
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
int saveEmpOne = mapper.saveEmpOne(employee);
System.out.println(saveEmpOne+"-------------------");
openSession.commit();
openSession.close();
}
Test Results:
query data test varchar --> list conversion::
@Test
public void test5(){
SqlSessionFactory sqlSessionFactory = MySqlSessionFacoty.getSqlSessionFactory();
SqlSession openSession = sqlSessionFactory.openSession();
EmployeeMapper mapper = openSession.getMapper(EmployeeMapper.class);
Employee selectEmp = mapper.selectEmp(10);
System.out.println(selectEmp);
/**数据加载成功
2019-07-24 15:08:02 INFO com.cjy.mybatis.typehandler.ListTypeHandler - method ====>>> getResult(ResultSet rs, String columnName)
2019-07-24 15:08:02 INFO com.cjy.mybatis.typehandler.MyDateTypeHandler - getResult(ResultSet rs, String columnName)....
Employee [id=10, userName=yanjiu, gender=1, [email protected], createtime=Wed Jul 24 15:05:58 CST 2019, hobbys=[yuwen, shuxue, yingyu, zhengzhi]]
*/
}
3. TypeHandlers registration method
Single registration: the typeHandler tag specifies the full class name of the handler
Multiple registrations: specify multiple single registration methods; or use the package tag
<typeHandlers>
<!-- <typeHandler javaType="list" jdbcType="VARCHAR" handler="com.cjy.mybatis.typehandler.ListTypeHandler"/>
<typeHandler javaType="Date" jdbcType="VARCHAR" handler="com.cjy.mybatis.typehandler.MyDateTypeHandler"/> -->
<package name="com.cjy.mybatis.typehandler"/>
<!--
typeHandler: 单个注册方式
package:多个注册方式
-->
</typeHandlers>