MyBatis查询数据库

1.MyBatis是什么?

MyBatis是一款有序的持久层框架,能更简单的完成程序和数据库交互的工具,也就是更简单的的操作和读取数据库的工具。

2.为什么要学习MyBatis?

我们原来操作数据库的时候,是使用JDBC的代码,但是它是非常麻烦的。每次都要建立数据库连接池,通过DataSource获取数据库连接Connection,然后执行语句,最后还要释放资源等等,这是相当繁琐的步骤。学习使用MyBatis就能更加简单的操作数据库了。

3.怎么学习MyBatis?

MyBatis学习分为两个部分:

  • 配置MyBatis开发环境
  • 使用MyBatis模式和语法操作数据库。

4第一个MyBatis查询操作

开始搭建MyBatis之前,我们先看一下MyBatis在整个框架中的定位,框架交互流程图:

 4.1创建数据和表

下面我们添加用户表和文章表:

-- 创建数据库
drop database if exists mycnblog;
create database mycnblog DEFAULT CHARACTER SET utf8mb4; 

-- 使⽤数据数据
use mycnblog;

-- 创建表[⽤户表]
drop table if exists userinfo;
create table userinfo(
 id int primary key auto_increment,
 username varchar(100) not null,
 password varchar(32) not null,
 photo varchar(500) default '',
 createtime datetime default now(),
 updatetime datetime default now(),
 `state` int default 1
) default charset 'utf8mb4';

-- 创建⽂章表
drop table if exists articleinfo;
create table articleinfo(
 id int primary key auto_increment,
 title varchar(100) not null,
 content text not null,
 createtime datetime default now(),
 updatetime datetime default now(),
 uid int not null,
 rcount int not null default 1,
 `state` int default 1
)default charset 'utf8mb4';

-- 添加⼀个⽤户信息
INSERT INTO `mycnblog`.`userinfo` (`id`, `username`, `password`, `photo`,
`createtime`, `updatetime`, `state`) VALUES
(1, 'admin', 'admin', '', '2021-12-06 17:10:48', '2021-12-06 17:10:48', 1);

-- ⽂章添加测试数据
insert into articleinfo(title,content,uid)
 values('Java','Java正⽂',1);

4.2添加MyBatis框架支持

 4.3配置连接字符串和MyBatis

4.3.1配置连接字符串

下面是application.yml的文件的相关配置:

Spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&userSSL=fasle
    username: root
    password: 1020118096
    dirver-class-name: com.mysql.jdbc.Driver

4.3.2配置MyBatis中XML路径

# 配置 mybatis xml的文件路径名,在resources/mapper创建所有表的xml文件
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

4.4添加业务代码

下面是后端开发的工程思路,也就是下面的流程来实现MyBatis查询所有的用户功能:

 4.4.1添加实体类

先添加用户的实体类:

import lombok.Data;
import java.util.Date;
/**
 * Describe:
 * User:lenovo
 * Date:2023-07-28
 * Time:9:14
 */
@Data
public class User {
    private Integer id;
    private String username;
    private String password;
    private String photo;
    private Date createTime;
    private Date updateTime;
    
}

4.4.2添加mapper接口

数据持久层的接口定义:

@Mapper
public interface UserMapper {
    
    public List<User> getAll();
}

4.4.3添加UserMapper.xml

数据持久层的实现,mybatis的固定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.example.demo.dao.UserMapper">

</mapper>

UserMapper.xml查询所有用户的具体实现SQL:

<?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.example.demo.dao.UserMapper">
    <select id="getAll" resultType="com.example.demo.model.User">
        select * from userinfo
    </select>
</mapper>

以下是对标签的说明:

  • <mapper>标签:需要指定namespace属性,表示命名空间,值为mapper接口的全限定名
  • <select>查询标签:是用来执行数据库的查询操作:
    1. id:是和Interface(接口)中定义的方法名称一样的,表明对接口的具体实现方法。
    2. resultType:是返回的数据类型。

4.4.4添加测试代码

测试代码实现如下:

@SpringBootTest //不能省略,告诉当前程序项目是在Spring Boot框架中运行的。
class UserMapperTest {

    @Autowired
    private UserMapper userMapper;
    @Test
    void getAll() {
        List<User> list = userMapper.getAll();
        System.out.println(list);
    }
}

 5.增、删、改操作

接下来,我们将实现用户的增加、删除、修改的操作,对应使用MyBatis的标签如下:

  • <insert>标签:插入语句;
  • <update>标签:修改语句;
  • <delete>标签:删除标签.

5.1增加用户操作

mapper interface:

@Mapper
public interface UserMapper {

    //查询所有用户操作
    public List<User> getAll();

    //添加用户操作
    Integer add(User user);
}

