【DB系列】Mybatis系列教程之CURD基本使用姿势

文章目录
  1. I. 基础环境搭建
    1. 1. SpringBoot项目配置
    2. 2. 数据库准备
  2. II. MyBatis CURD
    1. 1. 基本对象
    2. 2. 数据插入
      1. 2.1 解析说明
      2. 2.2 批量插入
    3. 3. 数据查询
    4. 4. 数据更新
    5. 5. 数据删除
    6. 6. 使用演示
    7. 7. 小结
  3. III. 不能错过的源码和相关知识点
    1. 0. 项目
    2. 1. 微信公众号: 一灰灰Blog

mybatis作为数据的ORM框架,在国内的应用市场还是非常可观的,当初刚开始工作时使用spring + mybatis进行开发,后来也使用过hibernate, jdbctemplate, jooq,mybatisplus等其他的一些框架,

就个人使用感触来讲jooq的使用姿势和写sql差不多,基本上可以会写sql的无需额外的培训,立马可以上手;

hibernate最大的特点就是借助方法名来映射sql语句,非常有特点,但是当查询条件复杂一些的话,对小白而言就没有那么友好了;

而jdbctemplate,这个在小项目,轻量的db操作中,用起来还是很爽的,非常灵活,但是也有一些点需要特别注意,比如queryForObject,查不到数据时抛异常而不是返回null;

至于mybatis以及衍生的mybatis-plus,也就是接下来的主角了,它的特点如何,为什么受到国内大量开发者的追捧,将它作为db操作的第一ORM框架,让我们看完之后再说

I. 基础环境搭建

接下来的Mybatis的项目演示,主要是在SpringBoot的环境下运行,底层的数据库采用MySql,对应的版本信息如下

  • springboot: 2.2.0.RELEASE
  • mysql: 5.7.22

1. SpringBoot项目配置

关于SpringBoot的项目创建过程省略,下面是核心的pom依赖

1
2
3
4
5
6
7
8
9
10
11
<dependencies>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>

核心的依赖mybatis-spring-boot-starter,至于版本选择,到mvn仓库中,找最新的

另外一个不可获取的就是db配置信息,appliaction.yml

1
2
3
4
5
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/story?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password:

2. 数据库准备

在本地数据库中,新增了一个表如下

