SpringBoot教程(十一) | SpringBoot集成Mybatis

SpringBoot教程(十一) | SpringBoot集成Mybatis

上一篇文章我们介绍了SpringBoot集成JdbcTemplate.简单体验了一下JdbcTemplate框架的用法,今天的内容比较重要,我们来介绍一下SpringBoot集成Mybatis的步骤。

1、 Mybatis 介绍

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)。

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手工设置参数以及抽取结果集。MyBatis 使用简单的 XML 或注解来配置和映射基本体,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

Mybatis特点:

1、Mybatis实现了接口绑定,使用更加方便。

2、对象关系映射的改进,效率更高

3、MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。

优点:

1、简单易学

mybatis本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。

2、灵活

mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。

3、解除sql与程序代码的耦合

通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。

4、提供映射标签,支持对象与数据库的orm字段关系映射

5、提供对象关系映射标签,支持对象关系组建维护

6、提供xml标签,支持编写动态sql。

缺点:

1、编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。

2、SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。

3、框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

4、二级缓存机制不佳

上面的内容都是从网上拷贝的,因为我想大多数的人应该都用过mybatis,并且我们本文的侧重点主要是SpringBoot的集成方式,而不是从头介绍Mybatis,如果大家对Mybatis的使用不太了解,建议先去学习一下Mybatis的用法。

2、集成步骤

接下来我们开始进行集成。为了方便操作,由于我们上次刚刚集成过JdbcTemplate, 代码中共存多个DAO层框架可能会有问题,我们在原有项目基础上拉取一个新的分支来进行开发,分支名就叫 feature/mybaits。完成的代码都会托管到gitCode上,大家可在文末获取地址。

2.1 引入依赖

首先我们先引入Mybatis所需依赖,mybatis本身已经提供了用于适配springBoot的Starter, 同时我们还需要引入 mysql-connector. 在pom.xml中添加:

xml复制代码<!-- lombok -->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version><scope>provided</scope>
</dependency><!-- mybatis-spring-boot-starter -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.1</version>
</dependency><!-- MySQL连接 -->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope>
</dependency>

2.2 配置数据库连接

在spring的配置文件中,配置我们需要访问的数据库的连接信息,这个配置和前面jdbcTemplate的配置一样

yml复制代码spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springboot_learningusername: rootpassword: root

2.3 开发Mapper

在JdbcTemplate中我们访问数据库的这一层使用dao表示的。但是在mybatis中,我们一般都把这一层称之为mapper, 并且一般类名也用这个结尾,其实代表的都是一个意思,就是使用习惯的问题。在Mybatis中的Mapper也是分为接口和实现,比较特殊的是mapper的实现一般使用xml文件的形式来体现。我们的sql也都是写在xml文件中。

我们在项目中创建一个mapper的文件夹,用来存放所有的Mapper接口。我们在里边创建UserMapper用来处理user表的增删改查操作。

java复制代码@Mapper
public interface UserMapper {/*** 删除操作* @param id* @return*/int deleteByPrimaryKey(Integer id);/*** 插入操作* @param record* @return*/int insert(User record);/*** 插如操作* @param record* @return*/int insertSelective(User record);/*** 根据id查询操作* @param id* @return*/User selectByPrimaryKey(Integer id);/*** 更新操作* @param record* @return*/int updateByPrimaryKeySelective(User record);/*** 更新操作* @param record* @return*/int updateByPrimaryKey(User record);
}