mapper.xml:

    <insert id="add">
        insert into userinfo(user, password,photo,state)
        values(#{username}, #{password}, #{photo}, 1)
    </insert>

Test:

    @Test
    void add() {
        User user = new User();
        user.setUsername("zhangsan");
        user.setPassword("123");
        user.setPhoto("cat.png");
        System.out.println(userMapper.add(user));
    }

默认情况下,这个方法返回值为受影响结构的行数

5.2修改用户操作

mapper interface:

//更新用户操作
    Integer update(User user);

mapper.xml:

    <update id="update">
        update userinfo set username = #{username} where id = #{id}
    </update>

test:

 @Test
    void update() {
        User user = new User();
        user.setUsername("lisi");
        user.setId(2);
        System.out.println(userMapper.update(user));
    }

 5.3删除用户操作

mapper interface:

//删除用户操作
    Integer delById(User user);

mapper.xml:

    <delete id="delById">
        delete from userinfo where id = #{id}
    </delete>

test:

@Test
    void delById() {
        User user = new User();
        user.setId(2);
        System.out.println(userMapper.delById(user));
    }

 5.4 #{} VS ${}

不同点:

  • #{}和${}都能实现传递参数的目的,但是#{}采取预编译的形式,而${}采取直接替换的模式。
  • #{}由于采取预编译的模式,更加的安全,${}采用直接替换的模式,只能导致SQL注入的问题。所以在正常情况下,我们都是用#{}。
  • 同时我们如果传递的参数是字符串,如果使用${}符(不考虑SQL注入的问题),会直接进行替换,但是在SQL语句中字符串是需要加引号的,这就导致了SQL语句需要我们手动添加引号,但是使用#{}会自动为字符串添加引号。
  • 我们如果进行模糊查询,我们必须使用${}符,#{}会自动的加上引号,导致错误。例如:select * from userinfo where username like '%${}%'。同样的我们可以换一种写法:select * from userinfo where user name like concat('%', #{}, '%')

6.查询操作

6.1返回字典映射:ResultMap

resultMap使用场景:

  • 字段名称和程序中的属性名称不同的时候,我们可以使用resultMap配置映射
  • 一对一和一对多关系可以使用映射并查询数据

字段名和属性名不同的情况

创建User1类:

@Data
public class User1 {
    private Integer id;
    private String username;
    private String pwd;
    private String photo;
    private Date createTime;
    private Date updateTime;
}

创建User1Mapper类:

@Mapper
public interface User1Mapper {

    //查询操作
    List<User1> getUserById(Integer id);
}

创建User1Mapper.xml文件:

<resultMap id="BaseMap" type="com.example.demo.model.User1">
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="password" property="pwd"></result>
    </resultMap>

    <select id="getUserById" resultMap="com.example.demo.dao.User1Mapper.BaseMap">
        select * from userinfo where id = #{id}
    </select>

 test方法:

@SpringBootTest
class User1MapperTest {

    @Autowired
    private User1Mapper user1Mapper;

    @Test
    void getUserById() {
        System.out.println(user1Mapper.getUserById(1));
    }
}

 6.2多表查询

在进行多表查询的时候,如果我们使用resultType标签,在一个类中包含了另一个对象是查询不出来所包含的对象的,比如以下代码:

@Data
public class ArticleInfo {
    private Integer id;
    private String title;
    private String content;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private Integer rcount;
    //包含了另一个对象
    private User user;
}

这个时候,由于我们查询文章的时候,又需要查询作者的信息,导致对象中包含了对象,我们使用MyBatis是无法进行响应的user对象中字段匹配的。

ArticleInfoMapper.java 类:

@Mapper
public interface ArticleInfoMapper {

    //查询文章以及对应的作者名字
    List<ArticleInfo> getAll();
}

ArticleInfoMapper.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.example.demo.dao.ArticleInfoMapper">
    <select id="getAll" resultType="com.example.demo.model.ArticleInfo">
        select a.*, u.username u_username from articleinfo a left join userinfo u on a.uid=u.id
    </select>
</mapper>

Test类:

@SpringBootTest
class ArticleInfoMapperTest {
    @Autowired
    private ArticleInfoMapper articleInfoMapper;

    @Test
    void getAll() {
        List<ArticleInfo> list = articleInfoMapper.getAll();
        System.out.println(list);
    }
}

 修改如下:

<?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.example.demo.dao.ArticleInfoMapper">
    <resultMap id="BaseMap" type="com.example.demo.model.ArticleInfo">
        <id column="id" property="id"></id>
        <result column="title" property="title"></result>
        <result column="content" property="content"></result>
        <association property="user"
                     resultMap="com.example.demo.dao.UserMapper.UserBaseMap"
                     columnPrefix="u_">
        </association>
    </resultMap>
    <select id="getAll" resultMap="com.example.demo.dao.ArticleInfoMapper.BaseMap">
        select a.*, u.username u_username from articleinfo a left join userinfo u on a.uid=u.id
    </select>

</mapper>

 以上使用association>标签,表示一对一结果映射:

  • property属性:指定Article中对应的属性,即用户
  • resultMap属性:指定关联的结果集映射,将基于该映射配置来组织用户数据。
  • columnPrefix属性:这个属性不能省略,如果省略并且还需要作者的id时,关联表中有两个id,,这会跟文章的id混淆,导致匹配错误的问题。

6.3一对多,一个用户多篇文章案例

一对多,我们需要使用<collection>标签,用法和<association>相同,如下所示:

<resultMap id="BaseMap" type="com.example.demo.model.User2">
    <id column="id" property="id"></id>
    <result column="username" property="username"></result>
    <result column="password" property="password"></result>
    <result column="photo" property="photo"></photo>
    <collection property="alist" resultMap=com.exam.demo.mappper.ArticleInfoMapper.baseMap"
        columnPrefix="a_">
    </collection>
</resultMap>
<select id="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}

7.复杂情况:动态SQL使用

在我们填写一些信息的时候,可能会遇到这问题,比如在注册的时候只有账号,密码,和确认密码是必填项,真实姓名、性别、年龄等是选填,这个时候我们应当如何构造SQL语句呢?

7.1<if>标签

假设注册场景:名字、密码必填,头像图片选填。

UserMapper.java文件:

//添加用户
    Integer add1(User user);

UserMapper.xml文件:

<insert id="add1">
        insert into userinfo(
        username,
        <if test="photo != null">
            photo,
        </if>
        password
        ) values(
        #{username},
        <if test="photo != null">
            #{photo},
        </if>
        #{password})
</insert>

我们现在只插入姓名和密码的结果为:

 7.2<trim>标签

之前插入用户的时候,我们只有一个photo是可选字段,但是如果姓名,密码,照片都为可选字段我们要怎么做呢?

<trim>标签中有以下属性:

  • prefix:整个语句块,以prefix的值为前缀
  • suffix:整个语句快,以suffix的值为后缀
  • prefixOverrides:表示整个语句块要去除掉的前缀
  • suffixOverrides:表示整个语句块要去除掉的后缀

调整UserMapper.xml的插入语句:

    <insert id="add2">
        insert into userinfo(
        <trim suffixOverrides=",">
            <if test="username != null">
                username,
            </if>
            <if test="password != null">
                password,
            </if>
            <if test="photo != null">
                photo
            </if>
        </trim>
        ) values(
        <trim  suffixOverrides=",">
            <if test="username != null">
                #{username},
            </if>
            <if test="password != null">
                #{password},
            </if>
            <if test="photo != null">
                #{photo},
            </if>
        </trim>
        )
    </insert>

我们只添加名字和密码:

7.3<where>标签

传入的用户对象,根据属性做where条件查询,用户对象中属性不为null的,都可以作为查询条件。

UserMapper.java:

   List<User> selectByCondition(User user);

UserMapper.xml:

<select id="selectByCondition" resultType="com.example.demo.model.User">
        select * from userinfo
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="username != null">
                and username = #{username}
            </if>
            <if test="photo != null">
                and photo = #{photo}
            </if>
            <if test="createTime">
                and createtime = #{createTime}
            </if>
            <if test="updateTime">
                and updatetime = #{updateTime}
            </if>
        </where>
    </select>

<where>标签也可以使用<trim prifix="where" prefixOverrides="and">代替

7.4<set>标签

根据川渝的用户对象属性来更新数据。

UserMapper接口中修改用户,根据传入的用户ID,修改其他非空属性。

 //<set>标签的使用
    int updateById(User user);

UserMapper.xml:

<update id="updateById">
        update userinfo
        <set>
            <if test="username != null">
                username = #{username},
            </if>
            <if test="password != null">
                password = #{password},
            </if>
            <if test="photo != photo">
                photo != #{photo}
            </if>
        </set>
        where id = #{id}
    </update>

<set>标签可以使用<trim prefix="set" suffixOverrides=",">代替

7.5<foreach>标签

对集合进行遍历时可以使用该标签。<foreach>标签有如下属性:

  • collection:绑定方法参数中的集合
  • item:遍历时的每一个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

根据多个文章id查询文章数据:

//根据Id查询文章,<foreach>的使用
    List<ArticleInfo> selectByIds(List<Integer> list);

.xml:

<select id="selectByIds" resultType="com.example.demo.model.ArticleInfo">
        select * from articleinfo where id in
        <foreach collection="list" item="item" open="(" close=")" separator=",">
            #{item}
        </foreach>
    </select>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值