MyBatis入门

发布时间:2024年01月06日

MyBatis 是什么?

  • MyBatis 是?款优秀的持久层框架,它?持?定义 SQL、存储过程以及?级映射

    • 对象关系映射框架
    • 存储过程
      • 封装了一堆sql的方法
      • 缺点:
        • 操作难度大
        • 没办法调试
        • 修改和扩展难
        • 逻辑判断放在了 MySQL服务器,浪费数据库资源
    • ?级映射
      • 表字段和类字段 的 映射
    • MyBatis 去除了?乎所有的 JDBC 代码以及设置参数和获取结果集的?作。
    • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接?和 Java POJO(Plain Old Java Objects,普通?式 Java 对象)为数据库中的记录。
  • 简单来说 MyBatis 是更简单完成程序和数据库交互的?具,也就是更简单的操作和读取数据库?具

  • MyBatis 在整个框架中的定位,框架交互流程图:

    • image-20231123161722529
      • 为什么要实现 InterFace ,而不直接实现类:

        • 通过 xml解耦 Java 和 数据库的关系
      • 原理:

        • 通过代理对象实现 接口,生成 SQL 调用 JDBC
  • MyBatis 也是?个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。

    • 在?向对象编程语?中,将关系型数据库中的数据与对象建?起映射关系

      • 进??动的完成数据与对象的互相转换:

        1. 将输?数据(即传?对象)+SQL 映射成原? SQL
        2. 将结果集映射为返回对象,即输出对象
      • ORM 把数据库映射为对象

        • 数据库表(table)–> 类(class)
        • 记录(record,?数据)–> 对象(object)
        • 字段(field) --> 对象的属性(attribute)
    • ?般的 ORM 框架,会将数据库模型的每张表都映射为?个 Java 类。

    • 也就是说使? MyBatis 可以像操作对象?样来操作数据库中的表,可以实现对象和数据库表之间的转换

为什么要学习 MyBatis?

  • 那已经有了 JDBC 了,为什么还要学习 MyBatis?

    • JDBC 的操作流程:
      1. 创建数据库连接池 DataSource
      2. 通过 DataSource 获取数据库连接 Connection
      3. 编写要执?带 ? 占位符的 SQL 语句
      4. 通过 Connection 及 SQL 创建操作命令对象 Statement
      5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
      6. 使? Statement 执? SQL 语句
      7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
      8. 处理结果集
      9. 释放资源
  • 从上述代码和操作流程可以看出,对于 JDBC 来说,整个操作?常的繁琐

    • 我们不但要拼接每?个参数,?且还要按照模板代码的?式,?步步的操作数据库
    • 并且在每次操作完,还要?动关闭连接等,?所有的这些操作步骤都需要在每个?法中重复书写。
  • MyBatis 可以帮助我们更?便、更快速的操作数据库

入门

环境配置

1.添加依赖

image-20231123163459029

2.配置数据库链接信息
  • application.yml

    • spring:
        datasource:
          url: jdbc:mysql://localhost:3306/mycnblog
          username: root
          password: 200337qqq
          driver-class-name: com.mysql.cj.jdbc.Driver
      
      • 注意事项
        • 如果使? mysql-connector-java 是 5.x 之前的使?的是“com.mysql.jdbc.Driver”,如果是?于 5.x使?的是“com.mysql.cj.jdbc.Driver”。
3.配置 MyBatis 中的 XML 路径
  • MyBatis 的 XML 中保存是查询数据库的具体操作 SQL,配置如下:

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

添加业务代码

  • mybatis 组成 2 部分:

    • 接口 (表的所有操作方法)
      • 给其他类调用
    • XML实现接口
      • 具体sql的实现
  • 按照后端开发的?程思路,也就是下?的流程来实现 MyBatis 查询所有?户的功能:

    • image-20231123170445951
添加实体类
  • 先添加?户的实体类:

    • import lombok.Data;
      import java.util.Date;
      @Data
      public class Userinfo {
          private Integer id;
          private String username;
          private String password;
          private String photo;
          private Date createTime;
          private Date updateTime;
      }
      
添加 mapper 接?
  • 数据持久层的接?定义:

    • @Mapper
      public interface UserinfoMapper {
          List<Userinfo> getAll(Integer id);
      }
      
添加 UserinfoMapper.xml
  • 数据持久成的实现,mybatis 的固定 xml 格式:

    • namespace

      • 要实现接口的全路径
    • id

      • 实现的方法名
    • resultType

      • 返回类型
    • ${id}

      • 动态标签,用于传入参数
    • <?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.mybatistest.mapper.UserinfoMapper">
          <select id="getAll" resultType="com.example.mybatistest.entity.Userinfo">
              select * from userinfo where id =${id}
          </select>
      </mapper>
      
添加 Service
@Service
public class MybatisServiceImp implements MybatisService {

