MyBatis

Author:Dawn_T17🥥

目录

MyBatis介绍

 MyBatis入门

入门程序

JDBC

一个小插件——lombok 

数据库连接池

MyBatis基础操作 ——通过注解配置

前置

占位符

日志 

预编译SQL 和SQL注入展示

1.删除操作

2.添加操作 

主键返回

3.更新操作

4.查询操作

数据封装​

条件查询

 MyBatis基础操作 ——通过XML配置

***四个一致

MybatisX插件 

动态SQL

 

 

 

 


MyBatis介绍

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。           ---MyBatis官网                        

持久层(Persistence Layer)即DAO层

持久层是软件架构中的一个重要概念,主要负责数据的持久化存储和管理。

 MyBatis入门

入门程序

1.创建工程 (三步工作)

 

2.配置MyBatis

MyBatis项目下的resources里有一个配置文件

用来配置数据库连接信息

 

配置数据库连接信息-四要素
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234

3.编写SQL语句

@Mapper 注解(映射器)

 在运行时候,会自动生成该接口实现类对象(代理对象),并且将该对象交给IOC容器管理

@Mapper 通常是在 MyBatis 框架中使用的注解。

当一个接口被标注了 @Mapper 注解后,MyBatis 框架会自动为这个接口创建代理对象,并将其纳入 MyBatis 的映射器体系中,使得在其他代码中可以通过这个接口来执行数据库的操作,而无需手动创建实现类。

@Select注解 是在 MyBatis 框架中使用的注解。

它用于在 Mapper 接口的方法上,指定要执行的 SQL 查询语句。通过 @Select 注解,可以清晰地定义方法与特定的数据库查询操作的关联。

@Selete注解用来传递查询数据相关的SQL语句

package com.dawn_t.mapper;

import com.dawn_t.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper  //在运行时候,会自动生成该接口实现类对象(代理对象),并且将该对象交给IOC容器管理
public interface UserMapper {

    //查询全部用户信息
    @Select("select * from user")
    public List<User> list();
}

4.测试 

package com.dawn_t;

import com.dawn_t.mapper.UserMapper;
import com.dawn_t.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest
class SpringbootMybatisQuickstartApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
   public void testListUser(){
        List<User> userList =userMapper.list();
        userList.stream().forEach(user -> {
            System.out.println(user);
        });

   }

}

JDBC

见其他文章

因为JDBC代码繁杂,数据库连接释放次数频繁,浪费资源。

现在业务开发主要运用SpringBoot 联合Mybatis

一个小插件——lombok 

 通过Maven导入lombok相关依赖(不用版本号)

lombok会在编译时候,自动生成相关代码

这个过程需要lombok插件

这个插件是IDEA自带的插件,下载IDEA时候已经下载好了。

数据库连接池

数据库连接池是一种用于优化数据库操作性能的技术

它的主要作用是减少创建和关闭数据库连接所带来的开销。在没有连接池的情况下,每次与数据库进行交互都需要创建新的连接,完成操作后再关闭连接。这个过程涉及到一系列的系统资源分配和释放,非常耗时。

例如,在一个高并发的 Web 应用中,如果每个用户请求都单独创建和关闭数据库连接,服务器的性能会受到极大影响,可能导致响应延迟甚至系统崩溃。

连接池会预先创建一定数量的数据库连接,并将这些连接保存在池中。当应用程序需要访问数据库时,它可以从池中获取一个可用的连接,使用完毕后将连接放回池中,而不是关闭连接。

在实际应用中,合理配置连接池的参数非常重要,比如最大连接数、最小连接数、等待超时时间等。如果最大连接数设置过小,可能无法满足高并发的需求;如果设置过大,又可能会浪费系统资源。

 

MyBatis基础操作 ——通过注解配置

前置

占位符

***Mybatis中的SQL语句动态获取参数

用占位符 #{ }

#{a}

 

日志 

日志是在软件开发和系统运行过程中,对关键事件和操作的记录。

日志很杂,很多,不用记

未添加日志输出前,我们看不到具体的实行过程

这里在application.properties添加一个Mybatis日志输出指令

#配置MyBatis的日志信息,指定输出到控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

就会在运行和测试的时候在控制台上输出 预编译的SQL 

预编译SQL 和SQL注入展示

预编译 SQL 是一种提高数据库操作安全性和性能的技术。

它的工作原理是将 SQL 语句的结构(模板)提前发送给数据库进行解析和优化,而实际执行时只需要将具体的参数值传递进去。

