MyBatis学习

本篇进行MyBatis学习


概念学习

MyBatis查询数据库

MyBatis是什么?

MyBaits是基于JDBC的
MyBatis 是⼀款优秀的持久层框架,它支持自定义SQL、存储过程以及高级映射。MyBatis 去除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式Java 对象)为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的工具,也就是更简单的操作和读取数据库工具。
我们可以查看MyBatis的官方文档MyBatis官网

为什么要学习 MyBatis?

对于后端开发来说,程序是由以下两个重要的部分组成的:

  1. 后端程序
  2. 数据库

简单来说:JDBC太难,

MyBatis 也是⼀个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在面向对象编程语言中,将关系型数据库中的数据与对象建立起映射关系,进而自动的完成数据与对象的互相转换:

  1. 将输⼊数据(即传⼊对象)+SQL 映射成原生 SQL
  2. 将结果集映射为返回对象,即输出对象

ORM 把数据库映射为对象:
数据库表(table)–> 类(class)
记录(record,行数据)–> 对象(object)
字段(field) --> 对象的属性(attribute)
⼀般的 ORM 框架,会将数据库模型的每张表都映射为一个 Java 类。
也就是说使用MyBatis 可以像操作对象⼀样来操作数据库中的表,可以实现对象和数据库表之间的转换

MyBatis使用

MyBatis 学习只分为两部分:

  1. 配置 MyBatis 开发环境;
  2. 使用 MyBatis 模式和语法操作数据库

配置 MyBatis 开发环境

MyBatis环境搭建:

1.添加MyBatis框架支持

新建项目添加依赖
在这里插入图片描述

注意创建好了MyBatis项目之后,启动会报错!!!

2.设置MyBatis配置信息

设置数据库连接的相关信息

数据库连接代码,在配置文件中添加

# 数据库连接配置
spring.datasource.url=jdbc:mysql://localhost:3306/mycnblog?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
MyBatis xml保存路径和xml的命名格式

配置 mybatis xml 的文件路径,创建所有表的 xml 文件,在配置文件中添加

mybatis.mapper-locations=classpath:/mybatis/*Mapper.xml//存储mabits的目录和文件名

MyBatis模式开发

在这里插入图片描述

由两部分组成:

  1. interface:让其他层可以注入使用的接口
  2. mybaitis:xml ->具体实现sql【它是上面interface的“实现”】

首先在resources中添加mybatis(设置的文件)中的xml文件
在这里插入图片描述

然后创建实体类
在这里插入图片描述
在userMapper中进行接口声明

@Mapper//注意添加此注解
public interface UserMapper {
    List<UserEntity> getAll();
}

在userMapper.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.mapper.UserMapper">//这里是对应的Mapper类,实现的接口(包名+接口名)
    <select id="getAll" resultType="com.example.demo.entity.UserEntity">//mapper里面的方法和返回类型,id与接口方法名相同
        select * from userinfo//sql语句
    </select>
</mapper>

在服务层(servlce),将映射进行服务层
代码:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public List<UserEntity> getAll(){
        return userMapper.getAll();
    }
}

服务层进入控制层

RequestMapping("/user")
@RestController
public class UserController {

    @Autowired
    private UserService userService;
    @RequestMapping("/getall")
    public List<UserEntity> getAll(){
        return userService.getAll();
    }
}

以上为基础开发

根据id查找对象

//根据id查询用户对象
    UserEntity getUserById(@Param("id") Integer id);

此处使用注解@Param,代表了传递过来的内容被重命名,在数据库查询时,需要属于@Param修改的名字

Mabatis获取动态参数

**1、${paramName},**直接替换,可以在日志中进行查看
首先添加配置文件

#打印MyBatis执行SQL
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
logging.level.com.example.demo=debug

日志将打印出所执行的sql语句,系统默认的日志打印时info,这里进行配置改为debug级别才能进行查看。

select * from userinfo where id=${id}

在这里插入图片描述
通过日志可以看到是直接替换

2、#{paramName} 占位符

select * from userinfo where id=#{id}

在这里插入图片描述
使用占位符可以有效避免sql注入的问题

直接替换和使用占位符的区别
直接替换在处理非数值类型的查询时,会出现错误
占位符预处理,则不会

使用占位符可以有效避免sql注入的问题,但在使用sql关键字处理时就会出现问题,这个时候需要使用直接替换

使⽤ ${sort} 可以实现排序查询,⽽使⽤ #{sort} 就不能实现排序查询了,因为当使⽤ #{sort} 查询时,
如果传递的值为 String 则会加单引号,就会导致 sql 错误。

单表的增删改

改操作

interface代码

int updatePassword(@Param("id")Integer id,
                       @Param("password") String password,
                       @Param("newPassword") String newPassword);

xml代码

<update id="updatePassword">
        update userinfo set password=#{newPassword}
        where id=#{id} and password=#{password}
    </update>

删除操作

对于删除事务

interface代码

@Transactional
    @Test
    void delById() {
        int id = 1;
        int result = userMapper.delById(id);
        System.out.println("删除"+result);
    }

xml代码

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

添加操作

interface代码

    //添加用户
    int addUser(UserEntity user);

    //添加用户方法2
    int addUserGetId(UserEntity user);

xml代码:

<insert id="addUser"><!--添加返回受影响的行数-->
        insert into userinfo(username,password) values(#{username},#{password})
    </insert>

    <insert id="addUserGetId" useGeneratedKeys="true" keyProperty="id"><!--是否自动生成id,返回影响行数和id-->
        insert into userinfo(username,password) values(#{username},#{password})
    </insert>

like查询

模糊查询
interface代码:

//根据名称模糊查询
    List<UserEntity> getListByName(@Param("username") String username);

xml代码(使用concat)

<!--模糊查询-->
    <select id="getListByName" resultType="com.example.demo.entity.UserEntity">
        select * from userinfo where username like concat('%',#{username},'%')<!--模糊查询,查询任意字符,使用字符串拼接-->
    </select>

返回类型的区别resultType和resultMap

返回字典映射
resultMap 使用场景:
字段名称和程序中的属性名不同的情况,可使用resultMap 配置映射;
一对一和一对多关系可以使用 resultMap 映射并查询数据。
如出现字段名与属性名不相同的情况

<!--resultMap的使用-->
    <resultMap id="BaseMap" type="com.example.demo.entity.UserEntity">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="password" column="password"></result>
        <result property="createtime" column="createtime"></result>
    </resultMap>

    <select id="getListByName" resultMap="BaseMap">
        select * from userinfo where username like concat('%',#{username},'%')<!--使用字符串拼接-->
    </select>

在这里插入图片描述

多表操作

多表查询

第一种方式:

mapper代码:
在这里插入图片描述
xml代码
在这里插入图片描述

值得注意的是由于lombok的使用,在继承了别的类的类中添加lombok的注解如@Data,并不会让父类的属性进行tostring操作,所有并不会显示父类信息,所以要自己tostring类
勾选父类同样tostring
在这里插入图片描述

一个查询多个表并打印:

mapper代码

List<ArticleInfoVO> getListByUid(@Param("uid") Integer uid);

xml代码:

<!--根据uid查找作者-->
    <select id="getListByUid" resultType="com.example.demo.entity.vo.ArticleInfoVO">
        select a.*,u.username from articleinfo a
        left join userinfo u on u.id=a.uid
        where a.uid=#{uid}
    </select>

单元测试代码:

@Test
    void getListByUid() {
        Integer uid = 1;
        List<ArticleInfoVO> list = articleMapper.getListByUid(uid);
        /*for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }*/
        list.stream().parallel().forEach(System.out::println);//parallel()并行执行
    }