然后在resources 资源目录下(application.yml同级目录下)创建一个mapper文件夹,用于存放xml格式的mapper实现。在里面写一个UserMapper.xml

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.lsqingfeng.springboot.mapper.UserMapper"><resultMap id="BaseResultMap" type="com.lsqingfeng.springboot.entity.User"><id column="id" jdbcType="INTEGER" property="id" /><result column="name" jdbcType="VARCHAR" property="name" /><result column="age" jdbcType="INTEGER" property="age" /><result column="address" jdbcType="VARCHAR" property="address" /><result column="create_time" jdbcType="TIMESTAMP" property="createTime" /><result column="update_time" jdbcType="TIMESTAMP" property="updateTime" /></resultMap><!--sql语句片段,将公共部分抽出--><sql id="Base_Column_List">id, name, age,address,create_time, update_time</sql><select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">select<include refid="Base_Column_List" />from t_userwhere id = #{id,jdbcType=INTEGER}</select><delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">delete from t_userwhere id = #{id,jdbcType=INTEGER}</delete><insert id="insert" parameterType="com.lsqingfeng.springboot.entity.User">insert into t_user ( name, age,address,create_time ,update_time)values (#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER},#{address},#{createTime,jdbcType=TIMESTAMP},#{updateTime,jdbcType=TIMESTAMP})</insert><!--动态sql--><insert id="insertSelective" parameterType="com.lsqingfeng.springboot.entity.User">insert into t_user<trim prefix="(" suffix=")" suffixOverrides=","><if test="id != null">id,</if><if test="name != null">name,</if><if test="age != null">age,</if><if test="address != null">address,</if><if test="createTime != null">create_time,</if><if test="updateTime != null">update_time,</if></trim><trim prefix="values (" suffix=")" suffixOverrides=","><if test="id != null">#{id,jdbcType=INTEGER},</if><if test="name != null">#{name,jdbcType=VARCHAR},</if><if test="age != null">#{age,jdbcType=INTEGER},</if><if test="address != null">#{address},</if><if test="updateTime != null">#{createTime,jdbcType=TIMESTAMP},</if><if test="updateTime != null">#{updateTime,jdbcType=TIMESTAMP},</if></trim></insert><update id="updateByPrimaryKeySelective" parameterType="com.lsqingfeng.springboot.entity.User">update t_user<set><if test="name != null">name = #{name,jdbcType=VARCHAR},</if><if test="age != null">age = #{age,jdbcType=INTEGER},</if><if test="address != null">address = #{address},</if><if test="createTime != null">create_time = #{createTime,jdbcType=TIMESTAMP},</if><if test="age != null">update_time = #{updateTime,jdbcType=TIMESTAMP}</if></set>where id = #{id,jdbcType=INTEGER}</update><update id="updateByPrimaryKey" parameterType="com.lsqingfeng.springboot.entity.User">update t_userset name = #{name,jdbcType=VARCHAR},age = #{age,jdbcType=INTEGER},address = #{address,jdbcType=VARCHAR},create_time = #{createTime,jdbcType=TIMESTAMP},update_time = #{updateTime,jdbcType=TIMESTAMP}where id = #{id,jdbcType=INTEGER}</update>
</mapper>

然后在Service层中引用mapper.

2.4 配置Mapper的路径

我们现在是把xml类型的文件都放在了resources下的mapper文件夹中了。但是这个路径对与我们的项目中的mybatis来说他是不知道的,所以我们需要告诉它这个路径的位置。怎么告诉呢,就是在application.yml中配置一下。