优势:

  1. 安全性增强

    有效防止 SQL 注入攻击。因为参数值是作为数据而不是可执行的代码处理,恶意输入无法改变 SQL 语句的结构和逻辑。
  2. 性能提升

    数据库可以对预编译的语句进行缓存和复用,对于相同结构但参数不同的多次执行,节省了重复解析和优化的开销。
  3. 代码可读性和可维护性

    使代码更加清晰和易于理解,将 SQL 语句的结构和参数分离,减少了复杂的字符串拼接操作。

关于性能 

非预编译和预编译对比 

关于安全 

SQL注入展示

SQL 注入是一种常见的网络攻击手段,攻击者通过在输入中插入恶意的 SQL 代码来改变原本 SQL 语句的逻辑,从而获取未经授权的数据或者执行非法操作。

如果没有使用预编译,直接拼接用户输入来构建 SQL 语句:

String username = request.getParameter("username");
String password = request.getParameter("password");

String sql = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";

 如果攻击者输入用户名 ' OR '1'='1 和任意密码,最终的 SQL 语句就会变成:

SELECT * FROM users WHERE username = '' OR '1'='1' AND password = 'any_password'

 这样就绕过了正常的认证逻辑,能够获取所有用户的数据。

如下图,密码行输入一些SQl语句,改变SQL查询条件,非法登录!

用预编译处理后

数据库会将预编译的 SQL 语句结构进行解析和优化,并将传入的参数视为数据而不是可执行的代码,从而避免了 SQL 注入的风险。 

1.删除操作

@Delete注解用来传递删除数据相关的SQL语句

接口方法

@Mapper
public interface EmpMapper {
     @Delete("delete from emp where id=#{id}")
     public int delete(Integer id);
}

测试类  

@SpringBootTest
class SpringbootMybatisCrudApplicationTests {

  @Autowired
    private EmpMapper empMapper;
  @Test
    public void testDelete(){
      empMapper.delete(17);
  }
 //可以获取返回值,这个返回值表示影响的数据数量
//  将empMapper的返回值设为int
//  public void testDelete(){
//   int delete=empMapper.delete(16);
//    System.out.println(delete);
//  }
}

2.添加操作 

@Insert注解用来传递添加数据相关的SQL语句

pojo对象准备

//lombok
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Emp {
    //数据库中用下划线_表示的数据名称,pojo对象里我换成了驼峰命法表示
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Short gender;
    private String image;
    private Short job;
    private LocalDate entrydate;
    private Integer deptId;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
}

接口方法 

@Mapper
public interface EmpMapper {
//直接写死,不推荐
//     @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
//             "values('T','Tang',1,'1.jpg',1,'2005-06-07',1,now(),now())")
//     public void insert();

//占位符动态赋值
     @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
             "values(#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
     public void insert(Emp emp);
}
//values中是Emp对象中的变量名称

当插入的数据有多个值的时候,可以封装进一个对象中,一起动态赋值传递具体参数 

测试类 

@SpringBootTest
class SpringbootMybatisCrudApplicationTests {

  @Autowired
    private EmpMapper empMapper;
  @Test
  public void testInsert(){
    Emp emp= new Emp();
    emp.setUsername("T");
    emp.setName("Tang");
    emp.setImage("1.jpg");
    emp.setGender((short) 1);
    emp.setJob((short) 1);
    emp.setEntrydate(LocalDate.of(2005,6,17));
    emp.setCreateTime(LocalDateTime.now());
    emp.setUpdateTime(LocalDateTime.now());
    emp.setDeptId(1);
    empMapper.insert(emp);
  }
}
主键返回

现在用get()方法获得id,会获得NULL

我们用主键返回,为主键属性赋值

主键返回运用场景:

在插入一条主表数据后,获取到主键值,然后将其用于插入关联表的数据。

例如,先插入订单主表数据,获取订单 ID 后,再将其用于插入订单详情表中,以建立关联。

@Options(useGeneratedKeys = true,keyProperty = "id")
     @Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +
             "values(#{username},#{name},#{gender},#{image},#{job},#{entrydate},#{deptId},#{createTime},#{updateTime})")
     public void insert(Emp emp);
   @Options(useGeneratedKeys = true,keyProperty = "id")

useGeneratedKeys = true 表示使用数据库生成的主键,keyProperty = "id" 指定将主键值赋给@Options注解注解的实体类 Emp中的 id 属性。

3.更新操作

接口方法

@Mapper
public interface EmpMapper {
     @Update("update emp set username=#{username},name=#{name},gender=#{gender},image=#{image}," +
      "job=#{job},entrydate=#{entrydate},dept_id=#{deptId},update_time=#{updateTime} where id=#{id}")
     public void update(Emp emp);
}

测试类 

@SpringBootTest
class SpringbootMybatisCrudApplicationTests {