    @Autowired
    private UserinfoMapper userinfoMapper;

    @Override
    public List<Userinfo> getAll(Integer id) {
        return userinfoMapper.getAll(id);
    }
}
添加 Controller
  • 控制器层的实现代码如下:

    • @RestController
      @RequestMapping("/user")
      public class MybatisController {
      
          @Autowired
          MybatisService mybatisService;
      
          @RequestMapping("/getuser") //因为Windows不区分大小写,所以尽量使用 小写 ,替代:中划线 get-user
          public List<Userinfo> getuser(Integer id){
              if(id == null){
                  return null;
              }
              return mybatisService.getAll(id);
          }
      }
      
使? apipost 测试

image-20231123212201521

注意事项

返回值为 list的时候,填 list中的类型

  • List<Userinfo> getAll();
    
    • <select id="getAll" resultType="com.example.mybatis3.entity.Userinfo">
          select * from userinfo
      </select>
      

简单的CURD操作

插入

  • 步骤:

    1. 在mapper中声明方法

      • 传递的是对象

        • int add(Userinfo userinfo);
          
    2. 在 mapper.xml 中 提供 sql实现

      • 赋值的是对象属性

        • 注意: 对应的不是数据库字段,而是 实体类的属性
      • <insert id="add" >
            insert into userinfo(username, password, createtime, updatetime)
            values(#{username},#{password},#{createTime},#{updateTime})
        </insert>
        
        • 默认是返回int 受影响的行数, 不会有 resultType
  • 如何拿到 插入实体类对应的 id

    • <insert id="add" useGeneratedKeys="true" keyProperty="id">
          insert into userinfo(username, password, createtime, updatetime)
          values(#{username},#{password},#{createTime},#{updateTime})
      </insert>
      
      • useGeneratedKeys:
        • 这会令 MyBatis 使? JDBC 的 getGeneratedKeys ?法来取出由数据库内部?成的主键
          • ?如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的?动递增字段),默认值:false。
      • keyColumn:
        • 设置?成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第?列的时候,是必须设置的。
        • 如果?成列不??个,可以?逗号分隔多个属性名称。
      • keyProperty:
        • 指定对应 实体类中的 属性名称
        • 指定能够唯?识别对象的属性,MyBatis 会使? getGeneratedKeys 的返回值或 insert 语句的 selectKey ?元素设置它的值
          • 默认值:未设置(unset)。如果?成列不??个,可以?逗号分隔多个属性名称
    • 测试:

      • image-20231124161140237

修改

  1. int upUser(Userinfo userinfo);
    
  2. <update id="upUser">
        update userinfo set username=#{username} where id = #{id}
    </update>
    

删除

  1. int deleteUser(Integer id);
    
  2. <delete id="deleteUser">
        delete from userinfo where id=#{id}
    </delete>
    

查询

参数占位符 #{} 和 ${}
  • #{}:预编译处理
  • ${}:字符直接替换
    • 预编译处理是指:
      • MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号
      • 使? PreparedStatement的 set ?法来赋值。
    • 直接替换
      • 是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。
${} 优点
  • 使? ${sort} 可以实现排序查询,?使? #{sort} 就不能实现排序查询了
    • 因为当使? #{sort} 查询时
    • 如果传递的值为 String 则会加单引号,就会导致 sql 错误。
SQL 注?问题
  • 使用 #{} 占位符会告诉 mysql这是 一个值,而不是关键字等其他信息,所以不会出现sql注入的问题
<select id="isLogin" resultType="com.example.demo.model.User">
select * from userinfo where username='${name}' and password='${pwd}'
</select>
  • sql 注?代码:“’ or 1='1”
    • image-20231124174316568

image-20231124170317557

  • 结论:?于查询的字段,尽量使? #{} 预查询的?式

    • #{} 当作预处理,填充到 原来的value上

    • image-20231124174427857

    • 预查询:

      • 只是一个值的替换,本身的查询规则,查询选择(索引)都定了
      • 只是在某一个零件上用一个动态的value替换的
      • 相当于模板
like 查询
  • like 使? #{} 报错

    • <select id="findUserByName2" resultType="com.example.demo.model.User">
      select * from userinfo where username like '%#{username}%';
      </select>
      
      • 相当于: select * from userinfo where username like ‘%‘username’%’;
  • 这个是不能直接使? ${}

    • 因为 username不能穷举,会有 sql注入的问题
  • 可以考虑使? mysql 的内置函数 concat() 来处理,实现代码如下:

    • 将 username,% 拼接起来

    • <select id="findUserByName3" resultType="com.example.demo.model.User">
      	select * from userinfo where username like concat('%',#{username},'%');
      </select>
      
文章来源:https://blog.csdn.net/yin_ming_hui/article/details/135431098
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。