Spring Boot整合MyBatis框架
引入MyBatis的starter
在maven的pom.xml文件中引入如下的mybatis依赖,这里的数据库使用MySQL,所以同时加入MySQL的依赖:
<!-- 配置MySQL依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.42</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 配置MyBatis依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
创建POJO实例
创建User类如下,@Data注解为使用了lombok库,@Alias注解为使用MyBatis的别名,即将当前的User类别名定义为user,这样在MyBatis的xml文件中进行设置时,可以直接使用这里定义的别名,无需使用User类的全限定名。(如果这里不使用别名,则后续xml中使用该类时,需要使用该类的全限定名)
@Data
@Alias(value = "user")
public class User {
private Long id;
@NotNull(message = "用户名不能为空")
private String userName;
@NotNull(message = "备注不能为空")
private String note;
@NotNull(message = "性别不能为空")
private SexEnum sex;
}
同时注意这里的sex属性的类型为SexEnum枚举类型,所以需要定义一个typeHandler来进行转换:
// 声明JDBCType为整型
@MappedJdbcTypes(JdbcType.INTEGER)
// 声明JavaType为SexEnum
@MappedTypes(value = SexEnum.class)
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
/**
* 设置非空性别参数
*/
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int i, SexEnum sexEnum, JdbcType jdbcType) throws SQLException {
preparedStatement.setInt(i, sexEnum.getId());
}
/**
* 通过列名读取性别
*/
@Override
public SexEnum getNullableResult(ResultSet resultSet, String s) throws SQLException {
int sex = resultSet.getInt(s);
if (sex != 1 && sex != 2) {
return null;
}
return SexEnum.getEnumById(sex);
}
/**
* 通过下标读取性别
*/
@Override
public SexEnum getNullableResult(ResultSet resultSet, int i) throws SQLException {
int sex = resultSet.getInt(i);
if (sex != 1 && sex != 2) {
return null;
}
return SexEnum.getEnumById(sex);
}
/**
* 通过存储过程读取性别
*/
@Override
public SexEnum getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
int sex = callableStatement.getInt(i);
if (sex != 1 && sex != 2) {
return null;
}
return SexEnum.getEnumById(sex);
}
}
这样MyBatis就可以根据这里的设置,自动将sex的枚举类型转换为Integer类型。
创建数据库表结构
根据上述的User类,定义如下的数据库表结构:
create table t_user (
id int(12) not null auto_increment,
user_name varchar(60) not null,
sex int(3) not null default 1 check (sex in(1,2)),
note varchar(256) null,
primary key(id)
);
创建MyBatis映射文件
完成上述的步骤后,MyBatis支持使用注解和配置文件的方式来实现SQL和POJO的映射关系,这里使用XML配置文件的方式进行,定义userMapper.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.zyt.springbootlearning.dao.UserMapper">
<select id="getUserById" parameterType="long" resultType="user">
select id, user_name as userName, sex, note from t_user where id = #{id}
</select>
</mapper>
该文件的所在路径为:/resources/mapper/userMapper.xml,后面需要该xml所在的路径进行配置。
可以看到,该文件中存在几个关键的配置信息,如下:
- namespace:指明用于操作该表的一个接口的全限定名,后续会进行创建。
- parameterType:定义select语句中使用的参数的类型,这里的Id为Long类型。
- resultType:指明查询语句执行后得到的返回值类型。由于上述User类中使用了MyBatis的别名设置,所以这里可以直接使用上述设置的user别名,如果没有使用别名,则需要使用User类的全限定名:cn.zyt.springbootlearning.domain.User。
- select标签内,使用SQL创建需要进行数据库操作的SQL语句,这里的查询列名需要和POJO类中的属性名保持一致,MyBaits会自动启动这种映射。但注意这里的userName列使用了别名将查询后的结果映射到User类的useName属性。针对这种情况,也可以开启驼峰映射,这样就可以不使用别名了(这个在application.properties中进行设置,开启驼峰映射)。或者在userMapper.xml配置文件中,使用ResultMap指明属性名和数据表表列名之间的映射关系。如下:
<resultMap id="getUserByResultMap" type="cn.zyt.springbootlearning.domain.User">
<result property="userName" column="user_name"/>
</resultMap>
<select id="getUserByMap" parameterType="long" resultMap="getUserByResultMap">
select id, user_name as userName, sex, note from t_user where id = #{id}
</select>
resultMap标签中的property为POJO中的属性名,column为表中的列名,通过这种定义就可以将POPO中的属性名和表中的列名映射起来,同时如果使用了resultMap,select标签中的SQL返回时不在使用returnType而是需要指明resultMap(根据resultMap的id指明)。resultMap还有很多有用的功能,这里只是简单的进行使用。
定义MyBatis映射接口
上述namespace指明了该select语句对应的接口全限定名,所以需要定义如下对应的结构,来映射到这条select语句:
@Repository
public interface UserMapper {
User getUserById(Long id);
}
注意这里使用了@Repsitory注解,这样就定义好了select语句相对应的查询方法,接口中的方法名与mapper.xml文件中select标签中的id需一致。
在application.properties配置文件中配置mybatis相关设置
# MySQL配置项
spring.datasource.url=jdbc:mysql://[mysql_server_ip]:3306/dev_springboot
spring.datasource.username=[username]
spring.datasource.password=[password]
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.tomcat.max-idle=10
spring.datasource.tomcat.max-wait=10000
spring.datasource.tomcat.max-active=50
spring.datasource.tomcat.min-idle=5
spring.datasource.tomcat.initial-size=5
# MyBatis配置项
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=cn.zyt.springbootlearning.domain
mybatis.type-handlers-package=cn.zyt.springbootlearning.typehandler
mybatis.configuration.map-underscore-to-camel-case=true
mybatis.configuration.default-fetch-size=100
mybatis.configuration.default-statement-timeout=30
在mybatis的配置项中,有如下几个需要注意:
- mybatis.mapper-locations:定义了项目中mapper.xml映射文件所在的目录
- mybatis.type-aliases-packages:定义MyBatis扫描别名的包,与上述@Alias注解联用。
- mybatis.type-handlers-package:由于上述使用到了typeHandler,这里需要指明typeHandler所在的包
- mybatis.configuration.map-underscore-to-camel-case=true:开启驼峰映射,这样mybatis可以直接将数据表中的user_name列名映射为userName属性值,无需其他配置
Spring Boot整合MyBatis
在Spring Boot中使用MyBatis中定义的UserMapper接口的getUserById方法时,有几种不同的方式:
- 使用MapperFactoryBean装配MyBatis接口
- 使用MapperScannerConfigurer扫描装配MyBatis接口
- 使用@MapperScan注解扫描装配MyBatis接口
其中,最后一种方式最简单且常用,所以下面使用最后一种方式来扫描并装配MyBatis接口。在Spring Boot项目的启动类中加入如下注解:
@SpringBootApplication(scanBasePackages = {"cn.zyt.springbootlearning.*"})
@MapperScan(basePackages = "cn.zyt.springbootlearning.*", annotationClass = Repository.class)
public class SpringbootLearningApplication {
...
}
注意上述的@MapperScan注解,该注解允许我们通过扫描加载MyBatis的mapper。并且这在MyBatis接口中使用了@Respository注解,所以在annotationClass定义为Respository,同时Spring Boot还提供了一个@Mapper注解,其作用于@Respository注解相同,二者选用其一即可。
创建Service和Controller进行测试
通过上述的过程即基本完成了Spring Boot中整合MyBatis的过程,只是在使用MyBatis时需要根据具体的业务逻辑更加深入的使用MyBatis的功能即可。下面使用上述定义的UserMapper接口中的getUserById方法,创建相应的Service和Controller对整合的情况进行测试。
1. 创建如下的UserService接口和UserServiceImpl实现类:
public interface UserService {
User getUserById(Long id);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getUserById(Long id) {
return userMapper.getUserById(id);
}
}
2. 创建如下的UserController类:
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/getUserById")
@ResponseBody
public User getUserById(Long id) {
User user = userService.getUserById(id);
return user;
}
}
3. 完成上述内容后,启动Spring Boot项目,然后在浏览器中输入: http://localhost:8080/user/getUserById来进行测试,即可得到数据库中相应的返回数据(前提是数据库中有数据,上述过程没有进行参数校验和有效性查询)。
通过以上过程即完成了Spring Boot项目整合MyBatis的过程,后续需要更加详细的学习MyBatis的使用。上面仅是简单的使用select语句使用id进行了数据库的查询操作,下面给出一些其他的mapper.xml配置,以供参考:
<insert id="insertUser" parameterType="cn.zyt.springbootlearning.domain.User" useGeneratedKeys="true" keyProperty="id">
insert into t_user (user_name, sex, note) values (#{userName}, #{sex}, #{note})
</insert>
<select id="getUserList" resultType="cn.zyt.springbootlearning.domain.User">
select * from t_user
</select>
<select id="searchUser" resultType="cn.zyt.springbootlearning.domain.User">
select * from t_user where id = #{userId} or user_name = #{userName}
</select>
上述的代码来自自己的springboot-learning项目,感兴趣的可以进行查看:https://github.com/Yitian-Zhang/springboot-learning。