1
2
3
4
5
6
7
8
9
10
CREATE TABLE `money` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
`money` int(26) NOT NULL DEFAULT '0' COMMENT '钱',
`is_deleted` tinyint(1) NOT NULL DEFAULT '0',
`create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=551 DEFAULT CHARSET=utf8mb4;

接下来本文涉及到的CURD都是针对这张表来说的

II. MyBatis CURD

接下来我们将从0到1,实现基于mybatis进行mysql操作的全流程

1. 基本对象

经常使用Mybatis的小伙伴可能知道,操作一个db,通常会伴随几个不可或缺的东西

  • 数据库实体类:可以理解为数据库表锁映射到的Java Bean对象
  • Mapper接口:interface类,其中定义db的操作方法
  • xml文件:与上面接口对应,xml文件中写实际的sql

mybatis推荐的玩法是借助xml来写sql,但是官方也提供了注解的方式,因此xml文件并不是必须的;后面会介绍注解的操作方式;本文将主要是传统的xml配套使用姿势

针对上面这张表,第一步定义实体类MoneyPo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Data
@NoArgsConstructor
@AllArgsConstructor
public class MoneyPo {
private Integer id;

private String name;

private Long money;

private Integer isDeleted;

private Timestamp createAt;

private Timestamp updateAt;
}
  • 上面的三个注解属于lombok的知识点,有不清楚的小伙伴可以搜索一下

接下来是Mapper接口, MoneyMapper如下

1
2
3
4
// 注意这个@Mapper注解,用于表明这个接口属于Mybatis的Mapper对象
@Mapper
public interface MoneyMapper {
}

然后是Mapper接口对应的xml文件MoneyMapper.xml

注意xml文件放在资源文件resources下面,且xml文件的目录结构,与上面的Mapper接口的包路径保持完全一致 (why? 参看博文 【DB系列】SpringBoot系列Mybatis之Mapper接口与Sql绑定几种姿势)

1
2
3
4
<?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.git.hui.boot.mybatis.mapper.MoneyMapper">
</mapper>

2. 数据插入

前面的三步骤,将我们需要的实体类,接口对象,xml文件都初始化完毕,接下来就是进入我们的CURD环节,实现数据库的增删改查,这里主要使用insert标签

比如我们现在希望插入一条数据,首先需要做的就是在Mapper接口中定义一个方法

1
int savePo(@Param("po") MoneyPo po);

接着就是在xml文件中对应的sql

1
2
3
4
5
6
<insert id="savePo" parameterType="com.git.hui.boot.mybatis.entity.MoneyPo" useGeneratedKeys="true"
keyProperty="po.id">
INSERT INTO `money` (`name`, `money`, `is_deleted`)
VALUES
(#{po.name}, #{po.money}, #{po.isDeleted});
</insert>

2.1 解析说明

注意上面的xml文件

  • parameterType: 用于指定传参类型
  • useGenerateKeys + keyProperty: 表明需要将插入db的主键id,会写到这个实体类的id字段上
  • sql语句传参:形如#{},大括号里面填写变量名,上面用的是po.name,po为接口定义中的参数名,这个就表示使用po对象的name成员,作为db的name字段

接下来就是重要知识点:

  • 传参除了使用 #{}之外,还可以使用 ${},区别在于前面为参数参数占位,后面为字符串替换,因此存在sql注入的风险

举例说明

1
2
select * from money where id=${id}
select * from money where id=#{id}

针对上面这两个sql,当id = 1 or 1=1,对应的两个sql变成

1
2
3
4
-- 第一个sql会返回所有的数据
select * from money where id = 1 or 1 =1
-- 下面这个会抛sql异常
select * from money where id = '1 or 1=1'

2.2 批量插入

除了上面的单挑插入,批量插入也是ok的,和前面的使用姿势差不多

1
int batchSave(@Param("list") List<MoneyPo> list);

对应的sql如下

1
2
3
4
5
6
7
<insert id="batchSave" parameterType="com.git.hui.boot.mybatis.entity.MoneyPo"  useGeneratedKeys="true" keyProperty="id">
insert ignore into `money` (`name`, `money`, `is_deleted`)
values
<foreach collection="list" item="item" index="index" separator=",">
(#{item.name}, #{item.money}, #{item.isDeleted})
</foreach>
</insert>

对于foreach标签的说明,会放在后面的博文中专门进行介绍,这里简单理解为遍历即可

3. 数据查询

查询可以说是我们日常开发中最常见的情况了,这里先给出简单的查询demo,至于更复杂的查询条件(如联表,子查询,条件查询等)在后面的博文中进行介绍

如根据主键进行查询,主要借助select标签来实现

1
MoneyPo findById(int id);

对应的sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  <resultMap id="BaseResultMap" type="com.git.hui.boot.mybatis.entity.MoneyPo">
<id column="id" property="id" jdbcType="INTEGER"/>
<result column="name" property="name" jdbcType="VARCHAR"/>
<result column="money" property="money" jdbcType="INTEGER"/>
<result column="is_deleted" property="isDeleted" jdbcType="TINYINT"/>
<result column="create_at" property="createAt" jdbcType="TIMESTAMP"/>
<result column="update_at" property="updateAt" jdbcType="TIMESTAMP"/>
</resultMap>
<sql id="money_po">
id, name, money, is_deleted, create_at, update_at
</sql>

<select id="findById" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select
<include refid="money_po"/>
from money where id=#{id}
</select>

重点关注下上面的实现,select语句内容比较简单,但是有几个需要注意的点

  • sql标签:内部定义需要查询的db字段,最大的特点是供后面的查询语句,通过include来引入,从而实现代码片段的复用
  • resullMap标签:从db字段与MoneyPo实体类对比,我们可以知道部分字段名不是完全一样,如db中使用下划线,java中使用驼峰,那么db字段与java 成员变量如何映射呢?这里使用result标签来指定两者的映射关系,以及类型

(上面这个相信会始终伴随各位小伙伴的开发生涯)

4. 数据更新

更新主要借助update标签,相比较上面的两个,它的知识点就比较少了

1
int addMoney(@Param("id") int id, @Param("money") int money);

对应的sql如下

1
2
3
<update id="addMoney" parameterType="java.util.Map">
update money set money=money+#{money} where id=#{id}
</update>

说明

  • 上面标签中的parameterType,在这里实际上是可以省略的
  • @Param注解:主要用于指定参数名,在xml中可以使用内部定义的名字来作为参数变量;如果不加上这个注解,在xml中,参数变量则使用param0, param1来替代

5. 数据删除

删除使用delete标签

1
int delPo(@Param("id") int id);

对应的sql如下

1
2
3
<delete id="delPo" parameterType="java.lang.Integer">
delete from money where id = #{id,jdbcType=INTEGER}
</delete>

6. 使用演示

上面的mapper接口中定义了完整的CURD,接下来就是使用这个Mapper接口来实现交互了,在Spring中,使用姿势就非常简单了,直接当一个Spring Bean对象注入到service类中即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Repository
public class MoneyRepository {
@Autowired
private MoneyMapper moneyMapper;

public void testBasic() {
MoneyPo po = new MoneyPo();
po.setName("mybatis user");
po.setMoney((long) random.nextInt(12343));
po.setIsDeleted(0);

moneyMapper.savePo(po);
System.out.println(po);
MoneyPo out = moneyMapper.findById(po.getId());
System.out.println("query:" + out);
moneyMapper.addMoney(po.getId(), 100);
System.out.println("after update:" + moneyMapper.findById(po.getId()));
moneyMapper.delPo(po.getId());
System.out.println("after del:" + moneyMapper.findById(po.getId()));
}
}

执行输出结果如下

1
2
3
4
MoneyPo(id=552, name=mybatis user, money=7719, isDeleted=0, createAt=null, updateAt=null)
query:MoneyPo(id=552, name=mybatis user, money=7719, isDeleted=0, createAt=2021-08-01 11:47:23.0, updateAt=2021-08-01 11:47:23.0)
after update:MoneyPo(id=552, name=mybatis user, money=7819, isDeleted=0, createAt=2021-08-01 11:47:23.0, updateAt=2021-08-01 11:47:23.0)
after del:null

7. 小结

相信各位小伙伴看到这里,搭建一个mybatis实现数据库的CURD的项目应该是问题不大了,本文的主要知识点如下

  • mybatis项目的三套件:实体类 + mapper接口 + xml文件
  • 数据库的增删改查

其中有一些知识点比较重要,本文只是抛出来了,有兴趣的小伙伴可以持续关注后续更新

下面这些知识点,后面会进行更详细的说明

  • 如何获取插入数据的主键id
  • 批量场景下的foreach标签使用
  • 数据库表结构与java 实体类的映射 resultMap标签
  • Mapper接口与xml文件的关联方式
  • Mapper接口如何被扫描到,并被Spring bean对象
  • Mapper接口与xml的传参方式 @Param注解
  • sql参数替换的两种写法 ${}, #{}
  • 传参类型,返回值类型定义
  • 代码复用片段sql标签

III. 不能错过的源码和相关知识点

0. 项目

1. 微信公众号: 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

一灰灰blog


打赏 如果觉得我的文章对您有帮助,请随意打赏。
分享到