TypeHandler
TypeHandler
用于JDBC
类型与Java
类型的转换,例如java.sql.Date
与java.util.date
的转换,MyBatis
默认实现了很多常用的TypeHandler
,向数据库中每个列中写入或读出数据时都会先经过TypeHandler
的处理。
BaseTypeHandler
TypeHandler
是MyBatis
中处理Java
与数据库类型转换的接口,可以通过实现此接口自定义类型处理器,但自定义类型处理器是并不是直接实现TypeHandler
接口,而是继承BaseTypeHandler
抽象类,BaseTypeHandler
抽象类实现了TypeHandler
接口并实现了一部分功能,子类只需实现其中的若干方法:
public abstract class BaseTypeHandler<T>
extends TypeReference<T> implements TypeHandler<T> {
/* 作用说明:用于将Java类型转换为数据库类型
参数说明:
1.参数1,用于获取当前编译过的SQL语句,使用此对象可直接向数据库中写入数据
2.参数2,用于获取当前SQL语句中占位符的索引,通过ps.setXXX(i,obj)可向数据库写入数据
3.参数3,用于获取当前传入的参数
4.参数4,用于获取当前参数的数据库类型 */
public abstract T setNonNullParameter(PreparedStatement ps,
int i,T param,jdbcType type) throws SQLException;
/* 作用说明:用于将数据库类型转换为Java类型
参数说明:
1.参数1,用于获取查询结果集
2.参数2,用于获取当前列名,可以通过resultSet.getXXX(columnLabel)获取对应的字段值 */
public abstract T getNullableResult(ResultSet resultSet,
String columnLabel) throws SQLException;
/* 作用说明:用于将数据库类型转换为Java类型
参数说明:
1.参数1,用于获取查询结果集
2.参数2,用于获取当前列索引,可以通过resultSet.getXXX(columnIndex)获取对应的字段值 */
public abstract T getNullableResult(ResultSet resultSet,
int columnIndex) throws SQLException;
/* 作用说明:用于将数据库类型转换为Java类型
参数说明:
1.参数1,用于获取查询结果集
2.参数2,用于获取当前列索引,可以通过cs.getXXX(columnIndex)获取对应的字段值 */
public abstract T getNullableResult(CallableStatement cs,
int columnIndex) throws SQLException;
}
示例
下面将以枚举体的转换为实例说明BaseTypeHandler
的用法,数据库中的枚举数据:
`status` enum("A","B","C");
Java
中的枚举数据:
public enum Status {
A,B,C
}
类型处理器:
public class StatusTypeHandler extends BaseTypeHandler<Status> {
/* 注意必须提供空参构造器 */
public StatusTypeHandler() {
super();
}
@Override
public Status SetNonNullParameter(PreparedStatement ps,
int i,
Status param,jdbcType type) throws SQLException {
/* 将Java类型转换为数据库类型 */
if(param == Status.A) {
ps.setString(i,"A");
} else if(param == Status.B) {
ps.setString(i,"B");
} else if(param == Status.C) {
ps.setString(i,"C");
}
}
@Override
public Status getNullableResult(ResqultSet resultSet,String columnLabel)
throws SQLException {
/* 将数据库类型转换为Java类型 */
if(resultSet.getString(columnLabel).equals("A")) {return Status.A;}
else if(resultSet.getString(columnLabel).equals("B")) {return Status.B;}
else if(resultSet.getString(columnLabel).equals("C")) {return Status.C;}
return null;
}
@Override
public Status getNullableResult(ResqultSet resultSet,int columnIndex)
throws SQLException {
if(resultSet.getString(columnIndex).equals("A")) {return Status.A;}
else if(resultSet.getString(columnIndex).equals("B")) {return Status.B;}
else if(resultSet.getString(columnIndex).equals("C")) {return Status.C;}
return null;
}
@Override
public Status getNullableResult(CallableStatement cs,int columnIndex)
throws SQLException {
if(cs.getString(columnIndex).equals("A")) {return Status.A;}
else if(cs.getString(columnIndex).equals("B")) {return Status.B;}
else if(cs.getString(columnIndex).equals("C")) {return Status.C;}
return null;
}
}
自定义类型处理器必须提供空参构造器。
类型处理器的注册
application.yml
# MyBatis类型处理器在SpringBoot整合中的注册方法
mybatis:
# 指定类型处理器的所在包名
type-handlers-package: com.xxx.typehandler
MyBatis
注解开发
注解查询
@Insert
@Insert
注解的定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Insert.List.class)
public @interface Insert {
/* 指定insert SQL语句 */
String[] value();
/* 指定数据库版本号,用于区分不同的数据库 */
String databaseId() default "";
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface List {
Insert[] value();
}
}
@Delete
@Delete
注解的定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Delete.List.class)
public @interface Delete {
/* 指定delete SQL语句 */
String[] value();
/* 指定数据库版本号,用于区分不同的数据库 */
String databaseId() default "";
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface List {
Delete[] value();
}
}
@Update
@Update
注解的定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Update.List.class)
public @interface Update {
/* 指定update SQL语句 */
String[] value();
/* 指定数据库版本号,用于区分不同的数据库 */
String databaseId() default "";
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface List {
Update[] value();
}
}
@Select
@Select
注解的定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Select.List.class)
public @interface Select {
/* 指定select SQL语句 */
String[] value();
/* 指定数据库版本号,用于区分不同的数据库 */
String databaseId() default "";
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface List {
Select[] value();
}
}
查询示例
/* SpringBoot整合下的注解 */
@Mapper
@Repository
public interface UserDao {
@Select("select * from users where id = #{id}")
User selectById(@Param("id") Integer id);
}
动态SQL
注解开发支持动态SQL
,其做法是使用<script></script>
标签包裹SQL
语句,在标签中使用动态SQL
即可:
/* SpringBoot整合下的注解 */
@Mapper
@Repository
public interface UserDao {
/* 注意""使用\"\"转义 */
@Insert(
"<script>" +
"insert into users(name,password,gender,age) " +
"values" +
"<foreach collection=\"users\" item=\"user\" separator=\",\">" +
"(user.name,user.password,user.gender,user.age)" +
"</foreach>" +
"</script>")
boolean insert(@Param("users") List<User> users);
}
参数处理
使用@Param
注解可代替配置文件中的parameterType
属性,MyBatis
框架将根据此注解自动读取参数类型,并且使用@Param
注解可指定参数在SQL
语句中的引用名,@Param
注解的定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface Param {
/* 指定参数的引用名 */
String value();
}
返回处理
@ResultType
@Results
@Results
注解用处理较为复杂的返回类型,例如需要为某些属性指定类型处理器的返回类型,另外还可以用来处理属性名与字段名不一致的返回类型,其定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Results {
/* 为结果集指定id,方便@ResultMap引用 */
String id() default "";
/* @Result注解数组 */
Result[] value() default {};
}
如果查询方法的返回类型中的属性名与数据库表中的字段名不一致,@Results
注解需要与@Result
注解配合使用指定属性与字段的对应关系,@Result
的定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Results.class)
public @interface Result {
/* 是否为主键 */
boolean id() default false;
/* 数据库表列名 */
String column() default "";
/* Java实体类属性名 */
String property() default "";
/* Java实体类属性类型 */
Class<?> javaType() default void.class;
/* JDBC类型 */
JdbcType jdbcType() default JdbcType.UNDEFINED;
/* 类型处理器 */
Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
/* 一对一关联查询 */
One one() default @One;
/* 一对多关联查询 */
Many many() default @Many;
}
@Results
使用示例:
/* SpringBoot整合下的注解 */
@Mapper
@Repository
public interface UserDao {
@Results(id="user",value = {
@Result(column = "id",property = "id"),
@Result(column = "name",property = "name"),
@Result(column = "post_id",property = "postId")
})
@Select(...)
User selectById(@Param("id") Integer id);
}
当需要多次使用相同的@Results
时,可以使用@ResultMap
引用@Results
的id
即可,@ResultMap
定义为:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface ResultMap {
/* 引用@Results的id */
String[] value();
}
使用示例:
/* SpringBoot整合下的注解 */
@Mapper
@Repository
public interface UserDao {
/* id指定唯一标识,value指定@Result数组 */
@Results(id="user",value = {
@Result(column = "id",property = "id"),
@Result(column = "name",property = "name"),
@Result(column = "post_id",property = "postId")
})
@Select(...)
User selectById(@Param("id") Integer id);
/* @ResultMap引用@Results的id;
@ResultMap注解仅有value一个属性 */
@ResultMap("user")
@Select(...)
User selectByName(@Param("name" String name));
}