MyBatis使用方法

简介

MyBatis是⼀款优秀的持久层框架, 它⽀持⾃定义 SQL、存储过程以及⾼级映射. MyBatis去除了⼏乎所有的JDBC代码以及设置参数和获取结果集的⼯作.MyBatis可以通过简单的XML或注解来配置和映射原始类型、接⼝和Java POJO为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具。
image.png

使用

前置操作

添加MyBatis依赖

MyBatis FrameworkMySQL Driver都要添加, MyBatis只是个桥梁, 内部还是靠JDBC
image.png

配置连接

application.yml文件里配置

# 数据库连接配置
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

配置 MyBatis 中的 XML 路径

application.yml文件里配置
MyBatis 的 XML 中保存是查询数据库的具体操作 SQL

mybatis:
	mapper-locations: classpath:mapper/**Mapper.xml

搭好格式

①在resource文件夹下新建mapper文件夹存放XxxMapper.xml文件
②源代码目录下新建mapper文件夹存放接口定义
③指定MyBatis映射器XML文件的位置配置

mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

④可以新建model文件夹存放对象的定义

举例(selectAll)

定义接口

mapper文件夹下定义接口, 记得加@Mapper注解
image.png

定义对象属性

根据表的字段定义对象
image.png

配置xml文件

resource下的mapper里定义xml文件, 名字最好和接口名字一样
image.png

<?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="接口的完整类名">
    <select id="接口方法名" resultType="返回结果对象的类型">
        SQL语句
    </select>
</mapper>

注意事项
image.png

sql传参数

使用@Param注解加参数

queryById(@Param("uid") Integer id)
select * from userinfo where id = #{uid}
将id参数映射到sql语句里的uid参数
queryById(@Param("uid") Integer id)
select * from userinfo where id = #{param1}
param1代表第一个参数,和①的效果一样
③当只有一个参数的时候,可以不加@Param注解. 不过sql里面的#{..}要写参数名, 可以随便写

为了防止参数列表过长, 使用传对象的方法
首先接口的参数是对象:
Integer insert(User user)
配置sql语句,把要传的参数写上
insert into userinfo (username,password,photo) values (#{username},#{password},#{photo})
使用Setter方法设置参数给对象, 在传对象
image.png

如果给传入的对象加@Param注解,那么sql语句就不能直接写属性名, 要写#{对象.属性}:
接口定义:
Integer insert2(@Param("userinfo") User user);
SQL语句:
insert into userinfo (username, password, photo) values (#{userinfo.username},#{userinfo.password},#{userinfo.photo})

接口定义:
void update(User user);
sql语句
update userinfo set username = #{username},password=#{password} where id = #{id}
测试
image.png

Integer delete(Integer id);
sql语句:
delete from userinfo where id=#{id}
测试:
image.png

多表查询

补充

sql里#{}和${}区别

问题:
根据名称来查询
image.png
如果是#正常查询, 则错误 , 因为把查询的 " a d m i n " 当成了列 < b r / > − − − − 如果手动操作数据库 , 输入 : < b r / > − − − − ‘ s e l e c t ∗ f r o m u s e r i n f o w h e r e u s e r n a m e = " a d m i n " ‘ 则会正常查出来 < b r / > − − − − 要是 : < b r / > − − − − ‘ s e l e c t ∗ f r o m u s e r i n f o w h e r e u s e r n a m e = a d m i n ‘ 则会报错 : 没找到 a d m i n 列 < b r / > 所以说 则错误, 因为把查询的"admin"当成了列<br />----如果手动操作数据库,输入:<br />----`select * from userinfo where username = "admin"`则会正常查出来<br />----要是: <br />----`select * from userinfo where username = admin`则会报错:没找到admin列<br />所以说 则错误,因为把查询的"admin"当成了列<br/>如果手动操作数据库,输入:<br/>selectfromuserinfowhereusername="admin"‘则会正常查出来<br/>要是:<br/>selectfromuserinfowhereusername=admin则会报错:没找到admin<br/>所以说传递的参数直接放进了sql语句中,没有自己加引号,可以自己加上引号
select * from userinfo where username = '${username}'

原因:

  • #{} : 是预编译处理, 相当于占位符
  • ${} : 是字符直接替换, 字符的内容直接被当做sql语句, 会导致不安全的现象, 也就是sql注入

如果参数从"admin"变成"' or 1='1",那么sql就会变成select * from userinfo where username = '' or 1='1', 就变成了username=空或者1=‘1’, 那么结果就查出来了

使用情况 < b r / > ① o r d e r b y ( 只能用 使用情况<br />①order by(只能用 使用情况<br/>orderby(只能用)
List<User> queryByOrder(String order);
select * from userinfo order by id #{order}
执行会出错
所以排序的时候, 只能使用KaTeX parse error: Expected 'EOF', got '#' at position 89: …l注入<br />②like(#̲ + concat())<br…,程序正确运行,但存在sql注入问题. 需要使用mysql内置函数like concat(‘%’,‘m’,‘%’)(用于将多个字符串拼接在一起),就可以:<br />select * from userinfo where username like concat(‘%’,#{name},‘%’)`正确查询

xml更多属性

<insert id="insert2" useGeneratedKeys="true" keyProperty="id">
	insert into userinfo (username, password, photo) values (#{userinfo.username},#{userinfo.password},#{userinfo.photo})
</insert>

这段代码是针对数据库插入操作的语句:
useGeneratedKeys="true":这是一个属性, 当设置为"true"时, 表示数据库会生成并返回自动生成的主键值.
keyProperty="id":这是另一个属性, 它指定了用于存储自动生成的主键值的Java对象属性名. 在这里, 它的意思是, 数据库生成的主键值将被设置到Java对象的"id"属性中。

重命名

当java代码里的参数名和数据库的字段名不一致的时候,可以重命名,例如对于userinfo表:
定义一个resultMap并写好id, 将User里面的属性对应到字段名
然后使用的时候,加上resultMap="BaseMap"就可以了
(要是字段没写全的话,没写的字段会按默认规则映射, 不过最好写全)

<resultMap id="BaseMap" type="mybatis.model.User">
  <id property="id" column="id"></id>
  <result property="name" column="username"></result>
  <result property="pwd" column="password"></result>
  <result property="createTime" column="createtime"></result>
  <result property="updateTime" column="updatetime"></result>
</resultMap>


<select id="queryAllByMap" resultMap="BaseMap">
  select * from userinfo
</select>

如果出现错误的话,可尝试修改配置JDBC的url参数

spring:
  datasource:
    url: jdbc:mysql://地址:端口/数据库名?useSSL=false&allowPublicKeyRetrieval=true&characterEncoding=utf8

可能遇到的错误表明应用程序无法获取到JDBC连接,并且出现了Public Key Retrieval is not allowed的异常。这种情况通常是由于数据库连接字符串配置问题引起的。在MySQL数据库中,可能需要设置allowPublicKeyRetrieval参数来允许公钥检索。这个参数用于决定是否在连接过程中从服务器获取公钥。

测试

测试接口

在接口定义处生成->测试, 勾选需要测试的方法
image.png
给测试文件加上相应的注解, 并写好测试方法
image.png
可以看到打印的日志内容是正确的
image.png

打印sql日志

mybatis:
  configuration: # 配置打印 MyBatis 执行的 SQL
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

运行的时候就能看到具体的执行过程(以queryByName为例), 可以看到参数具体变成了什么
image.png

具体业务举例

查询所有用户

UserController

@RestController
    @RequestMapping("/user")
    public class UserController {
        @Autowired
        private UserService userService;

        @RequestMapping("/selectAll")
        public List<User> selectAllUser(){
            return userService.selectAllUser();
        }
    }

UserService

@Service
    public class UserService {
        @Autowired
        private UserMapper userMapper;
        public List<User> selectAllUser() {
            return userMapper.queryAll();
        }
    }

访问http://localhost:8080/user/selectAll,得到

[
  {
    "id": 1,
    "username": "admin",
    "password": "admin",
    "photo": "",
    "createTime": "2021-12-06T09:10:48.000+00:00",
    "updateTime": "2021-12-06T09:10:48.000+00:00"
  },
  {
    "id": 2,
    "username": "lisi",
    "password": "123456",
    "photo": "4556a",
    "createTime": "2023-07-25T03:46:06.000+00:00",
    "updateTime": "2023-07-25T03:46:06.000+00:00"
  },
  {
    "id": 13,
    "username": "lisi",
    "password": "123456",
    "photo": "4556a",
    "createTime": "2023-07-25T05:14:14.000+00:00",
    "updateTime": "2023-07-25T05:14:14.000+00:00"
  }
]

多表查询

一对一的表映射

写法1(不推荐)

**用User对象接受对应的属性**
ArticleInfo:
image.png
xml:
**(尽量不要出现from * 的情况)**
image.png
使用association连接另一个表, 并引入其resultMap(路径+result的id)

写法2(常用)

**将User对象里面的属性拆解出来**
ArticleInfo:
image.png
xml:
**(尽量不要出现from * 的情况)**
image.png

动态SQL

**默认值!=null**
有时候, 例如填写表单的时候,有些是必填,有些非必填. 如果直接这样提交的话, 字段会被赋值为null, 但有时有的字段有默认值,不写的话应该是默认值而不是null,所以要根据填写了哪些字段动态sql(另外还有条件判断等情况)
例如:
对于插入内容是null,结果也是null,但他默认值是1,而不是null
image.png
image.png
image.png

标签

image.png

缺点

当每个属性都加, 那么如果第一个和最后一个为空, 那么sql语句必然因逗号而语法错误
image.png

标签

image.png

<insert id="insertByCondition">
    insert into articleinfo
    <trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=",">
        <if test="title!=null">
            title,
        </if>
        <if test="content!=null">
            content,
        </if>
        <if test="userId!=null">
            uid,
        </if>
        <if test="state!=null">
            state
        </if>
    </trim>
    values
    <trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=",">
        <if test="title!=null">
            #{title},
        </if>
        <if test="content!=null">
            #{content},
        </if>
        <if test="userId!=null">
            #{userId},
        </if>
        <if test="state!=null">
            #{state}
        </if>
    </trim>
</insert>

举例:
image.png
image.png

标签

一般情况: (加上1=1防止and破坏sql格式)
image.png
使用:
①生成where关键字
②去除多余的and
③如果没有where条件,就不生成where关键字
image.png
举例:
image.png
image.png

标签

①生成set关键字
②去除最后的逗号
(虽然也可以用标签,但这样更简单
image.png
举例:
image.png
image.png

标签

批量操作
image.png
示例:
image.png
image.png
image.png
补充:
collection也可以是参数的名称. 测试方法的参数列表加上@Param("ids")然后写collection="ids"也可以

注解实现sql

**只适合写简单的, 复杂的很难写**
接口实现上加上注解
image.png
然后不需要写xml就可以直接使用
image.png

其他

“XML标签具有空体”

在MyBatis中,如果你使用了像、等标签,而这些标签没有子元素(称为空体),可能会导致警告提示"XML标签具有空体"。虽然这个警告不会影响代码的执行,但是为了代码的可读性和规范性,我们可以消除这个警告。

<resultMap id="BaseMap2" type="mybatis.model.ArticleInfo">
  	<id property="id" column="id"></id>
  	<result property="title" column="title"></result>
  	<result property="content" column="content"></result>
  	<result property="createtime" column="createtime"></result>
  	<result property="updatetime" column="updatetime"></result>
  	<result property="rcount" column="rcount"></result>
  	<result property="userId" column="userid"></result>
</resultMap>

消除"XML标签具有空体"警告的方法是在空标签上添加一个闭合斜杠/,表示它是一个自闭合标签,而不是一个空标签。这样做可以告诉解析器这是一个完整的标签,不需要进一步的子元素。

<resultMap id="BaseMap2" type="mybatis.model.ArticleInfo">
    <id property="id" column="id" />
    <result property="title" column="title" />
    <result property="content" column="content" />
    <result property="createtime" column="createtime" />
    <result property="updatetime" column="updatetime" />
    <result property="rcount" column="rcount" />
    <result property="userId" column="userid" />
</resultMap>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值