  @Autowired
    private EmpMapper empMapper;
  @Test
  public void testUpdate(){
    Emp emp= new Emp();
    emp.setId(15);
    emp.setUsername("X");
    emp.setName("Xu");
    emp.setImage("1.jpg");
    emp.setGender((short) 1);
    emp.setJob((short) 1);
    emp.setEntrydate(LocalDate.of(2005,6,17));
    emp.setCreateTime(LocalDateTime.now());
    emp.setUpdateTime(LocalDateTime.now());
    emp.setDeptId(1);
    empMapper.update(emp);
  }
}

4.查询操作

接口方法

@Mapper
public interface EmpMapper {

     @Select("select * from emp where id=#{id}")
     public Emp getById(Integer id);
}

测试类 

@SpringBootTest
class SpringbootMybatisCrudApplicationTests {

  @Autowired
    private EmpMapper empMapper;
  @Test
  public void testGetById(){
     Emp emp= empMapper.getById(18);
    System.out.println(emp);
  }
}

打开控制台会发现,查询出的结果,未和数据库属性名统一的接受不到数据 

数据封装

改进措施

1. 

//    方案一:给字段起别名
    @Select("select id, username, password, name, gender, image, job, " +
            "entrydate, dept_id deptId, create_time createTime, update_time updateTime from emp where id=#{id}")
      public Emp getById(Integer id);

2. 

  //方案二:通过@Results和@Result注解手动映射封装
    @Results({
            @Result(column ="dept_id"  ,property = "deptId"),
            @Result(column ="create_time"  ,property = "createTime"),
            @Result(column ="update_time"  ,property = "updateTime")
    })
    @Select("select * from emp where id=#{id}")
    public Emp getById(Integer id);

@Results 和 @Result 注解用于手动定义数据库表字段与 Java 对象属性之间的映射关系。 

column :指定数据库表中的列名。它指明了从数据库中获取数据时所依据的列。

property :指定要将对应列的值映射到的 Java 对象的属性名

通过 @Result 注解中对 column 和 property 的设置,实现了数据库表列与 Java 对象属性之间的精确映射,确保从数据库获取的数据能够正确地赋值给对应的对象属性。

3. 

 //方案三:开启mybaties的驼峰命名自动映射开关
    @Select("select * from emp where id=#{id}")
    public Emp getById(Integer id);

前提,在application.properties里添加按驼峰命名自动映射的开关配置

(打 camel 就能弹出来)

#开启mybaties的驼峰命名自动映射开关
mybatis.configuration.map-underscore-to-camel-case=true
条件查询

TIP

引号内不可以使用 #{},因为是预编译,编译后会变成 ?,SQL语法中引号内不得有占位符?

改成${}拼接占位符可以

也可以用SQL中的concat函数

concat函数

在 MySQL 中,CONCAT 函数用于将多个字符串连接在一起。

其语法为:CONCAT(str1, str2, str3,...) ,它可以接受多个参数,并将这些参数依次连接成一个字符串。

@param注解

在 MyBatis 的映射接口方法中,当一个方法有多个参数时,使用 @Param 注解可以为参数指定一个明确的名称,方便在 SQL 语句中通过指定的名称来引用这些参数。

使用原因:Java编译后,变量名是没有的,会被转化,例如 var1,var2等。所以当有多个参数时候 ,会无法互相识别匹配,用@param注解使得参数名和数据属性名称相关联。

@Select("SELECT * FROM emp WHERE name = #{name}")
Emp getEmpByName(@Param("name") String name);

 @Select("select * from emp where name like concat('%',#{name},'%') and gender=#{gender} and " +
            "entrydate between #{begin} and #{end} order by update_time desc ")
    public List<Emp> list(@Param("name") String name,@Param("gender") Short gender,@Param("begin") LocalDate begin,@Param("end")LocalDate end);
@Test
  public void testList(){
      List<Emp> empList=empMapper.list("张", (short) 1,LocalDate.of(2010,1,1),LocalDate.of(2020,1,1));
      System.out.println(empList);
  }

 MyBatis基础操作 ——通过XML配置

XML配置文件,又叫XML映射文件

 在 MyBatis 中,XML 映射文件(通常以 .xml 为扩展名)用于定义 SQL 语句、结果映射以及其他与数据库操作相关的配置。

  1. 命名空间规范

    • 在 <mapper> 标签中,namespace 属性的值应与对应的接口全限定名一致,以确保 MyBatis 能够正确关联接口方法和 XML 中的操作定义
  2. SQL 语句规范

    • 清晰准确地编写 selectinsertupdate 和 delete 等操作的 SQL 语句。
    • 正确使用参数占位符 #{} 来接收传入的参数,确保参数的类型与实际传递的类型匹配。
  3. 结果映射规范

    • 对于查询操作,通过 resultType 或 resultMap 来定义结果的映射方式。
    • 如果使用 resultMap,则需要在 XML 中单独定义结果映射的规则。