动态sql的使用

动态 sql 是Mybatis的强大特性之⼀,能够完成不同条件下不同的 sql 拼接

标签

必填字段和非必填字段,那如果在添加用户的时候有不确定的字段传⼊,程序应该如何实现呢?
如果用户设置值就会用用户设置的值,如果没有就系统默认的值,保证数据的一致性
使用:
进行判断

<insert id="addUserGetId2">
        insert into userinfo(username,password
        <if test="photo!=null">//test判断的是key的属性(不是数据库中的字段)
            ,photo//数据库的信息
        </if>
        )values(#{username},#{password}
        <if test="photo!=null">
            ,#{photo}//类里面的属性
        </if>
        )
    </insert>

标签

当如果所有字段都是⾮必填项,就考虑使用标签结合标签,对多个字段都采取动态生成的方式。
标签中有如下属性:
prefix:表示整个语句块,以prefix的值作为前缀
suffix:表示整个语句块,以suffix的值作为后缀
prefixOverrides:表示整个语句块要去除掉的前缀
suffixOverrides:表示整个语句块要去除掉的后缀

MyBatis多个参数都是非必传参数的解决方案
第一种方法:一加一方案
xml文件:

<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
        select * from articleinfo
        where 1=1
        <trim prefixOverrides="and">
            <if test="id!=null and id>0">
                and id=#{id}
            </if>
            <if test="title!=null and title!=' '">
                and title like concat ('%' ,#{title},'%')
            </if>
        </trim>
    </select>

第二种方式:trim方式,

<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
        select * from articleinfo
        <trim prefix="where" suffixOverrides="and">
            <if test="id!=null and id>0">
                id=#{id} and
            </if>
            <if test="title!=null and title!=' '">
                title like concat ('%' ,#{title},'%')
            </if>
        </trim>
    </select>

当trim中生成了代码,那么才会添加< trim >里面的前缀和后缀,如果trim中没有生成代码,那么前缀和后缀就会省略(不生成)

第三种方式:< where >标签

where只能去掉前缀and关键字,并不能帮你去除后面的and关键字

<select id="getListByIdOrTitle" resultType="com.example.demo.entity.vo.ArticleInfoVO">
        select * from articleinfo
        <where>
            <if test = "id!=null and id>0">
                id=#{id}
            </if>
            <if test="title!=null and title!=''">
                and title like concat('%',#{title},'%')
            </if>
        </where>
    </select>

以上标签也可以使⽤ <trim prefix="where" prefixOverrides="and">

< set >标签

根据传入的用户对象属性来更新用户数据,可以使用< set >标签来指定动态内容。
UserMapper 接口中修改用户方法:根据传入的用户id 属性,修改其他不为 null 的属性:

<update id="updateById" parameterType="org.example.model.User">
 	update user
 		<set>
			<if test="username != null">
			 	username=#{username},
 			</if>
 			<if test="password != null">
 				password=#{password},
 			</if>
 		</set>
 	where id=#{id}
</update>

以上< set >标签也可以使⽤ <trim prefix="set" suffixOverrides=","> 替换。

< foreach >标签

对集合机械能遍历时可以使用该标签。标签有如下属性:
collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
item:遍历时的每⼀个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串
示例:根据多个文章 id 来删除文章数据。
ArticleMapper 中新增接口方法:

批量删除操作

<delete id="delById">
        delete from articleinfo
        where id in
        <foreach collection="idList" item="aid" open="(" close=")" separator=",">
            #{aid}
        </foreach>
    </delete>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值