需求:
一个商户,在登记的时候需要注册它的经营范围。比如1手机,2电脑,3相机,4平板,在界面上是一个复选框(checkbox)。
在数据库保存的是用逗号分隔的字符串,例如“1,3,4”,而返回给程序的时候是整形数组List {1,3,4}。很显然,mybatis默认提供的类型转换器达不到这样的要求,这种情况下,我们可以自定义mybatis的类型转换器就可以实现自定义 Java类型与数据库类型之间的自动转换
实现:
自定义一个TypeHandler,在对数据库时进行入库操作时,将List 类型的数据自动转换为逗号分隔的字符串进行入库,在查询时,自动再转换为List进行返回,
- 数据库定义
CREATE TABLE `merchant` (
`id` int(11) NOT NULL,
`name` varchar(100) NOT NULL,
`scope` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- merchant POJO:
package com.gupaoedu.domain;
import lombok.Data;
import java.util.List;
@Data
public class Merchant {
private int id;
private String name;
private List<Integer> scope;
}
- 自定义typeHandler
自定义的typeHandler或者是mybatis默认的typeHandler,都会去继承一个基类BaseTypeHandler<>, 其中的泛型是我们要处理的Java类型,需要重写四个方法:
setNonNullParameter: 设置String类型的参数时调用, 从Java类型到Jdbc类型的转换,只有在insert语句中的字段上加上typehandler=自定义的typeHandler全类名,才会生效
getNullableResult(ResultSet resultSet, String s) : 根据列名获取String 类型的参数时调用,从数据库查询出Jdbc类型,把它赋值给Java类型时会调用,是Jdbc类型 -》 Java类型
getNullableResult(CallableStatement callableStatement, int i) 根据参数索引获取
package com.gupaoedu.type;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class MerchantHandler extends BaseTypeHandler<List<Integer>> {
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, List<Integer> integers, JdbcType jdbcType) throws SQLException {
StringBuffer sb = new StringBuffer();
integers.forEach(integer -> {
sb.append(String.valueOf(integer)).append(",");
});
preparedStatement.setString(i, sb.substring(0, sb.length() - 1));
}
@Override
public List<Integer> getNullableResult(ResultSet resultSet, String s) throws SQLException {
if(null == resultSet.getString(s) || 0 == resultSet.getString(s).trim().length()){
return null;
}
String[] split= resultSet.getString(s).split(",");
List<Integer> list= new ArrayList<>();
for (String str : split) {
list.add(Integer.valueOf(str));
}
return list;
}
@Override
public List<Integer> getNullableResult(ResultSet resultSet, int i) throws SQLException {
return null;
}
@Override
public List<Integer> getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
return null;
}
}
- mapper接口和xml
package com.gupaoedu.mapper;
import com.gupaoedu.domain.Merchant;
import org.apache.ibatis.annotations.Param;
public interface MerchantMapper {
Merchant getMerchantById(@Param("id") int id);
int insertMerchant(Merchant merchant);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.gupaoedu.mapper.MerchantMapper">
<resultMap id="merchantMap" type="com.gupaoedu.domain.Merchant">
<id property="id" column="id"/>
<result property="name" column="name"/>
<result property="scope" column="scope" jdbcType="VARCHAR"
javaType="list" typeHandler="com.gupaoedu.type.MerchantHandler"/>
</resultMap>
<select id="getMerchantById" resultMap="merchantMap">
select * from merchant where id = #{id}
</select>
<insert id="insertMerchant" parameterType="com.gupaoedu.domain.Merchant">
INSERT INTO merchant(name, scope)VALUES
( #{name},#{scope,typeHandler=com.gupaoedu.type.MerchantHandler,jdbcType=VARCHAR})
</insert>
</mapper>
- mybatis全局配置添加:
<typeHandlers>
<typeHandler jdbcType="VARCHAR" javaType="list" handler="com.gupaoedu.type.MerchantHandler"/>
</typeHandlers>
<mappers>
<mapper resource="BlogMapper.xml"/>
<mapper resource="BlogMapperExt.xml"/>
<mapper resource="MerchantMapper.xml"/>
</mappers>
- 测试类
package com.gupaoedu;
import com.gupaoedu.domain.Merchant;
import com.gupaoedu.mapper.MerchantMapper;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
public class MyTypeHandlerTest {
private SqlSessionFactory sqlSessionFactory;
@Before
public void prepare() throws IOException {
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
inputStream.close();
}
@Test
public void getMerchantByIdTest(){
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
MerchantMapper mapper = sqlSession.getMapper(MerchantMapper.class);
Merchant merchant = mapper.getMerchantById(1);
System.out.println(merchant);
}catch (Exception e) {
e.printStackTrace();
}finally {
sqlSession.close();
}
}
@Test
public void insertMerchant(){
Merchant merchant = new Merchant();
merchant.setName("gupaoedu");
List<Integer> scope = Arrays.asList(new Integer[]{1,2,3,4});
merchant.setScope(scope);
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
MerchantMapper mapper = sqlSession.getMapper(MerchantMapper.class);
int rowAffected = mapper.insertMerchant(merchant);
// 这里需要手动提交才可以!SqlSession的默认实现DefaultSqlSession中的openSession方法,默认设置的autoCommit是false!!!
sqlSession.commit();
System.out.println(rowAffected);
}catch (Exception e) {
e.printStackTrace();
}finally {
sqlSession.close();
}
}
}
- 测试结果
在插入操作中,忘记了事务提交操作,导致每次看到数据库执行了插入操作,然后又被自动回滚了,查看sqlSessionFactory.openSession()的实现,发现openSession方法默认是关闭了自动提交事务的