目录
1.什么是 MyBatis
MyBatis
是一款优秀的持久层框架,它⽀持 自定义 SQL、存储过程 以及 高级映射 。MyBatis
去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis
可以通过简单的 XML 或 注解 来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
简单来说
MyBatis
是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库工具。
2.MyBatis 环境搭建
开始搭建 MyBatis 之前,MyBatis 在整个框架中的定位,框架交互流程图:
MyBatis 也是一个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在面向对象编程语⾔中,将关系型数据库中的数据与对象建立起映射关系,进而自动的完成数据与对象的互相转换:
- 将输入数据(即传入对象)+SQL 映射成原生 SQL
- 将结果集映射为返回对象,即输出对象
ORM 把数据库映射为对象:
- 数据库表(table)–> 类(class)
- 记录(record,行数据)–> 对象(object)
- 字段(field) --> 对象的属性(attribute)
一般的 ORM 框架,会将数据库模型的每张表都映射为一个 Java 类。 也就是说使用 MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和数据库表之间的转换。
2.1 创建数据库和表
-- 创建数据库dropdatabaseifexists mycnblog;createdatabase mycnblog DEFAULTCHARACTERSET utf8mb4;-- 使用数据数据use mycnblog;-- 创建表[用户表]droptableifexists userinfo;createtable userinfo(
id intprimarykeyauto_increment,
username varchar(100)notnull,
password varchar(32)notnull,
photo varchar(500)default'',
createtime datetimedefaultnow(),
updatetime datetimedefaultnow(),`state`intdefault1)defaultcharset'utf8mb4';-- 创建文章表droptableifexists articleinfo;createtable articleinfo(
id intprimarykeyauto_increment,
title varchar(100)notnull,
content textnotnull,
createtime datetimedefaultnow(),
updatetime datetimedefaultnow(),
uid intnotnull,
rcount intnotnulldefault1,`state`intdefault1)defaultcharset'utf8mb4';-- 创建视频表droptableifexists videoinfo;createtable videoinfo(
vid intprimarykey,`title`varchar(250),`url`varchar(1000),
createtime datetimedefaultnow(),
updatetime datetimedefaultnow(),
uid int)defaultcharset'utf8mb4';
2.2 添加 MyBatis 框架支持
① 在已有的项目中添加:
<!-- 添加 MyBatis 框架 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.4</version></dependency><!-- 添加 MySQL 驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency>
② 在创建新项目时添加:
2.3 配置数据库连接和MyBatis
在 application.yml 配置数据库连接:
# 配置数据库连接spring:datasource:url: jdbc:mysql://127.0.0.1/mycnblog?charsetEncoding=utf8
username: root
password:12345678driver-class-name: com.mysql.cj.jdbc.Driver
配置 MyBatis 中的 XML 路径:
# 设置Mybatis的xml保存路径mybatis:mapper-locations: classpath:mybatis/**Mapper.xml
2.4 添加代码
按照后端开发的工程思路来实现 MyBatis 查询所有用户的功能:
目录结构:
2.4.1 添加实体类
添加用户的实体类:
@Setter@Getter@ToStringpublicclassUserInfo{privateint id;privateString username;privateString password;privateString photo;privateString createtime;privateString updatetime;privateint state;}
2.4.2 添加 mapper 接口
数据持久层的接口定义:
@MapperpublicinterfaceUserMapper{publicList<UserInfo>getAll();}
2.4.3 添加 UserMapper.xml
数据持久层的实现,mybatis 的固定 xml 格式:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.demo.mapper.UserMapper"></mapper>
UserMapper.xml 查询所有用户的具体实现 SQL:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="com.example.demo.mapper.UserMapper"><selectid="getAll"resultType="com.example.demo.model.UserInfo">
select * from userinfo
</select></mapper>
标签说明:
<mapper>
标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接口的全限定名,包括全包名.类名。<select>
查询标签:是用来执行数据库的查询操作的:id
:是和 Interface(接口)中定义的方法名称⼀样的,表示对接口的具体实现方法。resultType
:是返回的数据类型,也就是开头我们定义的实体类。
2.4.4 添加 Service
服务层实现代码如下:
@ServicepublicclassUserService{@ResourceprivateUserMapper userMapper;publicList<UserInfo>getAll(){return userMapper.getAll();}}
2.4.5 添加 Controller
控制器层的实现代码如下:
@RestController@RequestMapping("/user")publicclassUserController{@ResourceprivateUserService userService;@RequestMapping("/getuserbyid")publicUserInfogetUserById(Integer id){if(id !=null&& id >0){return userService.getUserById(id);}else{returnnewUserInfo();}}}
3.MyBatis 增删改查操作
操作步骤:
- 添加 controller
- 添加 service
- 添加 mapper (dao)
- 添加 xml
3.1 增加操作
① 添加 controller:
@RequestMapping("/insert")publicIntegerinsert(UserInfo userInfo){return userService.insert(userInfo);}
② 添加 service:
publicIntegerinsert(UserInfo userInfo){return userMapper.insert(userInfo);}
③ 添加 mapper :
Integerinsert(UserInfo userInfo);
④ 添加 xml:
<insertid="add">
insert into userinfo(username,password,photo,state)
values(#{username},#{password},#{photo},1)
</insert>
说明:参数占位符 #{} 和 ${}
#{}
:预编译处理。${}
:字符直接替换。 预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为 ? 号,使用用PreparedStatement 的set 方法来赋值。直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成 变量的值。
特殊的增加
默认情况下返回的是受影响的行号,如果想要返回自增 id,具体实现如下:
controller 实现代码:
publicIntegeradd2(@RequestBodyUserInfo userInfo){
userService.getAdd2(userInfo);return user.getId();}
mapper 接口:
@MapperpublicinterfaceUserMapper{// 添加,返回⾃增id voidadd2(User user);}
mapper.xml 实现如下:
<insertid="add2"useGeneratedKeys="true"keyProperty="id">
insert into userinfo(username,password,photo,state)
values(#{username},#{password},#{photo},1)
</insert>
useGeneratedKeys
:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。keyColumn
:设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第⼀列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。keyProperty
:指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
3.2 删除操作
前面三个步骤操作类似,重点看下第四步,数据持久层的实现(xml)。
<deleteid="delById"parameterType="java.lang.Integer">
delete from userinfo where id=#{id}
</delete>
3.3 修改操作
<updateid="update">
update userinfo set username=#{name} where id=#{id}
</update>
3.4 查询操作
3.4.1 单表查询
查询操作需要设置返回类型,绝大数查询场景可以使⽤
resultType
进行返回,它的优点是使用方便,直接定义到某个实体类即可。
<!-- 查询单条数据(根据id)--><selectid="getUserById"resultType="com.example.demo.model.UserInfo">
select *
from userinfo
where id = #{id}
</select>
3.4.2 多表查询
但有些场景就需要用到返回字典映射(
resultMap
)比如:
- 字段名称和程序中的属性名不同的情况;
- ⼀对⼀和⼀对多关系。
① 字段名和属性名不同的情况
xml 如下:
<resultMapid="BaseMap"type="com.example.demo.model.UserInfo"><idcolumn="id"property="id"></id><resultcolumn="username"property="username"></result><resultcolumn="password"property="pwd"></result></resultMap><selectid="getUserById"resultMap="com.example.demo.mapper.UserMapper.BaseMap">
select * from userinfo where id=#{id}
</select>
② 一对一映射
一对一映射要使用
<association>
标签,具体实现如下(一篇文章只对应一个作者):
<resultMapid="BaseMap"type="com.example.demo.model.ArticleInfo"><idproperty="id"column="id"></id><resultproperty="title"column="title"></result><resultproperty="content"column="content"></result><resultproperty="createtime"column="createtime"></result><resultproperty="updatetime"column="updatetime"></result><resultproperty="uid"column="uid"></result><resultproperty="rcount"column="rcount"></result><resultproperty="state"column="state"></result><associationproperty="user"resultMap="com.example.demo.mapper.UserMapper.BaseMap"columnPrefix="u_"></association></resultMap><selectid="getAll"resultMap="BaseMap">
select a.*,u.username u_username from articleinfo a
left join userinfo u on a.uid=u.id
</select>
property
属性:指定 Article 中对应的属性,即用户。resultMap
属性:指定关联的结果集映射,将基于该映射配置来组织用户数据。columnPrefix
属性:绑定一对一对象时,是通过 columnPrefix+association.resultMap.column 来映射结果集字段。
③ 一对多映射
一对多需要使用
<collection>
标签,用法和
<association>
相同,如下所示:
<resultMapid="BaseMap"type="com.example.demo.model.UserInfo"><idcolumn="id"property="id"/><resultcolumn="username"property="username"></result><resultcolumn="password"property="password"></result><resultcolumn="photo"property="photo"></result><collectionproperty="alist"resultMap="com.example.demo.mapper.ArticleInfoMapper.BaseMap"columnPrefix="a_"></collection></resultMap><selectid="getUserById"resultMap="BaseMap">
select u.*,a.title a_title from userinfo u
left join articleinfo a on u.id=a.uid where u.id=#{id}
</select>
3.4.3 like查询
like 使用 #{} 会报错,可以考虑使用 mysql 的内置函数 concat() 来处理,实现代码如下:
<selectid="getUserByLikeName"resultType="com.example.demo.model.UserInfo">
select *
from userinfo
where username like concat('%', #{username}, '%')
</select>
4.动态SQL使用
动态 sql 是Mybatis的强大特性之一,能够完成不同条件下不同的 sql 拼接。
可以参考官方文档:Mybatis动态sql
4.1 if 标签
<insertid="add3">
insert into userinfo(username,
<iftest="photo!=null">
photo,
</if>
password)
values (#{username},
<iftest="photo!=null">
#{photo},
</if>
#{password})
</insert>
test中的对象是传入对象的属性,当它不为空时,才拼接里面的内容。
4.2 trim 标签
<trim>
标签中有如下属性:
prefix
:表示整个语句块,以prefix的值作为前缀suffix
:表示整个语句块,以suffix的值作为后缀prefixOverrides
:表示整个语句块要去除掉的前缀suffixOverrides
:表示整个语句块要去除掉的后缀
示例:
<insertid="add4">
insert into userinfo
<trimprefix="("suffix=")"suffixOverrides=","><iftest="username!=null">
username,
</if><iftest="photo!=null">
photo,
</if><iftest="password!=null">
password
</if></trim>
values
<trimprefix="("suffix=")"suffixOverrides=","><iftest="username!=null">
#{username},
</if><iftest="photo!=null">
#{photo},
</if><iftest="password!=null">
#{password}
</if></trim></insert>
4.3 where 标签
传入的用户对象,根据属性做where条件查询,用户对象中属性不为 null 的,都为查询条件。
<where>
标签, 如果有查询条件就会生成where, 如果没有查询条件就不会生成where<where>
会判断第一个条件前面有没有and, 如果有就会去掉.
<selectid="getList"resultMap="BaseMap">
select * from userinfo
<where><iftest="username!=null">
username=#{username}
</if><iftest="password!=null">
and password=#{password}
</if></where></select>
4.4 set 标签
更新的时候也会出现问题, 使用
<set>
标签来解决(与
<where>
标签类似):
<updateid="updateById">
update userinfo
<set><iftest="username!=null">
username=#{username},
</if><iftest="password!=null">
password=#{password}
</if></set>
where id=#{id}
</update>
4.5 foreach 标签
对集合进行遍历时可以使用该标签。标签有如下属性:
collection
:绑定方法参数中的集合,如 List,Set,Map或数组对象item
:遍历时的每一个对象open
:语句块开头的字符串close
:语句块结束的字符串separator
:每次遍历之间间隔的字符串
示例:
<deleteid="delete">
delete from userinfo where id in
<foreachcollection="list"item="id"open="("close=")"separator=",">
#{id}
</foreach></delete>
版权归原作者 澄白易 所有, 如有侵权,请联系我们删除。