前言

TypeHandler

TypeHandler 是 Mybatis 中的类型处理器,用于 JavaType 和 JdbcType 之间的切换

1
2
3
4
5
6
7
8
9
10
11
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

BaseTypeHandler 是在 TypeHandler 的基础上做的一层封装,让类型处理器的实现更加简单

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
public abstract class BaseTypeHandler<T> extends TypeReference<T> implements TypeHandler<T> {

@Deprecated
protected Configuration configuration;

@Deprecated
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 {
try {
return getNullableResult(rs, columnName);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column '" + columnName + "' from result set. Cause: " + e, e);
}
}

@Override
public T getResult(ResultSet rs, int columnIndex) throws SQLException {
try {
return getNullableResult(rs, columnIndex);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column #" + columnIndex + " from result set. Cause: " + e, e);
}
}

@Override
public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
try {
return getNullableResult(cs, columnIndex);
} catch (Exception e) {
throw new ResultMapException("Error attempting to get column #" + columnIndex + " from callable statement. Cause: " + e, e);
}
}

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;

}

SpringBoot 实现自定义TypeHandler

以下是自定义的类型处理器,作用是将 String[] 转换为 varchar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@MappedTypes(String[].class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class StringArrayHandlerType extends BaseTypeHandler<String[]> {


@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, String[] strings, JdbcType jdbcType) throws SQLException {
preparedStatement.setString(i, StringUtils.join(Arrays.asList(strings), ","));
}

@Override
public String[] getNullableResult(ResultSet resultSet, String s) throws SQLException {
return this.getStringArray(resultSet.getString(s));
}

@Override
public String[] getNullableResult(ResultSet resultSet, int i) throws SQLException {
return this.getStringArray(resultSet.getString(i));
}

@Override
public String[] getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return this.getStringArray(callableStatement.getString(i));
}

private String[] getStringArray(String s){
return s.split(",");
}
}

application.yml

1
2
3
mybatis:
mapperLocations: classpath:mapper/*.xml
type-handlers-package: com.yxd.sharding.mybatis

测试

User.java

1
2
3
4
5
6
@Data
public class User {
private String username;
private String password;
private String[] hobbies;
}

UserMapper.java

1
2
3
4
5
6
7
8
@Mapper
public interface UserMapper {
@Insert("INSERT INTO user (`username`, `password`, `hobbies`) VALUES(#{username}, #{password}, #{hobbies})")
int insert(User user);

@Select("SELECT * FROM user WHERE id = #{id}")
User getById(Integer id);
}

数据库:user

字段名 类型
id int
username varchar
password varchar
hobbies varchar

单元测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
void insert() {
User user = new User();
user.setUsername("yuxudong");
user.setPassword("123456");
String[] hobbies = {"唱", "跳", "rap", "篮球"};
user.setHobbies(hobbies);
// 插入成功
userMapper.insert(user);
}

@Test
void get() {
User user = userMapper.getById(1);
// User(username=yuxudong, password=123456, hobbies=[唱, 跳, rap, 篮球])
System.out.println(user);
}

数据库中的结果

id username password hobbies
1 yuxudong 123456 唱, 跳, rap, 篮球