MyBatis是一个优秀的持久化框架,用于简化JDBC的开发。
持久层就是持久化访问的层,就是数据访问层(Dao),用于访问数据库的。
MyBatis使用的准备工作
创建项目,导入mybatis的启动依赖,mysql的驱动包

在pom文件中生成依赖
            
            
              java
              
              
            
          
                  <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>首先我们准备一下数据库的数据

创建user_info表
            
            
              sql
              
              
            
          
          DROP DATABASE IF EXISTS mybatis_test;
 CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
USE mybatis_test;
 
DROP TABLE IF EXISTS user_info;
 CREATE TABLE `user_info` (
 `id` INT ( 11 ) NOT NULL AUTO_INCREMENT,
 `username` VARCHAR ( 127 ) NOT NULL,
 `password` VARCHAR ( 127 ) NOT NULL,
 `age` TINYINT ( 4 ) NOT NULL,
 `gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1
',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0',
 `create_time` DATETIME DEFAULT now(),
 `update_time` DATETIME DEFAULT now() ON UPDATE now(),
 PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
 VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
 INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
 VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
 INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
 VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
 INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
 VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );配置数据库的连接(.yml文件中的配置)

创建数据库表中对应的实体类
            
            
              java
              
              
            
          
          @Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}注:数据库中字段全部都使用小写,单词之间用_来连接,Java中的属性使用小驼峰的方式
注:由于引入了lombok依赖,所以直接使用@Date注解,不需要再去写Getter和Setter方法
创建在持久层的接口,在MyBatis中持久层中的接口一般使用 xxxMapper 的命名方法

我们创建了UserInfoMapper接口

注:@Mapper注解就是表明该接口是MyBatis中的Mapper接口
单元测试
在创建出来的SpringBoot⼯程中,在src下的test⽬录下,已经⾃动帮我们创建好了测试类,我们可以 直接使⽤这个测试类来进⾏测试

单元测试是开发人员进行的测试,与测试人员无关。
进行测试的方法


生成测试类的方法
找到你需要生成测试类的Mapper接口的方法上,右键generate,点击Test


在你需要测试的方法上打 √ ,然后点ok就会自动生成了
MyBatis中的基础操作(注解)
打印日志
只需要在配置文件中配置即可


就可以直接看到sql的执行过程,参数传递,执行结果。
参数的传递
查询对象的方式(select)
id为固定值的时候
            
            
              java
              
              
            
          
          @Select("select * from user_info where id=3")
    List<UserInfo> selectAllById();
            
            
              java
              
              
            
          
          @Test
    void selectAllId() {
        System.out.println(userInfoMapper.selectAllById());
    }id为动态的数值
使用#{}的方式获取方法中的参数
            
            
              java
              
              
            
          
              @Select("select * from user_info where id=#{id}")
    UserInfo selectAllById3(Integer id);
            
            
              java
              
              
            
          
          @Test
    void selectAllById3() {
        System.out.println(userInfoMapper.selectAllById3(1));
    }
传递多个参数
            
            
              java
              
              
            
          
           @Select("select * from user_info where username=#{username} and password=#{password}")
    UserInfo selectAllByUserNameAndPassWord(String username,String password);
            
            
              java
              
              
            
          
           @Test
    void selectAllByUserNameAndPassWord() {
        System.out.println(userInfoMapper.selectAllByUserNameAndPassWord("zhangsan","zhangsan"));
    }
可以使用@Param注解进行参数的绑定(重命名)
            
            
              java
              
              
            
          
          @Select("select * from user_info where username=#{aa} and password=#{bb}")
    UserInfo selectAllByUserNameAndPassWord2(@Param("aa") String username,@Param("bb") String password);
            
            
              java
              
              
            
          
          @Test
    void selectAllByUserNameAndPassWord2() {
        System.out.println(userInfoMapper.selectAllByUserNameAndPassWord2("zhangsan","zhangsan"));
    }
增 (Insert)
            
            
              java
              
              
            
          
          @Insert("insert into user_info (username,password,age) values (#{username},#{password},#{age})")
    Integer insert(UserInfo userInfo);
            
            
              java
              
              
            
          
          @Test
    void insert() {
        UserInfo userInfo=new UserInfo();
        userInfo.setUsername("lisi");
        userInfo.setPassword("lisi");
        userInfo.setAge(1);
        Integer result=userInfoMapper.insert(userInfo);
        System.out.println("新增行数"+result);
    }
返回主键
获得自增Id
            
            
              java
              
              
            
          
          //获取自增Id
    @Options(useGeneratedKeys = true,keyProperty = "id")
    @Insert("insert into user_info (username,password,age) values (#{username},#{password},#{age})")
    Integer insert1(UserInfo userInfo);
            
            
              java
              
              
            
          
          @Test
    void insert1() {
        UserInfo userInfo=new UserInfo();
        userInfo.setUsername("lisi");
        userInfo.setPassword("lisi");
        userInfo.setAge(1);
        Integer result=userInfoMapper.insert1(userInfo);
        System.out.println("新增行数"+result+"Id"+userInfo.getId());
    }
删 (delete)
            
            
              java
              
              
            
          
          @Delete("delete from user_info where id =#{id}")
    Integer deleteUser(Integer id);
            
            
              java
              
              
            
          
          @Test
    void deleteUser() {
        userInfoMapper.deleteUser(13);
    }
改(update)
            
            
              java
              
              
            
          
          @Update("update user_info set delete_flag= #{deleteFlag},phone= #{phone} where id= #{id}")
    Integer updateUser(UserInfo userInfo);
            
            
              java
              
              
            
          
          @Test
    void updateUser() {
        UserInfo userInfo=new UserInfo();
        userInfo.setDeleteFlag(1);
        userInfo.setPhone("123");
        userInfo.setId(11);
        Integer result=userInfoMapper.updateUser(userInfo);
        System.out.println(result);
    }
查询的需要注意的问题
当我们进行查询的时候,我们会发现某些字段是没有进行赋值的,只有Java对象属性和数据库字段⼀模⼀样时,才会进⾏赋值
原因:MyBatis 在执行查询后,会将数据库中的字段值映射(映射 = 赋值)到 Java 实体类对象的属性中。但是,如果 数据库字段名和 Java 对象属性名不一致,MyBatis 默认不会自动进行映射赋值

解决办法:
1.起别名
            
            
              java
              
              
            
          
          @Select("select id, username,`password`, age, gender,  phone, " + 
"delete_flag as deleteFlag, create_time as createTime, update_time as updateTime" + 
" from user_info")2.结果映射
            
            
              java
              
              
            
          
          @Results(id = "BaseMap", value = {
            @Result(column = "delete_flag", property = "deleteFlag"),
            @Result(column = "create_time", property = "createTime"),
            @Result(column = "update_time", property = "updateTime")
    })
@Select("select * from user_info")3.添加驼峰命名的配置文件

设置为true

MyBatis XML配置文件
MyBatis的开发方式一般有两种,注解 & XML
现在我们来学习XML的开发方式
配置mybatis

Spring Boot 集成 MyBatis 时指定 Mapper XML 文件的位置,告诉 MyBatis 去哪里加载 SQL 映射文件
添加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.blame.springmybatis.mapper.UserInfoMapperXML">
    <select id="selectUserAll" resultType="com.blame.springmybatis.model.UserInfo">
        select * from user_info
    </select>
</mapper>

单元测试
            
            
              java
              
              
            
          
          @SpringBootTest
class UserInfoMapperXMLTest {
    @Autowired
    private UserInfoMapperXML userInfoMapperXML;
    @Test
    void selectUserAll() {
        userInfoMapperXML.selectUserAll().stream().forEach(x-> System.out.println(x));
    }
}
XML中的增删改查
增(insert)
            
            
              java
              
              
            
          
           Integer insertUser(UserInfo userInfo);
            
            
              XML
              
              
            
          
           <insert id="insertUser">
        insert into user_info (username, `password`, age) VALUES (#{username}, #{password}, #{age})
    </insert>
            
            
              java
              
              
            
          
          @Test
    void insertUser() {
        UserInfo userInfo=new UserInfo();
        userInfo.setUsername("xiaohei");
        userInfo.setPassword("123");
        userInfo.setAge(11);
        Integer result=userInfoMapperXML.insertUser(userInfo);
        System.out.println("增加行数"+result+"Id"+userInfo.getId());
    }
使用@Param注解进行重命名
            
            
              java
              
              
            
          
          Integer insertUser2(@Param("UserInfo") UserInfo userInfo);
            
            
              java
              
              
            
          
          <insert id="insertUser2">
        insert into user_Info (username, `password`, age) VALUES (#{username}, #{password}, #{age})
    </insert>
            
            
              java
              
              
            
          
          @Test
    void insertUser2() {
        UserInfo userInfo=new UserInfo();
        userInfo.setUsername("hei");
        userInfo.setPassword("15");
        userInfo.setAge(13);
        Integer result=userInfoMapperXML.insertUser(userInfo);
        System.out.println("增加行数"+result+"Id"+userInfo.getId());
    }
自增Id
            
            
              XML
              
              
            
          
          <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
 insert into user_info (username, `password`, age, gender, phone) values
 (#{userInfo.username},#{userInfo.password},#{userInfo.age},#
 {userInfo.gender},#{userInfo.phone})
 </insert>删(delete)
            
            
              java
              
              
            
          
          Integer deleteUser(Integer id);
            
            
              XML
              
              
            
          
          <delete id="deleteUser">
        delete from user_info where id =#{id}
    </delete>
            
            
              java
              
              
            
          
             @Test
    void deleteUser() {
        userInfoMapperXML.deleteUser(16);
    }
改(update)
            
            
              XML
              
              
            
          
          <update id="updateUser">
        update user_info set  password= #{password} , age=#{age} where id= #{id}
    </update>
            
            
              java
              
              
            
          
          Integer updateUser(String password,Integer age,Integer id);
            
            
              java
              
              
            
          
          @Test
    void updateUser() {
        UserInfo userInfo=new UserInfo();
        Integer result=userInfoMapperXML.updateUser("123",88,9);
    }
查(select)
            
            
              java
              
              
            
          
          List<UserInfo> selectUserAll();
            
            
              XML
              
              
            
          
          <select id="selectUserAll" resultType="com.blame.springmybatis.model.UserInfo">
        select * from user_info
    </select>其他查询
联合查询(多表查询)
在数据库中导入表
            
            
              sql
              
              
            
          
          DROP TABLE IF EXISTS articleinfo;
CREATE TABLE articleinfo (
 id INT PRIMARY KEY auto_increment,
 title VARCHAR ( 100 ) NOT NULL,
 content TEXT NOT NULL,
 uid INT NOT NULL,
 delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT,
 create_time DATETIME DEFAULT now(),
 update_time DATETIME DEFAULT now() 
) DEFAULT charset 'utf8mb4';
 INSERT INTO articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正⽂', 1 );配置对应的实体类
            
            
              java
              
              
            
          
          @Data
public class ArticleInfo {
    private Integer id;
    private String title;
    private String content;
    private Integer uid;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
    private String username;
    private Integer age;
}定义接口
            
            
              java
              
              
            
          
          @Mapper
public interface ArticleInfoMapper {
    ArticleInfo selectArticleById(Integer id);
}配置 .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.blame.springmybatis.mapper.ArticleInfoMapper">
    <select id="selectArticleById" resultType="com.blame.springmybatis.model.ArticleInfo">
        select ta.*,tb.username,tb.age from article_info ta left 
join user_info tb on ta.uid = tb.id where ta.id=#{id}
    </select>
</mapper>测试类
            
            
              java
              
              
            
          
          @SpringBootTest
class ArticleInfoMapperTest {
    @Autowired
    private ArticleInfoMapper articleInfoMapper;
    @Test
    void selectArticleById() {
        articleInfoMapper.selectArticleById(1);
    }
}
#{ }和${ }
这是mybatis中非常重要的两个占位符
首先我们看一下#{}
            
            
              java
              
              
            
          
          @Select("select username,`password`,age,gender,phone from user_info where id=#{id}")
    UserInfo queryById(Integer id);
            
            
              java
              
              
            
          
          @Test
    void queryById() {
        System.out.println(userInfoMapper.queryById(2));
    }
通过观察我们的sql语句,我们发现我们输入的参数 2 ,并没有在语句后面显示,而是用 ? ,我们把这种叫做预编译SQL
我们再观察一下${}
            
            
              java
              
              
            
          
              @Select("select username,`password`,age,gender,phone from user_info where id=${id}")
    UserInfo queryById2(Integer id);
            
            
              java
              
              
            
          
          @Test
    void queryById2() {
        System.out.println(userInfoMapper.queryById2(2));
    }
我们可以发现参数直接是拼在SQL语句中了
我们再把参数换成String类型
            
            
              java
              
              
            
          
          @Select("select username,`password`,age,gender,phone from user_info where username=#{username}")
    UserInfo queryById3(String username);
@Select("select username,`password`,age,gender,phone from user_info where username=${username}")
    UserInfo queryById4(String username);
            
            
              java
              
              
            
          
          @Test
    void queryById3() {
        System.out.println(userInfoMapper.queryById3("zhangsan"));
    }
    @Test
    void queryById4() {
        System.out.println(userInfoMapper.queryById4("zhangsan"));
    }我们先来看一下#{}的测试结果

再看一下${}的测试结果


我们发现报错了,说SQL语法异常
这次的参数是直接拼在SQL语句的后面,没有自动给username添加 ' '
修改后,测试成功
            
            
              java
              
              
            
          
           @Select("select username,`password`,age,gender,phone from user_info where username='${username}'")
    UserInfo queryById4(String username);
通过上面这个例子,我们可以发现#{}使用的是预编译SQL,通过?进行占位,提前对SQL进行编译,将参数填充到SQL语句中,#{}会根据参数类型,自动拼接引号 ' '
${}会直接进行字符的替换,一起对SQL进行编译,如果是字符串,得加上引号' '
SQL语句的执行流程
1.语法解析 2.SQL优化 3.SQL编译 4.SQL执行
#{} 和${}区别
#{}的性能更高
${}会出现SQL注入的风险
SQL注入:是通过操作输⼊的数据来修改事先定义好的SQL语句,以达到执⾏代码对服务器进⾏攻击的 ⽅法
SQL注入的代码演示
            
            
              java
              
              
            
          
          @Select("select username, `password`, age, gender, phone from user_info where username= '${name}' ")
            List<UserInfo> queryByName(String name);
            
            
              java
              
              
            
          
          @Test
    void queryByName() {
        List<UserInfo> userInfos = userInfoMapper.queryByName("admin");
        System.out.println(userInfos);
    } 测试成功
 测试成功
但是,如果我们参数传为以下的情况,我们发现不仅没有报错,而且得到了我们表中的全部信息,这就是SQL注入
            
            
              java
              
              
            
          
          @Test
    void queryByName() {
        List<UserInfo> userInfos = userInfoMapper.queryByName("' or 1='1");
        System.out.println(userInfos);
    }
排序功能
当我们表中数据按Id逆序进行排序,发现${}排序成功
            
            
              java
              
              
            
          
           @Select("select id, username, age, gender, phone, delete_flag, create_time,update_time " +
            "from user_info order by id ${sort} ")
    List<UserInfo> queryAllUserBySort(String sort);
            
            
              java
              
              
            
          
          @Test
    void queryAllUserBySort() {
        System.out.println(userInfoMapper.queryAllUserBySort("desc"));
    }
但我们发现#{} 没有成功,进行了报错。
            
            
              java
              
              
            
          
          @Select("select id, username, age, gender, phone, delete_flag, create_time,update_time " +
            "from user_info order by id #{sort} ")
    List<UserInfo> queryAllUserBySort2(String sort);SQL语法错误异常

可以发现,当使⽤ #{sort} 查询时,asc前后⾃动给加了引号,导致sql错误

like的使用
            
            
              java
              
              
            
          
           @Select("select id, username, age, gender, phone, delete_flag, create_time, 
update_time " +
 "from user_info where username like '%#{key}%' ")
 List<UserInfo> queryAllUserByLike(String key);这里 '%#{key}%' 是错误写法,因为 #{} 在 MyBatis 中是 参数占位符,它不会在 SQL 字符串内部被当作字符串拼接,而是被替换成 ?
我们可以使用从concat()
            
            
              java
              
              
            
          
          @Select("select id, username, age, gender, phone, delete_flag, create_time, 
update_time " +
 "from user_info where username like concat('%',#{key},'%')")
 List<UserInfo> queryAllUserByLike(String key);数据库连接池
预先创建好的一批数据库连接,当应用程序要访问数据库时,从池中获取连接,操作完成后再归还,而不是每次都重新建立和关闭连接

常用的的数据连接池
HikariCP(Spring Boot默认):性能最快、轻量
Druid(阿里巴巴):功能丰富、监控强大
C3P0 :比较落后
DBCP :使用少

切换数据库连接池
如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要引⼊相关依赖即可
            
            
              java
              
              
            
          
          <dependency>
 <groupId>com.alibaba</groupId>
 <artifactId>druid-spring-boot-3-starter</artifactId>
 <version>1.2.21</version>
 </dependency>希望能对大家有所帮助!!!!!
