Spring Boot整合Mybatis
SpringBoot整合MyBatis框架
MyBatis比JPA和Hibernate更为简单易用,也更加灵活。在以系统管理为主的时代,Hibernate的模型化有助于系统的分系和建模,重点在于业务模型的分系和设计,术语表和业务模型分系的阶段。而现今已经是移动互联网的时代,互联网的特点是面对公众,相对而言业务比较简单,但是往往网站会拥有大量的用户,面对的问题主要是大数据、高并发和性能问题。因此在这个时代,互联网企业开发的难度主要集中在大数据和性能问题上,所以互联网企业更加关注的是性能和灵活性。
简介
MyBatis官方定义:MyBatis是定制化SQL,存储过程以及高级映射的优秀的持久化层框架。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。MyBatis可以对配置和原生Map使用简单的XML或注解,将接口和JAVA的POJO(Plain Old Java Object,普通JAVA对象)映射成数据库中的记录。
可以看出MyBatis是基于一种sql到pojo的模型,它需要我们提供SQL、映射关系(XML或者注解,目前以XML为主)和pojo。但是对于sql和pojo的ing折关系,它提供了自动映射和驼峰映射等,使开发者的开发工作大大减少。
Maven依赖
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
MyBatis的配置MyBatis的配置文件包括两部分
- 基础配置文件
- 映射文件
MyBatis是一个基于SqlSessionFactory构建的框架。对于SqlSessionFactory
而言,它的作用是生成SqlSession
接口对象,这个接口对象是MyBatis操作的核心。
构建SqlSessionFactory是通过配置类(Configuration)来完成的,对于mybatis-spring-boot-starter,它会给与我们在配置文件(application.properties)进行Configuration配置相关内容。
-
properties(属性):属性文件在实际应用中一般采用spring进行配置,而不是mybatis,这里不介绍。
-
settings(设置):它的配置将改变mybatis的底层行为,可以配置映射规则,如指定映射和驼峰映射,执行器(executor)类型,缓存等内容,比较复杂,具体可以参考mybatis官方网站
-
typeAliases(类型别名):因为使用类全限定名会比较长,所以mybatis会对常用的类提供默认的别名,此外还允许我们通过typeAliases配置自定义别名
-
typeHandlers(类型处理器):这是mybatis的重要配置之一,在mybatis写入和读取数据库的过程中对于不同类型的数据(对于java是JavaType,对于数据库则是JdbcType)进行自定义转换,在大部分的情况下我们不需要使用自定义的typeHandler,因为在mybatis自身就已经定义了比较多的typehandler,mybatis会自动识别javaType和jdbcType,从而实现各种类型的转换。一般来说,typeHandler主要使用集中在枚举类型上。
-
objectFactory(对象工厂):这是一个在mybatis生成返回pojo时会调用的工厂类型。一般我们使用mybatis默认提供的对象工厂类型(DafaultObjectFactory)就可以了。
-
plugins(插件):有时候也成为拦截器,是mybatis最强大也是最危险的组件,它通过动态代理和责任链模式来完成,可以修改mybatis底层的实现功能。
-
environments(数据库环境):可以配置数据库连接内容和事务,一般而言,这些交由spring托管。
-
mappers(映射器):是mybatis最核心的组件,它提供sql和pojo映射关系,这是mybatis开发的核心。
定义POJO对象
现在我们定义一个POJO
Person
package com.lay.pojo;
// MyBatis指定别名
@Alias(value = "person")
public class Person {
private Long id = null;
private String personName = null;
//性别枚举,这里需要使用typeHandler进行转换
private SexEnum sex = null;//枚举
private String note = null;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return personName;
}
public void setUserName(String personName) {
this.personName = personName;
}
public SexEnum getSex() {
return sex;
}
public void setSex(SexEnum sex) {
this.sex = sex;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
这里通过注解@Alias(value = "person")
指定了对象的别名为user
,同时,person有个性别属性类型为枚举。
package com.lay.enumeration;
public enum SexEnum {
MALE(1, "男"), FEMALE(2, "女");
private int id;
private String name;
SexEnum(int id, String name) {
this.id = id;
this.name = name;
}
public static SexEnum getEnumById(int id) {
for (SexEnum sex : SexEnum.values()) {
if (sex.getId() == id) {
return sex;
}
}
return null;
}
public static SexEnum getEnumByName(String name) {
for (SexEnum sex : SexEnum.values()) {
if (sex.getName().equals(name)) {
return sex;
}
}
return null;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在mybatis里,枚举是可以通过typeHandler
进行转换的。
TypeHandler转换类
BaseTypeHandler<T>
抽象类实现了TypeHandler<T>
接口。
这里我们对性别这个枚举类通过继承BaseTypeHandler<T>
类进行转换。
SexTypeHandler
package com.lay.typehandler;
//声明JdbcType为整形
@MappedJdbcTypes(JdbcType.INTEGER)
//声明JavaType为枚举SexEnum
@MappedTypes(value = SexEnum.class)
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
//通过列名读取性别
@Override
public SexEnum getNullableResult(ResultSet rs, String col) throws SQLException {
int sex = rs.getInt(col);
if (sex != 1 && sex != 2) {
return null;
}
return SexEnum.getEnumById(sex);
}
//通过下标读取性别
@Override
public SexEnum getNullableResult(ResultSet rs, int idx) throws SQLException {
int sex = rs.getInt(idx);
if (sex != 1 && sex != 2) {
return null;
}
return SexEnum.getEnumById(sex);
}
//通过存储存储过程读取性别
@Override
public SexEnum getNullableResult(CallableStatement rs, int idx) throws SQLException {
int sex = rs.getInt(idx);
if (sex != 1 && sex != 2) {
return null;
}
return SexEnum.getEnumById(sex);
}
//设置非空性别参数
@Override
public void setNonNullParameter(PreparedStatement ps, int idx, SexEnum sex, JdbcType jdbcType) throws SQLException {
ps.setInt(idx, sex.getId());
}
}
映射文件(xml)
为了使POJO能够与数据库的数据对应,还需要一个映射文件。
personMapper.xml
<?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.lay.dao.MyBatisPersonDao">
<select id="getPerson" parameterType="long" resultType="person">
select id,person_name as personName,sex,note from t_person where id=#{id}
</select>
</mapper>
这里personMapper.xml
的目录结构是resources/mapper/personMapper.xml
- namespcae:指定一个接口(DAO)
- select:代表是一个查询语,id属性指这条sql,映射dao接口中的方法,parameterType代表参数类型,resultType代表返回类型,这里用到了pojo对象的别名。
- 这里我们注意到 数据库person_name用了别名对应pojo属性personName保持一致性。在默认的情况下,我们可以不写,mybatis会默认按照驼峰命名规则映射。或者我们也可以自己配置。
定义mybatis操作接口(DAO)
MyBatisPersonDao
package com.lay.dao;
@Mapper
public interface MyBatisPersonDao {
public Person getPerson(Long id);
}
注意这仅仅是一个接口,不需要任何实现类。通过配置扫描mybatis会自动装配进IoC容器实现依赖注入。
配置文件application.properties
application.properties
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot_database
spring.datasource.username=root
spring.datasource.password=123456
# spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#指定数据连接池的类型
spring.datasource.type=org.apache.commons.dbcp2.BasicDataSource
#最大等待连接中的数量,设置0为没有限
spring.datasource.dbcp2.max-idle=10
#最大连接活动数
spring.datasource.dbcp2.max-total=50
#最大等待毫秒数,单位ms,超过时间会出错误信息
spring.datasource.dbcp2.max-wait-millis=10000
#数据库连接池初始化连接数
spring.datasource.dbcp2.initial-size=5
# mybatis映射文件
mybatis.mapper-locations=classpath:mapper/*.xml
# mybatis扫描别名包,和注解@Alias联用
mybatis.type-aliases-package: com.lay.pojo
# 配置typehandler类型转换的扫描包
mybatis.type-handlers-package=com.lay.typehandler
#驼峰命名转换
mybatis.configuration.mapUnderscoreToCamelCase=true
#打印日志
logging.level.com.lay.dao:trace
扫描装配@MapperScan
SpringbootDatabaseApplication
package com.lay;
@SpringBootApplication
@MapperScan(basePackages = "com.lay.dao", annotationClass = Mapper.class)
public class SpringbootDatabaseApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootDatabaseApplication.class, args);
}
}
通过@MapperScan
指定扫描包basePackages = "com.lay.dao"
,会自动装配到IoC容器中。annotationClass = Mapper.class
限定被@Mapper
标注的类。
测试
首先定义一个服务接口
MyBatisPersonService
package com.lay.service;
public interface MyBatisPersonService {
public Person getPerson(Long id);
}
实现类MyBatisPersonServiceImpl
package com.lay.service.impl;
@Service
public class MyBatisPersonServiceImpl implements MyBatisPersonService {
@Autowired
MyBatisPersonDao myBatisPersonDao;
@Override
public Person getPerson(Long id) {
return myBatisPersonDao.getPerson(id);
}
}
访问控制器MybatisController
package com.lay.controller;
@Controller
@RequestMapping(value = "mybatis")
public class MybatisController {
@Autowired
MyBatisPersonService myBatisPersonService;
@RequestMapping(value = "getPerson")
@ResponseBody
public Person getPerson(@RequestParam("id") Long id) {
return myBatisPersonService.getPerson(id);
}
}
然后通过浏览器地址栏输入http://localhost:8080/mybatis/getPerson?id=1进行测试
其他装配方式
- MapperFactoryBean手动
@Configuration
public class MybatisConfig(){
//这里的SqlSessionFactory是spring boot自动为我们生成的。
@Autowired
SqlSessionFactory sqlSessionFactory=null;
@Bean
public MapperFactoryBean<MyBatisPersonDao> initMyBatisUserDao(){
MapperFactoryBean<MyBatisPersonDao> bean=new MapperFactoryBean<>();
bean.setMapperInterface(MyBatisPersonDao.class);
bean.setSqlSessionFactory(sqlSessionFactory);
return bean;
}
}
- 使用MapperScannerConfigurer扫描装配Mybatis接口
@Bean
public MapperScannerConfigurer mapperScannerConfig(){
//定义扫描器实例
MapperScannerConfigurer mapperScannerConfigurer=new MapperScannerConfigurer();
//加载SqlSessionFactory,spring boot会自动生产SqlSessionFactory实例
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
//定义扫描的包
mapperScannerConfigurer.setBasePackage("com.lay.dao");
//限定被标注@Mapper的接口才被扫描
mapperScannerConfigurer.setAnnotationClass(Mapper.class);
return mapperScannerConfigurer;
}
推荐阅读
-
SpringBoot 源码解析 (三)----- Spring Boot 精髓:启动时初始化数据
-
idea创建一个入门Spring Boot项目(controller层)使用Moven代码管理
-
Spring Boot引入依赖包Druid
-
Spring Boot 开发个人博客--后台登录
-
将spring boot部署到tomcat上
-
SpringBoot整合MyBatis获得插入数据后获取主键,返回值总是1
-
Spring整合Quartz实现一个简单的定时任务
-
Spring Boot面试题(2020最新版)
-
解决spring boot1.5以上版本@ConfigurationProperties提示“Spring Boot Configuration Annotation Processor not.."
-
什么是Spring Boot