xml复制代码mybatis:mapper-locations: classpath:mapper/*.xml

mapper的位置位于 classpath下的mapper文件夹中的所有xml结尾的文件。

这里还有一个问题也提下。就是mapper的接口的位置我们并没有配置,他是怎么知道的呢,其实是我们在每个Mapper的接口上都加上了@Mapper的注解,所以他可以自动扫描到。如果要加这个注解,那么所有的Mapper接口上就都需要加,这其实是比较麻烦的。怎么办呢,我们可以都不加这个注解,然后在SpringBoot的启动类上,加上一个MapperScan注解,将mapper的包路径配置进去,就都不用加了。

我们去掉@Mapper注解,也不加任何配置会报错:

image.png

我们在主类上添加注解:

java复制代码@SpringBootApplication
@MapperScan("com.lsqingfeng.springboot.mapper")
public class SpringBootLearningApplication {public static void main(String[] args) {SpringApplication.run(SpringBootLearningApplication.class, args);}
}

再次启动:

image.png

成功了。

3、 接口测试

组装好项目后,我们来调用一下接口。继续使用之前的jdbc里写好的Controller进行测试。

image.png

调用成功后,观察数据库。

image.png

李四这条使我们刚刚插入进去的,只不过两个时间是空值,因为我们并没有给时间赋值。

再看看查询接口。

image.png

4、mybatis自动填充时间

上面的案例中,由于我们没有对时间进行设置,导致创建时间和修改时间都是空的。其实Mybatis中为我们提供了拦截器的机制,相当于可以对每次执行的sql进行拦截,这样我们就可以对对操作进行判断,如果是插入操作,就直接设置创建时间和修改时间为当前时间。如果是更新操作则设置更新时间为当前时间。

拦截器代码如下。

java复制代码import org.apache.ibatis.binding.MapperMethod.ParamMap;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.stereotype.Component;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;/*** Mybatis拦截器,用能与设置创建时间和更新时间*/
@Component
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class CreateTimeSetInterceptor implements Interceptor {private static final String CREATE_TIME_SETTER = "setCreateTime";private static final String UPDATE_TIME_SETTER = "setUpdateTime";@Overridepublic Object intercept(Invocation invocation) throws Throwable {MappedStatement ms = (MappedStatement) invocation.getArgs()[0];Object parameter = invocation.getArgs()[1];if (ms.getSqlCommandType() == SqlCommandType.INSERT) {setTimeIfNeccesary(parameter, CREATE_TIME_SETTER);setTimeIfNeccesary(parameter, UPDATE_TIME_SETTER);} else if (ms.getSqlCommandType() == SqlCommandType.UPDATE) {setTimeIfNeccesary(parameter, UPDATE_TIME_SETTER);}return invocation.getMethod().invoke(invocation.getTarget(), invocation.getArgs());}private void setTimeIfNeccesary(Object param, String methodName) {Class<?> cls = param.getClass();if (cls == ParamMap.class) {@SuppressWarnings("unchecked")ParamMap<Object> map = (ParamMap<Object>) param;map.entrySet().forEach(entry -> {if (!entry.getKey().equals("et")) {setIfSetterExist(entry.getValue(), methodName);}});} else {setIfSetterExist(param, methodName);}}private void setIfSetterExist(Object param, String methodName) {Class<?> cls = param.getClass();try {Method m = null;try {m = cls.getDeclaredMethod(methodName, new Class[] { Date.class });if (m != null) {m.setAccessible(true);m.invoke(param, new Date());}} catch (NoSuchMethodException e1) {m = cls.getDeclaredMethod(methodName, new Class[] { Timestamp.class });if (m != null) {m.setAccessible(true);m.invoke(param, new Timestamp(System.currentTimeMillis()));}}} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException| InvocationTargetException e) {e.printStackTrace();}}}

接下来我们再来执行一个插入操作》

image.png

再次观察数据库:

image.png

发现时间已经有值了。

5、 mybatis-generator 插件

我们上面通过User表创建了UserMapper接口和UserMapper的xml实现。其实这类文件中的内容是比较有规律的,所以如果每次没有都去自己写,是比较耗费时间的,所有mybatis为我们提供了mybatis-generator插件,通过这个插件,我们可以设置对应的数据库连接和表名,然后插件就会帮我们自动生成对应的实体,mapper接口和Mapper实现,里面的方法只有常用的增删改查操作。能够大大较少我们操作的工作量。 这个步骤,我们一般称之为 mybatis 逆向生成。 逆向生成的方法比较多,有兴趣的自己去找找吧,这里不想展开了,因为现在随着mybatisPlus的普及,使用mybatis-plus-generator的更多一些。

好了关于SpringBoot集成Mybatis我们就介绍这么多。欢迎大家一起交流,有问题随时留言。

另: 配套项目代码已托管中gitCode: gitcode.net/lsqingfeng/…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/410010.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#,入门教程(18)——分支语句(switch-case)的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(17)——条件语句&#xff08;if-else&#xff09;的基础知识https://blog.csdn.net/beijinghorn/article/details/124033376 1、switch概述 switch-case分支语句 可以理解为 大号 的 if-else。 switch语句以switch关键字开头&…

