SpringBoot series Mybatis custom type conversion TypeHandler
When using mybatis for db operations, one of the things we often do is to map the fields in the db to java beans. Usually we use ResultMap
to implement the mapping. Through this tag, the binding relationship between the two can be specified, then if the java bean The field type in db is different from that in db, what should I do?
For example, it is timestamp in db, but long is defined in java bean
BaseTypeHandler
Implement custom type conversions by
<!-- more -->
I. Environmental Preparation
1. Database preparation
Use mysql as the instance database of this article and add a new table
CREATE TABLE `money` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
`money` int(26) NOT NULL DEFAULT '0' COMMENT '钱',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;
2. Project Environment
This article is developed with the help of SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+IDEA
pom dependencies are as follows
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
db configuration informationapplication.yml
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password:
II. Example Demonstration
1. entity definition
Note that thecreate_at
types of and in the above case are both , and the Entity we define is as followsupdate_at
timestmap
@Data
public class MoneyPo {
private Integer id;
private String name;
private Long money;
private Integer isDeleted;
private Timestamp createAt;
private Long updateAt;
}
2. Mapper test interface
Define a simple query interface, where the annotation method is used directly (as for the way of writing xml, there is not much difference)
/**
* 主键查询
*
* @param id id
* @return {@link MoneyPo}
*/
@Select("select * from money where id = #{id}")
@Results(id = "moneyResultMap", value = {
@Result(property = "id", column = "id", id = true, jdbcType = JdbcType.INTEGER),
@Result(property = "name", column = "name", jdbcType = JdbcType.VARCHAR),
@Result(property = "money", column = "money", jdbcType = JdbcType.INTEGER),
@Result(property = "isDeleted", column = "is_deleted", jdbcType = JdbcType.TINYINT),
@Result(property = "createAt", column = "create_at", jdbcType = JdbcType.TIMESTAMP),
// @Result(property = "updateAt", column = "update_at", jdbcType = JdbcType.TIMESTAMP)})
@Result(property = "updateAt", column = "update_at", jdbcType = JdbcType.TIMESTAMP, typeHandler = Timestamp2LongHandler.class)})
MoneyPo getById(@Param("id") int id);
// 关于 SelectProvider 的使用,后面再说,主要是动态sql的演示
@SelectProvider(type = MoneyService.class, method = "getByIdSql")
@ResultMap(value = "moneyResultMap")
MoneyPo getByIdForProvider(@Param("id") int id);
illustrate:
@Results
: This annotation has the same effect as the ResultMap label, and is mainly used to define the mapping relationship between the fields of the db and the java beanid = "moneyResultMap"
This id definition can realize the reuse of @Results@Result
: Pay attention toupdateAt
the typeHandler below, where a custom TypeHandler is specified to realizeJdbcType.TEMSTAMP
the conversion with the long in Java Bean
3. Type conversion
Custom type conversion, mainly inheritance BaseTypeHandler
class, the type of generic is the type in Java Bean
/**
* 自定义类型转换:将数据库中的日期类型,转换成long类型的时间戳
*
* 三种注册方式:
* 1.直接在 result标签中,指定typeHandler,如@Result(property = "updateAt", column = "update_at", jdbcType = JdbcType.TIMESTAMP, typeHandler = Timestamp2LongHandler.class)
* 2.在SqlSessionFactory实例中,注册 在SqlSessionFactory实例中.setTypeHandlers(new Timestamp2LongHandler());
* 3.xml配置,<typeHandler handler="com.git.hui.boot.mybatis.handler.Timestamp2LongHandler"/>
*
* @author yihui
* @date 2021/7/7
*/
@MappedTypes(value = Long.class)
@MappedJdbcTypes(value = {JdbcType.DATE, JdbcType.TIME, JdbcType.TIMESTAMP})
public class Timestamp2LongHandler extends BaseTypeHandler<Long> {
/**
* 将java类型,转换为jdbc类型
*
* @param preparedStatement
* @param i
* @param aLong 毫秒时间戳
* @param jdbcType db字段类型
* @throws SQLException
*/
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, Long aLong, JdbcType jdbcType) throws SQLException {
if (jdbcType == JdbcType.DATE) {
preparedStatement.setDate(i, new Date(aLong));
} else if (jdbcType == JdbcType.TIME) {
preparedStatement.setTime(i, new Time(aLong));
} else if (jdbcType == JdbcType.TIMESTAMP) {
preparedStatement.setTimestamp(i, new Timestamp(aLong));
}
}
@Override
public Long getNullableResult(ResultSet resultSet, String s) throws SQLException {
return parse2time(resultSet.getObject(s));
}
@Override
public Long getNullableResult(ResultSet resultSet, int i) throws SQLException {
return parse2time(resultSet.getObject(i));
}
@Override
public Long getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return parse2time(callableStatement.getObject(i));
}
private Long parse2time(Object value) {
if (value instanceof Date) {
return ((Date) value).getTime();
} else if (value instanceof Time) {
return ((Time) value).getTime();
} else if (value instanceof Timestamp) {
return ((Timestamp) value).getTime();
}
return null;
}
}
- setNonNullParameter: Convert java type to jdbc type
- getNullableResult: Convert jdbc type to java type
4. TypeHandler registration
It's fine for us to define a TypeHandler ourselves, and then we need it to take effect. Generally speaking, there are the following ways
4.1 Specified in result tag
Specified by typeHandler in the result tag
The way to use xml is like
<result column="update_at" property="updateAt" jdbcType="TIMESTAMP" typeHandler="com.git.hui.boot.mybatis.handler.Timestamp2LongHandler"/>
The way to annotate @Result is as follows
@Result(property = "updateAt", column = "update_at", jdbcType = JdbcType.TIMESTAMP, typeHandler = Timestamp2LongHandler.class)
4.2 SqlSessionFactory global configuration
The above usage poses are precisely specified. If we want to apply to all scenes, we can SqlSessionFactory
achieve this by
@Bean(name = "sqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
bean.setMapperLocations(
// 设置mybatis的xml所在位置,这里使用mybatis注解方式,没有配置xml文件
new PathMatchingResourcePatternResolver().getResources("classpath*:mapping/*.xml"));
// 注册typehandler,供全局使用
bean.setTypeHandlers(new Timestamp2LongHandler());
return bean.getObject();
}
4.3 Global xml configuration
In addition to the above case, there is another way mybatis-config.xml
to register with the help of configuration files, such as
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//ibatis.apache.org//DTD Config 3.1//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 驼峰下划线格式支持 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeHandlers>
<typeHandler handler="com.git.hui.boot.mybatis.handler.Timestamp2LongHandler"/>
</typeHandlers>
</configuration>
Note that using the above configuration file, you need to specify the following configuration in SpringBoot, otherwise it will not take effect
mybatis:
config-location: classpath:mybatis-config.xml
4.4 SpringBoot configuration
type-handlers-package
springboot configuration file, you can register TypeHandler by specifying
mybatis:
type-handlers-package: com.git.hui.boot.mybatis.handler
5. Summary
This article mainly introduces the mapping adaptation strategy of types in db and types in java beans, mainly through inheritance BaseTypeHandler
to achieve custom type conversion
To use a custom TypeHandler, there are two ways: global effect and precise specification
@Result
/<result>
tag, specified by typeHandler- SqlSessionFactory sets typeHandler globally
mybatis-config.xml
Profile settingstypeHandlers
In addition, in the configuration of this article, the inter-conversion configuration of hump and underscore is also supported, which is also a common configuration. You can configure mybatis-config
it as follows in
<setting name="mapUnderscoreToCamelCase" value="true"/>
The next question is, hump can be interchanged with underscore, so is there a way to implement custom name mapping?
III. Source code and related knowledge points that cannot be missed
0. Project
- Engineering: https://github.com/liuyueyi/spring-boot-demo
- Source code: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/104-mybatis-ano
- Source code: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/103-mybatis-xml
mybatis series of blog posts
- [DB series] SpringBoot series Mybatis Mapper interface and Sql binding several postures
- [DB series] Several ways to register Mapper of SpringBoot series Mybatis
- [DB series] Mybatis-Plus multi-data source configuration
- [DB series] Mybatis implements multiple data source switching based on AbstractRoutingDataSource and AOP
- [DB series] Mybatis multi-data source configuration and use
- 【DB series】Multiple data source configuration and use of JdbcTemplate
- 【DB series】Mybatis-Plus code is automatically generated
- 【DB Series】MybatisPlus Integration
- 【DB Series】Mybatis+Annotation Integration
- 【DB Series】Mybatis+xml Integration
1. A gray blog
It is not as good as a letter. The above content is purely from the family. Due to limited personal ability, it is inevitable that there will be omissions and mistakes. If you find bugs or have better suggestions, you are welcome to criticize and correct them. Thank you
The following is a gray personal blog, recording all blog posts in study and work, welcome everyone to visit
- A Huihui Blog Personal blog https://blog.hhui.top
- A gray Blog-Spring special blog http://spring.hhui.top