***四个一致

1.映射文件的名称和接口名称一致

2.namespace属性和Mapper接口全限定名一致

3.映射文件中sql语句id和Mapper接口方法名一致

4.查询语句,保证返回类型一致(resultType)

配置 XML过程:

文件名和接口名一致(同包同名),包的结构也要一致 

XML文件所属包结构和接口所处包结构一致

文件名和接口名称一致 

XML文件需要约束,直接去MyBtis中文网上找 ,复制粘贴

 namespace属性和Mapper接口全限定名一致

关于快速获得Mapper接口全限定名

找到mapper接口,右击接口名称,复制引用

 

案例:

XML配置条件查询语句

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.dawn.springbootmybatiscrud.mapper.EmpMapper">
<!--    resultType:单条记录所封装的类型-->
<select id="list" resultType="com.dawn.springbootmybatiscrud.pojo.Emp">
    select * from emp where name like concat('%',#{name},'%') and gender=#{gender} and
            entrydate between #{begin} and #{end} order by update_time desc
</select>
</mapper>

 接口(通过XML中SQL语句的id属性和此方法绑定)

public List<Emp> list(@Param("name") String name,@Param("gender") Short gender,@Param("begin") LocalDate begin,@Param("end")LocalDate end);

MybatisX插件 

MybatisX 是一款针对 IDEA 或相关开发工具的插件,它为 MyBatis 的开发提供了一系列的便利功能。

  1. 快速导航:能够方便地在 Mapper 接口、XML 映射文件和相关的实体类之间进行快速跳转。

  2. 代码生成:可以根据数据库表结构自动生成 MyBatis 的 Mapper 接口、XML 映射文件等代码。

  3. SQL 语句预览:在编写 Mapper 接口中的方法时,实时预览对应的 SQL 语句。

  4. 代码提示和补全:提供丰富的代码提示和自动补全功能,提高开发效率。

  5. 结果集映射预览:帮助开发者直观地了解查询结果与实体类之间的映射关系。

MybatisX 插件能够大大提升 MyBatis 开发的效率和便捷性。

安装后,可以快速导航,点击接口中的小蓝鸟即可快速导航到配置SQL的XML文件中 的小红鸟 

动态SQL

在 MyBatis 中,动态 SQL 是一种强大的特性,它允许您根据不同的条件构建不同的 SQL 语句

动态 SQL 主要通过 <if> 、<choose> 、<when> 、<otherwise> 、<foreach> 等标签来实现。

<if> 

<where> 

<mapper namespace="com.dawn.springbootmybatiscrud.mapper.EmpMapper">
<!--    resultType:单条记录所封装的类型-->
<select id="list" resultType="com.dawn.springbootmybatiscrud.pojo.Emp">
    select * from emp
        <where>
                          <if test="name !=null"> name like concat('%',#{name},'%') </if>
                          <if test="gender != null">and gender=#{gender} </if>
                          <if test="begin!=null and end != null">and entrydate between #{begin} and #{end} </if>
        </where>
                          order by update_time desc
</select>
</mapper>

<set> 

<update id="updateUser">
    UPDATE users
    <set>
        <if test="username!= null">username = #{username}, </if>
        <if test="password!= null">password = #{password}, </if>
    </set>
    WHERE id = #{id}
</update>

<foreach> 

在 MyBatis 中,<foreach> 标签用于遍历集合来构建动态的 SQL 语句,常用于批量操作,如批量插入、批量更新等。

<foreach item="item" index="index" collection="collection" open="(" separator="," close=")">
    <!-- 要重复执行的 SQL 片段 -->
</foreach>

其中:

  • item:表示每次迭代的元素。(遍历出来的元素)
  • index:表示当前迭代的索引。
  • collection:要遍历的集合属性。
  • openseparatorclose:分别指定开始符号、元素之间的分隔符和结束符号。

案例:

<insert id="batchInsertUsers">
    INSERT INTO users (username, password)
    VALUES
    <foreach item="user"  collection="userList" open="(" separator="," close=")">
        (#{user.username}, #{user.password})
    </foreach>
</insert>

<sql>

<include>

二者配合使用

<sql> 标签用于定义可复用的 SQL 片段:

<sql id="userColumns">
    id, username, password
</sql>

<include> 标签用于在其他 SQL 语句中引用上述定义的片段: 

<select id="getUsers">
    SELECT 
    <include refid="userColumns"/> 
    FROM users
</select>

 通过这种方式,可以将常用的 SQL 片段提取出来,避免重复编写,并且当需要修改这些共用部分时,只需在一处修改即可。

 

  • 13
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值