树莓派4B+ubuntu20.04+ros1桌面配置(一)

烧录系统至树莓派 下载系统&#xff1a; 方案一 https://ubuntu.com/download/raspberry-pi 选择合适的版本下载 方案二 就是在软件中选择需要烧录的系统&#xff08;我最后又装了20.04的ubuntu server系统&#xff0c;因为22的系统不能装ros1&#xff09; 方案三(采用…

vue中使用高德地图,根据类型显示不同点,点击出现弹框居中显示,并在可视化区域显示所有点

效果图 一、安装 vue-amap 插件 npm install vue-amap --save二、vue页面 <template> <div><ul styledisplay:flex;><liv-for"(item, index) in checkList":key"index"click"onClick(item)":class"item.checked ?…

Vue加载序列帧动图

解读方法 使用<img :src"currentFrame" alt"加载中" /> 加载图片动态更改src的值使用 requestAnimationFrame 定时更新在需要的页面调用封装的组件 <LoadToast v-if"showLoading" /> 封装组件 <template><div class"…

python flask学生管理系统

预览 前端 jquery css html bootstrap: 4.x 后端 python: 3.6.x flask: 2.0.x 数据库 mysql: 5.7 学生管理模块 登录、退出查看个人信息、修改个人信息成绩查询查看已选课程选课、取消选课搜索课程课程列表分页功能 教师模块 登录、退出查看个人信息、修改个人信息录入…

论文笔记:信息融合的门控多模态单元(GMU)

整理了GMU&#xff08;ICLR2017 GATED MULTIMODAL UNITS FOR INFORMATION FUSION&#xff09;论文的阅读笔记 背景模型实验 论文地址&#xff1a; GMU 背景 多模态指的是同一个现实世界的概念可以用不同的视图或数据类型来描述。比如维基百科有时会用音频的混合来描述一个名人…

数据结构04附录01:字符串大写转小写[C++]

图源&#xff1a;文心一言 上机题目练习整理~&#x1f95d;&#x1f95d; 本篇作为字符串的代码补充&#xff0c;提供了3种&#xff08;差别并不大&#xff09;解法以及函数的详细解释&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 前文&#xff1a;&#x1f338;…

WSL2 git clone命令无法克隆远程仓库

问题描述 最近在往WSL2里拉取git仓库的时候&#xff0c;突然出现了这个问题&#xff0c;WSL2无法连接到git服务器&#xff0c;导致代码无法拉取下来&#xff0c;可能是因为我最近不小心修改了windows的防火墙设置&#xff0c;导致出现了这个问题。 解决办法 在查阅了很多篇…

Angular系列教程之路由守卫

文章目录 前言路由守卫的类型CanLoadCanActivateCanActivateChildCanDeactivateResolve总结 前言 在Angular中&#xff0c;路由守卫是一个非常有用的功能&#xff0c;可以帮助我们控制用户在导航过程中的权限和访问限制。通过使用路由守卫&#xff0c;我们可以拦截导航并根据需…

2023年第十四届蓝桥杯软件赛省赛总评

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周。 在QQ群上交流答疑&am…

python爬虫小练习——爬取豆瓣电影top250

爬取豆瓣电影top250 需求分析 将爬取的数据导入到表格中&#xff0c;方便人为查看。 实现方法 三大功能 1&#xff0c;下载所有网页内容。 2&#xff0c;处理网页中的内容提取自己想要的数据 3&#xff0c;导入到表格中 分析网站结构需要提取的内容 代码 import requests…

探索Python数据结构与算法:解锁编程的无限可能

文章目录 一、引言1.1 数据结构与算法对于编程的重要性1.2 Python作为实现数据结构与算法的强大工具 二、列表和元组2.1 列表&#xff1a;创建列表、索引、切片和常用操作2.2 元组&#xff1a;不可变序列的特性和使用场景 三、字符串操作和正则表达式3.1 字符串的常见操作和方法…