01.文章初衷
写这篇博客的初衷有两个,第一点是因为做了三年多Java,从去年以来深感自己技术深度的不足,一番激烈的思想斗争后,决定开始重新自己的编程旅途。重新学习并记录自己所掌握的技术,一方面可以作为这次学习之旅的见证,另一方面则是可以用于日后职业选择时简历上的发光点。第二点则是源于我在优快云上查找资料时,很少看到契合初学者的内容,大多是更偏向于成熟程序员所写的技术文档风格,我的技术没那么好,实践过程中也会遭遇一些报错,我希望把我遇到的坑也写进去,以期可以对像我一样想要学习但不成熟的他人有所助益。
02.MyBatis简单介绍
专有名词:ORM
ORM(Object Relational Mapping),即对象关系映射,是用于关联对象与关系型数据库的技术。目前国际上比较流行的类似技术框架是JPA(Java Persistence API),而Mybatis则是国内比较受欢迎的。我自己更喜欢Mybatis Plus,但Mybatis受到很多企业的青睐,同时也是一些大厂自研产品的基底,如果可以把从JDBC到Mybatis的一整套底层概念搞通,我觉得是非常有意义的事情。
通过这类技术,我们可以做到在面向对象的Java业务代码中操作、关联数据库,也就是实现所谓的增删改查、分页以及批量操作等功能,同时我们还可以实现动态SQL之类的概念。
但本文更偏重如何在SpringBoot项目中使用Mybatis。
注:作者在学习Mybatis时经历了两种集成方式,即先配置文件,随后再以注解的方式简化。但本文中不考虑这些因素,也不是全面介绍Mybatis,而是致力于帮助初学者把Mybatis集成到Spring Boot项目中工作。
03.实践流程
03.01 搭建一个SpringBoot项目
不同人有不同的搭建习惯,我会按照自己的习惯搭建一个简单的SpringBoot项目。
我使用的IDEA版本为2021,大家可以去官网下载社区版
项目管理使用的是Maven,版本为3.6.1,JDK版本为1.8,数据库为MySQL,版本为5.7
点击左上角
File --> New --> Project
点击Next
左上角:我这里选择了2.X版本的SpringBoot
如果你的JDK版本和我一样也是1.8,请不要选择3.X版本的SpringBoot,只有JDK17才能支持
点击Finish,完成项目创建
等待依赖下载
完成后的效果如上
POM文件效果如下
启动类效果如下
配置文件初始状态
尝试启动项目,没问题,效果如下
03.02 搭建三层架构以及业务代码
这里文件夹的名称可以按照你的喜好或者企业的惯例来做
实体类的文件夹Model、Pojo、Entity按照不同的软件架构模式抑或习惯可以完全不同,知道是做什么的就可以了。而两个mapper文件夹也可以按照你的喜好去取名,两个文件夹的名称也不需要一致,因为后续我们会根据配置文件来锁定配置映射文件的位置。
常见的三层架构文件
此处增加的依赖有:
Controller代码
package com.example.tempproject.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.tempproject.model.BookModel;
import com.example.tempproject.service.BookService;
@RestController
public class BookController {
@Autowired
private BookService bookService;
@RequestMapping("/book/query/spi")
@ResponseBody
public BookModel queryBookById(String id) {
// 判空
Assert.hasText(id, "ID为空,无法查询书籍");
// 根据id查询
return bookService.queryBookById(id);
}
}
Service代码
package com.example.tempproject.service;
import com.example.tempproject.model.BookModel;
public interface BookService {
BookModel queryBookById(String id);
}
ServiceImpl代码
package com.example.tempproject.service.serviceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import com.example.tempproject.mapper.BookMapper;
import com.example.tempproject.model.BookModel;
import com.example.tempproject.service.BookService;
@Service
public class BookServiceImpl implements BookService {
private static Logger logger = LoggerFactory.getLogger(BookServiceImpl.class);
@Autowired
private BookMapper bookMapper;
@Override
public BookModel queryBookById(String id) {
// 从数据库查询
BookModel bookModel = bookMapper.selectById(id);
// 如果数据为空,日志记录
if (null == bookModel) {
logger.info("书籍不存在");
}
return bookModel;
}
}
Mapper.interface代码
package com.example.tempproject.mapper;
import org.apache.ibatis.annotations.Mapper;
import com.example.tempproject.model.BookModel;
@Mapper
public interface BookMapper {
BookModel selectById(String bookId);
}
BookModel代码
package com.example.tempproject.model;
import lombok.Data;
@Data
public class BookModel {
private String bookId;
private String bookType;
private String bookPrice;
private String bookAuthor;
public BookModel() {
}
public BookModel(String bookId, String bookType, String bookPrice, String bookAuthor) {
this.bookId = bookId;
this.bookType = bookType;
this.bookPrice = bookPrice;
this.bookAuthor = bookAuthor;
}
}
到这里就结束了所有业务代码的构建
其中BookMapper.interface文件,可以被理解为包含了所有SQL方法的接口
而BookMapper.xml文件则是包含了映射,也可能包含SQL
03.03 完成映射以及Mybatis的相关配置
BookMapper.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">
<!--
namespace后要填写BookMapper.interface所在的位置,代表了映射关系
-->
<mapper namespace="com.example.tempproject.mapper.BookMapper">
<!--
ResultMap代表了整个对象的映射具体代码
id是这组映射的唯一标识
type是返回类型
result则是具体字段的映射
column代表数据库字段名称
jdbcType代表了数据库字段数据类型(可以没有)
property则是类中字段的名称
-->
<resultMap id="BookResultMap" type="com.example.tempproject.model.BookModel">
<result column="book_id" jdbcType="VARCHAR" property="bookId"/>
<result column="book_type" jdbcType="VARCHAR" property="bookType"/>
<result column="book_price" jdbcType="DECIMAL" property="bookPrice"/>
<result column="book_author" jdbcType="VARCHAR" property="bookAuthor"/>
</resultMap>
<!--
SQL
id是SQL的唯一标识,要与BookMapper.interface中具体的方法名对应
resultMap后则要填写上方你要使用的ResultMap的id
-->
<select id="selectById" resultMap="BookResultMap">
select *
from book
where book_id = #{bookId}
</select>
</mapper>
Application.properties配置文件代码
#数据库配置
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/project_mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
#实体类配置
mybatis.type-aliases-package=com.yitong.model
#标注待解析的mapper的xml文件位置,第一个mapper对应resources中的文件夹名称
#*Mapper则是对应所有的Mapper文件
mybatis.mapper-locations=classpath:mapper/*Mapper.xml
在启动类上增加注解@MapperScan
package com.example.tempproject;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.tempproject.mapper")
public class TempProjectApplication {
public static void main(String[] args) {
SpringApplication.run(TempProjectApplication.class, args);
}
}
在数据库中准备好的数据如下
03.04 测试
尝试启动项目,启动成功
postman测试
测试效果如上
04. 小结
本篇文章仅仅完成了最基础的集成
第一步我们完成了SpringBoot项目的搭建
第二步我们添加了业务代码,在添加注解的过程中需要添加新的依赖
第三步我们需要完成两个配置文件的编写以及SQL的编写
其中在编写Application.properties配置文件时,指明了需要解析的映射配置的位置
而在映射文件中的namespace中,又映射了BookMapper.interface的位置
这也是为什么,虽然我们把两个文件都取名叫*Mapper,他们所在的文件夹也都叫Mapper,但其实没什么关系,我们没必要在意名字是否一致。我们需要理解的是
我们想要完成一段功能,靠的是配置文件,是代码本身
单纯凭借一些命名或者奇怪的操作不能完成这些
而值得注意的点则是
1.BookMapper.interface中的方法名要与BookMapper.xml中的SQL的id一致
2.SQL上的ResultMap要与上面的ResultMap的id一致
3.填写type时要注意写全
4.column代表数据库字段,而property代表的是类中的字段名
我每次看到一些教学博客,在写案例时,不用book_author而是采用bookauthor甚至name这种不能区分两者的字段名作为例子就觉得不可思议。因为这类实践教学科普文章博客的难度并不高,所以最需要的特质是详实和细致的例子。
05. 可能遇到的报错
1.ClassNotFound:在BookMapper.xml中,type后没有填写完整,导致在返回数据时,没有找到BookModel的bean
2.BookMapper.xml中的property或者column爆红:idea中的mybatis插件,如mybatisX或者mybatisProHelper都可能会造成这种问题,关闭插件即可
3.cannot resolve symbol “类名”:在BookMapper.xml中,type后没有填写完整
4.no typehandler found for property XXXX:column或者property没有填写正确
5.property 'sqlsessionfactory' or 'sqlsessiontemplate' are required:依赖选用错误,可能没有采用springboot的mybatis依赖
以上是一些可能遭遇的报错,和一些可能的解决方案
06. 其他
关于Mybatis可以聊的还有很多
比如1.更高级、复杂的映射情况
比如2.批量操作的编写
比如3.动态SQL的使用
比如4.注解的使用,以及一些简化操作
这些我会在第二期中谈到