Spring Boot(五):春眠不觉晓,Mybatis知多少


在JavaWeb项目开发中,我们使用最多的ORM框架可能就是Mybatis了,那么对于常用的mybatis,你究竟了解多少呢?

Mybatis是什么


MyBatis 是支持定制化 SQL存储过程以及高级映射的优秀的持久层框架MyBatis 避免了几乎所有的 JDBC 代码,手动设置参数以及获取结果集


MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录


Mybatis如何操作数据库


支持三种操作方式


1)注解


2)语句构建器


3)xml文件与接口映射方式


Mybatis的缓存机制


缓存的重要性是不言而喻的。考虑到性能,几乎所有与性能相关工具都会涉及到使用缓存, 我们可以避免频繁的与数据库进行交互, 尤其是在查询越多、缓存命中率越高的情况下, 使用缓存对性能的提高更明显。这个不在本篇细讲,到时候会专门作为一期内容呈现

Mybatis的执行流程


Spring Boot(五):春眠不觉晓,Mybatis知多少


1) 加载配置 配置来源于两个地方,一处是配置文件,一处是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中


2) SQL解析 当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数
3) SQL执行 将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果
4) 结果映射

将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回

执行流程-源码分析


mybatis的对数据库的底层操作,如Spring JDBC一样,实际上也是对JDBC的一个封装,它的底层原理依旧是JDBC。所以依然遵从JDBC的6个步骤


  • a 加载数据库驱动
  • b 建立链接
  • c 创建statement
  • d 执行SQL语句
  • e 处理结果集
  • f 关闭数据库


通过跟踪使用xml方式的查询方法源码,我们一路走下来是这样的:


1)建立连接


Spring Boot(五):春眠不觉晓,Mybatis知多少


2)获取xml文件与接口中的对应方法


Spring Boot(五):春眠不觉晓,Mybatis知多少


3)创建statement,并执行sql语句,返回结果集


Spring Boot(五):春眠不觉晓,Mybatis知多少


Spring Boot(五):春眠不觉晓,Mybatis知多少


4)在这几步结束之后,会关闭statement


5)关闭连接


Spring Boot(五):春眠不觉晓,Mybatis知多少


其中,我们需要知道的是,Spring会根据我们引入的数据库类型,预先加载数据库的驱动。因此Mybatis执行数据库的流程,实际上就是JDBC的6大步骤。


得力助手


针对Mybatis的一些较为繁琐的方面,也分别有几个好用的工具


  • mybatis-代码生成器
  • 分页插件
  • mybatis-plus


使用它们,可以大大提高Mybatis的开发效率,感兴趣可以了解一下。
嗯,怎么说呢,它们的好,谁用谁知道呢~


Spring Boot(五):春眠不觉晓,Mybatis知多少


实战环节


对原理有个大概的了解,接下来,就进入今天的实战环节啦~
本次实战依旧演示操作mysql数据库-完成Spring Boot 使用Mybatis操作数据库的例子。

引入依赖


只需要引入mybtis依赖和mysql驱动两个主要依赖


<code><dependency>
<groupid>org.mybatis.spring.boot/<groupid>
<artifactid>mybatis-spring-boot-starter/<artifactid>
<version>2.1.2/<version>
/<dependency>
<dependency>
<groupid>mysql/<groupid>
<artifactid>mysql-connector-java/<artifactid>
<scope>runtime/<scope>
/<dependency>/<code>


属性配置


分别进行数据库连接信息以及mybatis的相关信息配置


以下分别为大家演示了表字段与实体类属性的映射支持下划线对应驼峰的方式机制、指定mapper.xml文件位置、以及配置日志输出这3个常用的配置项

<code>#1、数据库连接信息配置
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
#2、开启下划线的表字段映射为驼峰格式的实体类属性
#mybatis.configuration.map-underscore-to-camel-case=true
#3、用于指定xml文件的位置(使用xml执行sql语句的方式时)
mybatis.mapper-locations=classpath:mapper/*.xml
#4、打印sql语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl/<code>


创建实体类


使用之前文章中提到过的一个好用的开发工具lombok(如果想要了解用法,可以参考文章

SpringBoot(二):第一个Spring Boot项目),我们建立好的实体类User如下:

<code>
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private long id;
private String name;
private int age;
private Date createTime;
private Date updateTime;
}/<code>


创建接口


针对在第一节中提到的三种操作方法,我们分别进行讲解


1)注解


mybatis提供了很多操作注解,如下


Spring Boot(五):春眠不觉晓,Mybatis知多少


mybatis的注解方式,是使用这些操作注解,将sql语句写入这些注解中,进行数据库的操作的(其中结尾为Provider的注解,用于语句构建器方式)


我们只需要在接口上添加@Mapper注解,然后直接使用这些注解进行方法的定义


Spring Boot(五):春眠不觉晓,Mybatis知多少


我们分别定义了数据库的新增和根据id查找记录这两个方法


2)语句构建器


a 创建UserBuilder


实现接口ProviderMethodResolver


<code>public class UserBuilder  implements ProviderMethodResolver {
public String deleteUserSql() {
return new SQL() {{
DELETE_FROM("user");
WHERE("ID = ${id}");
}}.toString();
}


public static String selectUserById() {
return new SQL()
.SELECT("name,age,create_time,update_time")
.FROM("user")
.WHERE("id = #{id}")
.toString();
}
}/<code>


b 创建接口


定义方法时,采用对应的Provider注解的方式,指定类型type为我们的语句构建类,然后定义与语句构建类中的方法名一致的方法


<code>/**
* 使用语句构造器方式定义数据库操作接口
*/
@Mapper
public interface UserMapperWithBuilder {
@SelectProvider(type = UserBuilder.class)
User selectUserById(long id);
}/<code>


3)xml方式


xml方式,使我们经常使用的方式,因为它对于项目开发来说,还是比较灵活的。


a 建立与接口映射的xml文件UserMapper.xml


Spring Boot(五):春眠不觉晓,Mybatis知多少


b 建立相应的映射接口


<code>@SpringBootApplication 

@Slf4j
@MapperScan("com.shumile.springbootmybatis.mapper")
//@EnableTransactionManagement
public class SpringBootMybatisApplication implementsApplicationRunner {
@Autowired
private UserMapperWithAnnotation userMapperWithAnnotation;
@Autowired
private UserMapperWithXml userMapperWithXml;
@Autowired
private UserMapperWithBuilder userMapperWithBuilder;
public static void main(String[] args) {
SpringApplication. run(SpringBootMybatisApplication.class, args);
}
@Override
@Transactional
public void run(ApplicationArguments args) throws Exception {
//testByMapper();
testByXml();
//testBuilder();
}
private void testBuilder(){
userMapperWithBuilder.selectUserById(18l);
}
private void testByXml() {
Map<string> map = new HashMap<>();
map.put("name","小米");
map.put("age",17);
List<user> userList = userMapperWithXml.getUserList(map);
userList.forEach(user->log.info("user:{}",user));
}
private void testByMapper() {
User c = User.builder().name("小米").age(17)
.createTime(new Date())
.updateTime(new Date()).build();
int count = userMapperWithAnnotation.save(c);
log.info("Save {} User: {}", count, c);
c = userMapperWithAnnotation.findById(c.getId());
log.info("Find User: {}", c);
}
}/<user>/<string>/<code>


温馨提示:需要注意以下几点,否则程序执行的时候会找不到

  • 这个文件的放置位置应该与配置文件中所配置的路径一致
  • mapper标签中的namespace属性要指定为对应的映射接口UserMapperWithXml
  • 各个方法的id要与接口中的法名保持一致,同时相应的输入输出参数保持一致


调用接口方法


1)在启动类上添加注解,用于扫描我们所定义的数据库操作接口

<code>@MapperScan("com.shumile.springbootmybatis.mapper")
/<code>


接着,分别通过方法testBuilder、testByMapper以及testByXml调用以上所定义的各个数据库方法


<code>@SpringBootApplication
@Slf4j
@MapperScan("com.shumile.springbootmybatis.mapper")
public class SpringBootMybatisApplication implementsApplicationRunner {
@Autowired

private UserMapperWithAnnotation userMapperWithAnnotation;
@Autowired
private UserMapperWithXml userMapperWithXml;
@Autowired
private UserMapperWithBuilder userMapperWithBuilder;
public static void main(String[] args) {
SpringApplication.
run(SpringBootMybatisApplication.class, args);
}

@Override
@Transactional
public void run(ApplicationArguments args) throws Exception {
//testByMapper();
testByXml();
//testBuilder();
}

private void testBuilder(){
userMapperWithBuilder.selectUserById(18l);
}


private void testByXml() {
Map<string> map = new HashMap<>();
map.put("name","小米");
map.put("age",17);
List<user> userList = userMapperWithXml.getUserList(map);
userList.forEach(user->log.info("user:{}",user));
}


private void testByMapper() {
User c = User.builder().name("小米").age(17)
.createTime(new Date())
.updateTime(new Date()).build();
int count = userMapperWithAnnotation.save(c);
log.info("Save {} User: {}", count, c);
c = userMapperWithAnnotation.findById(c.getId());
log.info("Find User: {}", c);
}
}/<user>/<string>/<code>

运行项目


运行项目,你就可以看到各个功能纷纷都实现啦,演示一下通过xml方式实现的日志打印效果


Spring Boot(五):春眠不觉晓,Mybatis知多少


我们可以看到,日志中不仅为我们打印出来了格式化以后的sql语句,还将输出了sqlSession的创建与关闭等信息。所以在平时采用配置文件中所配置的日志输出方式还是挺好用的呢。


当然还有一种专门用于数据库监控的p6Spy工具,也挺好用的,感兴趣的话,可以搜索一下用法哦~


如果跟着文章的思路一路走到这里的话,那么恭喜你,Mybatis的三种操作数据库的方式,你已经全部学会啦~


Spring Boot(五):春眠不觉晓,Mybatis知多少


总而言之


总体来说,使用语句构建器的方式操作数据库,采用具体的sql语句对应的方法来替换具体sql关键词,可以简化代码中直接书写的动态sql语句,并且还可以支持随意更换数据库,但总得来说,还是不够灵活


使用 XML 或注解的方式来配置 ORM,把 SQL 用标签管理起来,不关心,也不干涉实际 SQL 的书写。在这种思路下框架轻量,很容易集成,又因为我们可以使用 SQL 所有的特性,可以写存储过程,也可以写 SQL 方言(Dialect),所以灵活度相当高。


那么为什么我们更倾向于使用xml与接口映射的方式呢?
使用xml有以下两大优点:

  1. 可以把所有的sql写在xml文件中,要是有什么修改,甚至是换数据库的操作,我们只需要更换xml文件就行了
  2. 针对各种复杂的sql、以及sql可能实现起来比较麻烦的情况,我们也可以直接使用存储过程等多种方式来实现


虽然步骤相对比较麻烦,但是它最为灵活,也最为简洁,代码看起来更清爽,使用久了,也并不会觉得麻烦了。

Spring Boot(五):春眠不觉晓,Mybatis知多少


今天一起重新学习了Mybatis,总体来说,有以下几点:


1、Spring Boot集成Mybatis的加载流程

2、Mybatis操作数据库的三种方式


3、三种操作方式各自的特点


嗯,就这样。每天学习一点,时间会见证你的成长


下期预告:


Spring Boot(六):那些好用的连接池们


本期项目代码已上传到github~有需要的可以参考

<code>https://github.com/wangjie0919/Spring-Boot-Notes/<code>


往期精彩回顾


分享到:


相關文章: