目录
MyBatis已经成为移动互联网时代的主流持久层框架,在移动互联网和一些新兴的项目中MyBatis的占有率不断升高。MyBatis是一个不屏蔽SQL且提供动态SQL、接口式编程和简易SQL绑定POJO的半自动化框架,它的使用十分简单,而且能够非常容易定制SQL,以提高网站性能。
MyBatis是基于一种SQL到POJO的模型,它需要我们提供SQL、映射关系(XML或者注解)和POJO。
1.MyBatis的配置
首先我们引入MyBatis的starter,配置如下:
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
<!--定义MySql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
然后需要配置数据库的相关信息,在默认情况下,Spring Boot会使用其绑定的Tomcat数据源,我们可以对其进行配置。在jdbc.properties文件中配置如下:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=123456
#最大等待连接中的数量,设置0表示不限制
spring.datasource.tomcat.max-idle=10
#最大连接活动数
spring.datasource.tomcat.max-active=50
#最大等待毫秒数,超过时间会出错误信息
spring.datasource.tomcat.max-wait=3000
#数据库连接池初始化连接数
spring.datasource.tomcat.initial-size=5
MyBatis是一个基于SQLSessionFactory构建的框架。对于SqlSessionFactory而言,它的作用是生成SqlSession接口对象,这个接口对象是MyBatis操作的核心。而在MyBatis-Spring中的整合中,一般会"擦除"该对象,“擦除”以后就只剩下业务代码,这样就可以使得代码更具有可读性了。构建SqlSessionFactory是通过配置类完成的,因此对于mybatis-spring-boot-starter,它会给予我们在配置文件(application.properties)进行Configuration配置的相关内容。Configuration可以配置以下内容:
下面我们来看一个简单的例子:
创建数据库表并定义DO:
CREATE TABLE `user` (
`id` bigint(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(20) NOT NULL,
`sex` tinyint(2) NOT NULL,
`note` varchar(40) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
package com.martin.config.chapter5.pojo;
import lombok.Data;
import org.apache.ibatis.type.Alias;
/**
* @author: martin
* @date: 2019/11/3 10:44
* @description:
*/
@Alias(value = "user")//MyBatis指定别名
@Data
public class User {
private Long id;
private String userName;
private String note;
/**
* 定义了性别的枚举,可以通过typeHandler转换
*/
private SexEnum sex;
}
这里加入了加粗的注解@Alias,并且指定它的别名为“user”。这里定义了一个性别枚举,在MyBatis中,枚举可以通过typeHandler进行转换。因此这里开发了一个typeHandler:
package com.martin.config.chapter5.typehandler;
import com.martin.config.chapter5.pojo.SexEnum;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author: martin
* @date: 2019/11/3 10:58
* @description:
*/
@MappedJdbcTypes(JdbcType.INTEGER)
@MappedTypes(SexEnum.class)
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
/**
* 设置非空的性别参数
*
* @param preparedStatement
* @param idx
* @param object
* @param jdbcType
* @throws SQLException
*/
@Override
public void setNonNullParameter(PreparedStatement preparedStatement, int idx, SexEnum sexEnum, JdbcType jdbcType)
throws SQLException {
preparedStatement.setInt(idx, sexEnum.getCode());
}
/**
* 根据列名读取性别
*
* @param resultSet
* @param col
* @return
* @throws SQLException
*/
@Override
public SexEnum getNullableResult(ResultSet resultSet, String col) throws SQLException {
return getSexEnum(resultSet.getInt(col));
}
/**
* 根据下标读取姓名
*
* @param resultSet
* @param i
* @return
* @throws SQLException
*/
@Override
public SexEnum getNullableResult(ResultSet resultSet, int idx) throws SQLException {
return getSexEnum(resultSet.getInt(idx));
}
/**
* 通过存储过程读取性别
*
* @param callableStatement
* @param idx
* @return
* @throws SQLException
*/
@Override
public SexEnum getNullableResult(CallableStatement callableStatement, int idx) throws SQLException {
return getSexEnum(callableStatement.getInt(idx));
}
private static SexEnum getSexEnum(int sex) {
if (sex != 1 && sex != 2) {
return null;
}
return SexEnum.getEnumById(sex);
}
}
在MyBatis中对于typeHandler的要求是实现TypeHandler<T>接口,而它为了更加方便也通过抽象类BaseTypeHandler<T>实现了TypeHandler<T>接口,所以这里直接继承抽象类BaseTypeHandler<T>就可以了。注解@MappedJdbcTypes声明JdbcType为数据库的整型,@MappedTypes声明Java 类型为SexEnum,这样MyBatis就可以进行类型转换了。
为了将这个POJO能够与数据库的数据对应,还需要提供一个映射文件:
<?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.martin.config.chapter5.dao.UserMapper">
<select id="getUser" parameterType="long" resultType="user">
select id,user_name as userName,sex,note from user where id = #{id}
</select>
</mapper>
<mapper>元素的namespace属性,它指定一个接口;接着定义一个<select>元素,它代表着一个查询语句;默认情况下,MyBatis会启动自动映射,将SQL中的列映射到POJO上,有时候我们也可以启动驼峰映射,这样就可以不启用别名了。<mapper>元素的namespace属性定义的MyBatisUserDao代码实现如下:
package com.martin.config.chapter5.dao;
import com.martin.config.chapter5.pojo.User;
import org.springframework.stereotype.Repository;
/**
* @author: martin
* @date: 2019/11/3 12:00
* @description:
*/
@Mapper
public interface UserMapper {
User getUser(Long id);
}
该接口中的方法getUser和映射文件中定义的查询SQL的id是保持一致的,参数也是如此,这样就能够定义一个查询方法了。最后,需要对映射文件、POJO的别名和typeHandler进行配置,配置文件application.properties中加入如下代码:
#MyBatis映射文件统配
mybatis.mapper-locations=classpath:mapper/*.xml
#MyBatis扫描别名包(注解@Alias)
mybatis.type-aliases-package=com.martin.config.chapter5.pojo
#配置typeHandler的扫描包
mybatis.type-handlers-package=com.martin.config.chapter5.typehandler
#日志级别配置
logging.level.root=DEBUG
logging.level.org.springframework=DEBUG
logging.level.org.mybatis=DEBUG
这里我们配置了我们的映射文件、别名文件和typeHandler,这样就可以让MyBatis扫描它们了。日志级别设置为DEBUG级别,是为了更好的观察测试结果。其他的都不需要进行配置,因为mybatis-spring-boot-starter对MyBatis启动做了默认的配置。配置完成MyBatis以后,接下来我们开始讨论在Spring Boot中如何整合它。
2.Spring Boot整合MyBatis
MyBatis提供了注解@MapperScan,能够将MyBatis所需的对应接口扫描装配到Spring IOC容器中。代码如下:
package com.martin.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Repository;
/**
* 配置启动类
*
* @author martin
* @create 2019-01-03 下午 11:20
**/
@SpringBootApplication
@MapperScan(
//指定扫描包
basePackages = "com.martin.config.chapter5.*",
//指定SqlSessionFactory,sqlSessionTemplate被指定,则作废
sqlSessionFactoryRef = "sqlSessionFactory",
//指定sqlSessionTemplate,将忽略sqlSessionFactory的配置
sqlSessionTemplateRef = "sqlSessionTemplate",
//指定扫描的注解Mapper
annotationClass = Mapper.class
)
public class SpringBootConfigApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootConfigApplication.class, args);
}
}
@MapperScan允许我们通过扫描加载MyBatis的Mapper,如果Spring Boot中不存在多个SqlSessionFactory或者SqlSessionTemplate,那么完全可以不配置sqlSessionFactoryRef 和sqlSessionTemplateRef 。但是如果是存在多个时,就需要我们制定了,另外需要注意的是sqlSessionTemplateRef的优先权大于sqlSessionFactoryRef。最后,我们选择使用注解@Mapper作为限定,这是一个Spring对持久层的注解。
至此,一个Spring Boot整合MyBatis的程序就完成了,启动应用程序,在浏览器中输入:
可以看到下图的效果: