Mybatis自学完整笔记

有时候,不是因为你没有能力,也不是因为你缺少勇气,只是因为你付出的努力还太少,所以,成功便不会走向你。而你所需要做的,就是坚定你的梦想,你的目标,你的未来,然后以不达目的誓不罢休的那股劲,去付出你的努力,成功就会慢慢向你靠近。

导读:本篇文章讲解 Mybatis自学完整笔记,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

学习视频:
【狂神说Java】Mybatis最新完整教程IDEA版通俗易懂

Mybatis

1、简介

1.1、什么是Mybatis

在这里插入图片描述

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了[google code](https://baike.baidu.com/item/google code/2346604),并且改名为MyBatis 。2013年11月迁移到Github

1.2、如何获取Mybatis

  1. maven:

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.7</version>
    </dependency>
    
  2. 中文文档:https://mybatis.org/mybatis-3/zh/index.html

  3. Github:https://github.com/mybatis/mybatis-3

1.3、为什么需要Mybatis

  1. 帮助程序员操作数据库中的数据
  2. 方便
  3. 简化传统的JDBC代码,自动化
  4. 更容易上手
  5. 使用的人多

优点

  • 简单易学
  • 灵活
  • sql和代码的分离,提高了可维护性
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql

2、第一个Mybatis程序

思路:搭建环境——导入Mybatis——编写代码——测试

2.1、搭建环境

  1. 搭建数据库
CREATE DATABASE `mybatis`

USE `mybatis`;
CREATE TABLE `user`(
`id` INT NUO NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(20) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=UTF8;

INSERT INTO `user` (id,name,pwd) VALUES('1','张三','123465'),('2','李四','123465'),('3','王五','123465')
  1. 创建一个普通的Maven项目

  2. 删除src目录(将此项目当作父工程)

  3. 导入maven依赖

    <dependencies>
        <!--导入Myabtis依赖-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--导入Mysql依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <!--导入Junit依赖-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
    

2.2、运行

  1. 创建一个Mybatis工程模块

  2. 编写mybatis核心配置文件mybaitis-config.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?urlSSL=true&amp;useEncoding=true&amp;characterEncoding=utf-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
    </configuration>
    
  3. 编写静态数据类构建 SqlSessionFactory

    public class MybatisUtils {
        static SqlSessionFactory sqlSessionFactory = null;
        static {
            String resource = "mybatis-config.xml";
            InputStream inputStream = null;
            try {
                inputStream = Resources.getResourceAsStream(resource);
            } catch (IOException e) {
                e.printStackTrace();
            }
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
    
        public static SqlSession getSqlSession(){
            return sqlSessionFactory.openSession();
        }
    }
    
  4. 编写实体类

    package com.teng.entity;
    
    public class User {
        private int id;
        private String name;
        private String pwd;
    
        public User() {
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", pwd='" + pwd + '\'' +
                    '}';
        }
    
        public User(int id, String name, String pwd) {
            this.id = id;
            this.name = name;
            this.pwd = pwd;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getPwd() {
            return pwd;
        }
    
        public void setPwd(String pwd) {
            this.pwd = pwd;
        }
    }
    
    
  5. 编写接口和接口实现类(在mybatis中接口实现类转变为Mapper配置文件)

    UserMapper.java

    public interface UserMapper {
        public List<User> getUserList();
    }
    

    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">
    <!--
    namespace:绑定一个指定的Dao/Mapper接口
    id:接口中对应的方法名称
    resultType:返回结果的类型,如果是类则需要全路径
    -->
    <mapper namespace="com.teng.Dao.UserMapper">
    <select id="getUserList" resultType="com.teng.entity.User">
            select * from user
        </select>
    </mapper>
    
  6. 注册Mapper

    在mybatis-config.xml中添加如下代码

    <!--注册Mapper-->
        <mappers>
            <mapper class="com/teng/dao/UserMapper.xml"/>
    	</mappers>
    
    ?urlSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8
    ?userSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8
    
  7. 编写测试类

@Test
public void test(){

    //1.获取SqlSession对象
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    //2.执行SQL
    // 方式一:getMapper
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = userMapper.getUserList();
    for (User user : userList) {
        System.out.println(user.toString());
    }

    //关闭sqlSession
    sqlSession.close();
}

在这里插入图片描述

2.3、可能遇到的问题

1、

无法找到mybatis-config.xml配置文件,一般是你构建SqlSessionFactory时的resource赋值路径错了


在这里插入图片描述

2、

org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserMapper is not known to the MapperRegistry.

无法读取到UserMapper.xml文件,默认只读取java后缀的文件

maven由于他的约定大于配置,写的配置文件无法被导出或者生效的问题,解决方案:

<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

3、CRUD

3.1、CRUD

namespace中的包名要和Dao/Mapper接口的包名一致

在UserMapper.xml中:

  • id:就是对应的namespace中的方法名;

  • resultType : Sql语句执行的返回值;

  • parameterType : 参数类型;

具体实现:

UserMapper.java

    //根据用户ID查询用户信息
    User getUserByID(int id);

    //插入一个用户
    int addUser(User user);

    //修改用户
    int updateUser(User user);

    //删除用户
    int delUser(int id);

UserMapper.xml

<select id="getUserByID" parameterType="int" resultType="com.teng.entity.User">
        select * from user where id = #{id}
    </select>
    
    <insert id="addUser" parameterType="com.teng.entity.User">
        insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
    </insert>

    <update id="updateUser" parameterType="com.teng.entity.User">
        update user set name=#{name},pwd=#{pwd} where id=#{id};
    </update>

    <delete id="delUser" parameterType="int">
        delete from user where id = #{id}
    </delete>

测试类

@Test
public void test02(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User userByID = userMapper.getUserByID(1);
    System.out.println(userByID.toString());

    sqlSession.close();;
}

@Test
public void test03(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.addUser(new User(4, "小四", "123456"));
    //增删改必须要提交事务
    sqlSession.commit();
    sqlSession.close();
}

@Test
public void test04(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.updateUser(new User(4, "小六六", "666666"));

    sqlSession.commit();
    sqlSession.close();
}

@Test
public void test05(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.delUser(4);

    sqlSession.commit();
    sqlSession.close();
}

注意:增删改操作时需要提交事务


3.2、巧妙使用Map集合

当我们的实体类,或者数据库中的表,字段或者参数过多,我们应该考虑使用Map

//插入一个用户
    int addUser1(Map<String,String> map);
<insert id="addUser1" parameterType="Map">
    insert into user (id,name,pwd) values (#{id},#{name},#{pwd})
    <!--此处的id、name、pwd可以自定义!-->
</insert>
@Test
    public void test06(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, String> hashMap = new HashMap<String, String>();
        //此处的key值需要和上面的自定义匹配!
        userMapper.ad
        hashMap.put("id","4");
        hashMap.put("name","王四");
        hashMap.put("pwd","123456");dUser1(hashMap);
        sqlSession.commit();
        sqlSession.close();
    }
  • Map传递参数,直接在sql中取出key即可【parameter=“map”】

  • 对象传递参数,直接在sql中取出对象的属性即可【parameter=“Object”】

  • 只有一个基本类型参数的情况下,可以直接在sql中取到

  • 多个参数用Map , 或者注解

3.3、模糊查询

当前数据库user表内容

在这里插入图片描述

执行代码:

//根据用户名称查询用户信息
List<User> getUserByName(String name);
<select id="getUserByName" parameterType="String" resultType="com.teng.entity.User">
        select * from user where name like "%" #{name} "%"
</select>
@Test
public void test07(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> userByName = userMapper.getUserByName("王");
    for (User user : userByName) {
        System.out.println(user.toString());
    }

    sqlSession.close();;
}

查询结果:

在这里插入图片描述


注意:

​ 至于为什么是在SQL语句中直接写死“%”#{name}“%”,而不是在测试类中使用“%王%”,需要注意SQL注入问题(Sql 注入攻击是通过将恶意的 Sql 查询或添加语句插入到应用的输入参数中,再在后台 Sql 服务器上解析执行进行的攻击,它目前黑客对数据库进行攻击的最常用手段之一。)

4、配置解析

Mybatis的配置文件包含了会深深影响MyBatis行为的设置(setting)和属性(properties)信息

4.1、核心配置

mybatis-config.xml

configuration(配置)
	properties(属性)
	settings(设置)
	typeAliases(类型别名)
	typeHandlers(类型处理器)
	objectFactory(对象工厂)
	plugins(插件)
	environments(环境配置)
		environment(环境变量)
			transactionManager(事务管理器)
			dataSource(数据源)
	databaseIdProvider(数据库厂商标识)
	mappers(映射器)

4.2、配置环境

  1. MyBatis 可以配置成适应多种环境

    不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境

  2. 学会使用配置多套运行环境

  3. MyBatis默认的事务管理器就是JDBC ,连接池:POOLED

4.3、属性properties

可以通过properties属性来实现引用配置文件

  1. 编写一个配置文件:db.properties

    driver=com.mysql.cj.jdbc.Driver
    url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8
    username=root
    password=123456
    
  2. 在核心配置文件中引入

    <properties resource="db.properties"/>
    <!--或者使用下面这种方式增加其中一些属性配置-->
    <properties resource="db.properties">
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </properties>
    

    注意:在使用下面的方式时,如果两个文件中有同一个字段,有限使用外部配置文件的字段

4.4、类型别名typeAliases

  • 类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置

  • 意在降低冗余的全限定类名书写

    <!--可以给实体类起别名-->
    <typeAliases>
        <typeAlias type="com.kuang.pojo.User" alias="User"/>
    </typeAliases>
    

    也可以指定一个包,每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author,;若有注解,则别名为其注解值。见下面的例子:

    <typeAliases>
        <package name="com.kuang.pojo"/>
    </typeAliases>
    

    一般情况下,在实体类比较少的时候使用第一种方式,在实体类比较多的时候是使用第二种方式,其中:第一种可以DIY别名,第二种不行,如果非要改则需要在实体上增加注解!

    @Alias("author")
    public class Author {
        ...
    }
    

4.5、 设置 Settings

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

主要掌握:

在这里插入图片描述

在这里插入图片描述

4.6、其它配置

4.7、映射器 mappers

MapperRegistry:注册绑定我们的Mapper文件;

方式一:【推荐使用】

<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
    <mapper resource="com/kuang/dao/UserMapper.xml"/>
</mappers>

方式二:使用class文件绑定注册

<!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-->
<mappers>
    <mapper class="com.kuang.dao.UserMapper"/>
</mappers>

​ 注意点:

  • 接口和他的Mapper配置文件必须同名
  • 接口和他的Mapper配置文件必须在同一个包下

方式三:使用包扫描进行注入

<mappers>
    <package name="com.kuang.dao"/>
</mappers>

4.8、作用域和生命周期

在这里插入图片描述

声明周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。

  1. SqlSessionFactoryBuilder:
  • 一旦创建了SqlSessionFactory,就不再需要它了
  • 局部变量
  1. SqlSessionFactory:
  • 说白了就可以想象为:数据库连接池
  • SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建一个实例。
  • 因此SqlSessionFactory的最佳作用域是应用作用域(ApplocationContext)。
  • 最简单的就是使用单例模式或静态单例模式。
  1. SqlSession:
  • 连接到连接池的一个请求
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用!

在这里插入图片描述

4.9、解决属性名称和字段名不一致问题

数据库字段
在这里插入图片描述

属性名
在这里插入图片描述

解决方法:

  1. 起别名

    // select * from user where id = #{id}
    // 类型处理器
    // select id,name,pwd from user where id = #{id}
    <select id="getUserById" resultType="com.teng.entity.User">
        select id,name,pwd as password from USER where id = #{id}
    </select>
    
  2. 使用resultMap结果集

    <!--结果集映射-->
    <resultMap id="UserMap" type="User">
        <!--column数据库中的字段,property实体类中的属性-->
        <result column="id" property="id"></result>
        <result column="name" property="name"></result>
        <result column="pwd" property="password"></result>
    </resultMap>
    
    <select id="getUserList" resultMap="UserMap">
        select * from USER
    </select>
    
  • resultMap 元素是 MyBatis 中最重要最强大的元素

  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了

  • ResultMap 的优秀之处——你完全可以不用显式地配置它们

5、日志

5.1、日志工厂

设置名:logImpl

设置值:

  • SLF4J
  • LOG4J 【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING 【掌握】
  • NO_LOGGING

具体在Mybatis中使用哪一个日志,需要在setting中进行设定

STDOUT_LOGGING

<settings>
	<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

添加前后控制台输出对比:
在这里插入图片描述

在这里插入图片描述

5.2、log4j

  1. 什么是log4j?
  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件;
  • 我们也可以控制每一条日志的输出格式;
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程;
  • 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
  1. log4j的使用

    先导入log4j的依赖

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    

    创建log4j.properties配置文件

    #将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
    log4j.rootLogger=DEBUG,console,file
    ​
    #控制台输出的相关设置
    log4j.appender.console = org.apache.log4j.ConsoleAppender
    log4j.appender.console.Target = System.out
    log4j.appender.console.Threshold=DEBUG
    log4j.appender.console.layout = org.apache.log4j.PatternLayout
    log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
    #文件输出的相关设置
    log4j.appender.file = org.apache.log4j.RollingFileAppender
    log4j.appender.file.File=./log/rzp.log
    log4j.appender.file.MaxFileSize=10mb
    log4j.appender.file.Threshold=DEBUG
    log4j.appender.file.layout=org.apache.log4j.PatternLayout
    log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
    #日志输出级别
    log4j.logger.org.mybatis=DEBUG
    log4j.logger.java.sql=DEBUG
    log4j.logger.java.sql.Statement=DEBUG
    log4j.logger.java.sql.ResultSet=DEBUG
    log4j.logger.java.sq1.PreparedStatement=DEBUG
    

    配置settings为log4j实现

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    

    测试

在这里插入图片描述

log4j的简单使用:

  1. 创建对象

    //注意导包为:import org.apache.log4j.Logger;
    static Logger logger = Logger.getLogger(UserMapperTest.class);
    
  2. 测试

    @Test
    public void testLog4j(){
        logger.info("Info:进入testLog4j");
        logger.debug("Debug:进入testLog4j");
        logger.error("Error:进入testLog4j");
    }
    
  3. 结果
    在这里插入图片描述
    在这里插入图片描述

6、分页

6.1、使用limit进行分页

SQL语句:

select * from user limit [startIndex],[pageSize]
  1. 接口

    //limit分页查询
        List<User> getUserByLimit(Map<String,Integer> map);
    
  2. Mapper.xml

    <select id="getUserByLimit" parameterType="map" resultType="User">
        select * from user limit #{startIndex},#{pageSize}
    </select>
    
  3. 测试

    @Test
    public void getUserBylimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    
        HashMap<String, Integer> hashMap = new HashMap<String, Integer>();
        hashMap.put("startIndex",1);
        hashMap.put("pageSize",2);
    
        List<User> userByLimit = userMapper.getUserByLimit(hashMap);
        for (User user : userByLimit) {
            System.out.println(user.toString());
        }
    
        sqlSession.close();
    }
    
  4. 输出结果

在这里插入图片描述

6.2、RowBounds实现分页

  1. 接口

    //RowBounds分页查询
        List<User> getUserByRowBounds();
    
  2. Mapper.xml

    <select id="getUserByRowBounds" resultType="User">
        select * from user
    </select>
    
  3. 测试

    @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        RowBounds rowBounds = new RowBounds(1, 2);
        //在代码层面实现分页处理
        List<User> selectList = sqlSession.selectList("com.teng.dao.UserMapper.getUserByRowBounds", null, rowBounds);
        for (User user : selectList) {
            System.out.println(user.toString());
        }
    
        sqlSession.close();
    }
    
  4. 输出结果

在这里插入图片描述

6.3、PageHelper分页插件

MyBatis 分页插件 PageHelper

在这里插入图片描述

7、使用注解开发

7.1、面向接口开发

三个面向区别

  • 面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性和方法;
  • 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现;
  • 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题,更多的体现就是对系统整体的架构;

7.2、使用注解开发

  1. 编写接口

    //查询所有用户
    @Select("select * from user")
    List<User> getUserList();
    
  2. 注册Mapper

    <mappers>
        <mapper class="com.teng.dao.UserMapper"/>
    </mappers>
    
  3. 测试

    @Test
    public void getUserList(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user.toString());
        }
        sqlSession.close();
    }
    
  4. 测试结果

在这里插入图片描述

本质:反射机制实现

底层:动态代理

7.3、注解实现CRUD

可以在工具类中设置自动提交事物

public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession(true);
}
  1. 接口

    //增加用户
    @Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
    int insertUser(@Param("id") int id, @Param("name") String name, @Param("pwd") String pwd);
    
    //查询用户
    @Select("select * from user where id = #{id}")
    User getUserByID(@Param("id") int id);
    
    //修改用户
    @Update("update user set name = #{name} ,pwd = #{pwd} where id = #{id}")
    int updateUserByID(@Param("name") String name, @Param("pwd") String pwd, @Param("id") int id);
    
    //删除用户
    @Delete("delete from user where id = #{id}")
    int deleteUserByID(@Param("id") int id);
    
  2. 测试

    //增加用户
    @Test
    public void insertUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.insertUser(5,"小五","123456");
        sqlSession.close();
    }
    
    //查询用户
    @Test
    public void getUserByID(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User userByID = userMapper.getUserByID(5);
        System.out.println(userByID);
        sqlSession.close();
    }
    
    //修改用户
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.updateUserByID("小五","111111",5);
        sqlSession.close();
    }
    
    //删除用户
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.deleteUserByID(5);
        sqlSession.close();
    }
    
  3. 测试结果


关于@Param( )注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
  • 我们在SQL中引用的就是我们这里的@Param()中设定的属性名

#{}和${}的区别:

  1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”.
  2. $将传入的数据直接显示生成在sql中。如:orderby将传入的数据直接显示生成在sql中。如:order by user_id $,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
  3. #方式能够很大程度防止sql注入。
  4. $方式无法防止Sql注入。
  5. $方式一般用于传入数据库对象,例如传入表名.
  6. 一般能用#的就别用$.

MyBatis排序时使用order by 动态参数时需要注意,用$而不是#

8、Lombok

  1. 什么是Lombok

    Lombok是一款Java开发插件,可以通过它定义的注解来精简冗长和繁琐的代码,主要针对简单的Java模型对象(POJO)。

    好处就显而易见了,可以节省大量重复工作,特别是当POJO类的属性增减时,需要重复修改的Getter/Setter、构造器方法、equals方法和toString方法等。

    而且Lombok针对这些内容的处理是在编译期,而不是通过反射机制,这样的好处是并不会降低系统的性能。

  2. Lombok的安装

    1. 在IDEA的插件配置中搜索Lombok安装

在这里插入图片描述

  1. 添加Maven依赖

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.20</version>
    </dependency>
    
  2. 使用

    @Data//无参构造、get/set方法、equals()、hashCode()、toString()
    @AllArgsConstructor//有参构造
    @NoArgsConstructor//无参构造
    public class User {
        private int id;
        private String name;
        private String password;
    }
    
  3. 效果

在这里插入图片描述

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
@ExtensionMethod (Experimental, activate manually in plugin settings)

9、多对一处理

数据库搭建

CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO teacher(`id`, `name`) VALUES (1, 梁老师); 
INSERT INTO teacher(`id`, `name`) VALUES (2, 胡老师); 

CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8INSERT
INTO `student` (`id`, `name`, `tid`) VALUES (1, 小明, 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, 小红, 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, 小张, 2); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, 小李, 1); 
INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, 小王, 2);

其中:

​ 对于学生而言:几个学生归同一个老师管——>多对一

​ 对于老师而言:一个老师管几个学生——>一对多

9.1、 测试环境搭建

  1. 导入lombok

  2. 新建实体类Teacher,Student

    //Student
    @Data
    public class Student {
        private int id;
        private String name;
        private Teacher teacher;
    }
    
    //Teacher
    @Data
    public class Teacher {
        private int id;
        private String name;
    }
    
  3. 建立Mapper接口

  4. 建立Mapper.xml文件

  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件 【方式很多,随心选】

  6. 测试查询是否能够成功

9.2、按照查询嵌套处理

<!--
思路:
	1. 查询所有的学生信息
    2. 根据查询出来的学生的tid寻找特定的老师 (子查询)
-->
<select id="getStudent" resultMap="StudentTeacher">
    select * from student
</select>
<resultMap id="StudentTeacher" type="student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <!--复杂的属性,我们需要单独出来 对象:association 集合:collection-->
    <collection property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
</resultMap>
<select id="getTeacher" resultType="teacher">
    select * from teacher where id = #{id}
</select>

9.3、按照结果嵌套处理

<!--按照结果进行查询-->
<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid , s.name sname, t.name tname
    from student s,teacher t
    where s.tid=t.id
</select>
<!--结果封装,将查询出来的列封装到对象属性中-->
<resultMap id="StudentTeacher2" type="student">
    <result property="id" column="sid"/>
    <result property="name" column="sname"/>
    <association property="teacher" javaType="teacher">
        <result property="name" column="tname"/>
    </association>
</resultMap>

回顾Mysql多对一查询方式:

  • 子查询 (按照查询嵌套)
  • 联表查询 (按照结果嵌套)

10、一对多处理

10.1、环境搭建

  1. 导入lombok

  2. 新建实体类Teacher,Student

    //Student
    @Data
    public class Student {
        private int id;
        private String name;
        private int tid;
    }
    
    //Teacher
    @Data
    public class Teacher {
        private int id;
        private String name;
        private List<Student> student;
    }
    
  3. 建立Mapper接口

  4. 建立Mapper.xml文件

  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件 【方式很多,随心选】

  6. 测试查询是否能够成功

10.2、按照结果嵌套处理

<select id="getTeacherList1" resultMap="teacherMap">
    select t.id as tid, t.name as tname, s.id as sid, s.name as sname
    from teacher t, student s
    where t.id = s.tid and t.id = #{id}
</select>
<resultMap id="teacherMap" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <collection property="student" ofType="student">
        <result property="id" column="sid"/>
        <result property="name" column="tname"/>
    </collection>
</resultMap>

11、小结

  1. 关联 – association 【多对一】
  2. 集合 – collection 【一对多】
  3. javaType & ofType
    1. JavaType用来指定实体类中的类型
    2. ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一,属性名和字段的问题
  • 如果问题不好排查错误,可以使用日志,建议使用Log4j

面试高频

  • Mysql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

12、动态SQL

什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

所谓的动态SQL,本质上还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

准备数据库:

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT 博客id,
`title` VARCHAR(100) NOT NULL COMMENT 博客标题,
`author` VARCHAR(30) NOT NULL COMMENT 博客作者,
`create_time` DATETIME NOT NULL COMMENT 创建时间,
`views` INT(30) NOT NULL COMMENT 浏览量
)ENGINE=INNODB DEFAULT CHARSET=utf8

12.1、搭建环境

创建一个子工程

  1. 导包

  2. 编写配置文件

  3. 编写实体类

    @Data
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;//此字段与数据库中的字段不一致,需要在配置文件中配置mapUnderscoreToCamelCase为true
        private int views;
    }
    
  4. 编写实体类对应Mapper接口和Mapper.xml文件

  5. 增加一个生成ID的类

    public class IDutils {
        public static String getID(){
            return UUID.randomUUID().toString().replace("-","");
        }
    }
    
  6. 插入数据

    <mapper namespace="com.teng.dao.BlogMapper">
        <insert id="addBlog" parameterType="blog">
            insert into blog (id,title,author,create_time,views)
            values (#{id},#{title},#{author},#{createTime},#{views});
        </insert>
    </mapper>
    
        @org.junit.Test
        public void addInitBlog(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    
            Blog blog = new Blog();
            blog.setId(IDutils.getID());
            blog.setTitle("Mybatis如此简单!");
            blog.setAuthor("小梁");
            blog.setCreateTime(new Date());
            blog.setViews(9999);
            blogMapper.addBlog(blog);
    
            blog.setId(IDutils.getID());
            blog.setTitle("Spring如此简单!");
            blogMapper.addBlog(blog);
    
            blog.setId(IDutils.getID());
            blog.setTitle("SpringMVC如此简单!");
            blogMapper.addBlog(blog);
    
            blog.setId(IDutils.getID());
            blog.setTitle("微服务如此简单!");
            blogMapper.addBlog(blog);
    
            sqlSession.close();
        }
    

12.1、if

  1. 接口

    //查询指定要求的blog
    List<Blog> queryBlog(Map map);
    
  2. BlogMapper.xml

    <select id="queryBlog" parameterType="map" resultType="blog">
        select * from blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </select>
    
    <!--其中的 where 1=1 不规范,此时需要进行优化-->
    <select id="queryBlog" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>
    
  3. 测试

    @org.junit.Test
        public void queryBlog(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap<String, String> hashMap = new HashMap<String, String>();
        hashMap.put("title","Mybatis如此简单!");
        //        hashMap.put("author","小梁");
        List<Blog> blogs = mapper.queryBlog(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }
    
  4. 测试结果

在这里插入图片描述

12.2、choose, when, otherwise

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <choose>
            <when test="title != null"> title=#{title}</when>
            <when test="author != null"> author=#{author}</when>
            <!--
                还可以设定一个otherwise:如果上面两个条件都不走,则走otherwise
                比如:<otherwise> id=#{id}</otherwise>
                -->
        </choose>
    </where>
</select>

12.3、set

//修改字段名
int updateBlog(Map map);
<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <if test="title!=null">title=#{title}</if>
        <if test="author!=null">author=#{author}</if>
    </set>
    where id = #{id}
</update>
@org.junit.Test
public void updateBlog(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    HashMap<String,String> hashMap = new HashMap<String,String>();
    hashMap.put("id","208f88df984f43d380ab8beef41c9743");
    hashMap.put("title","SpringMVC真的简单吗?");
    blogMapper.updateBlog(hashMap);
    sqlSession.close();
}

在这里插入图片描述

12.4、trim

mybatis的trim标签一般用于去除sql语句中多余的and关键字,逗号,或者给sql语句前拼接 “where“、“set“以及“values(“ 等前缀,或者添加“)“等后缀,可用于选择性插入、更新、删除或者条件查询等操作。

属性 描述
prefix 给sql语句拼接的前缀
suffix 给sql语句拼接的后缀
prefixOverrides 去除sql语句前面的关键字或者字符,该关键字或者字符由prefixOverrides属性指定,假设该属性指定为”AND”,当sql语句的开头为”AND”,trim标签将会去除该”AND”
suffixOverrides 去除sql语句后面的关键字或者字符,该关键字或者字符由suffixOverrides属性指定

实例:

<select id="queryBlog" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <if test="title != null">
        and title = #{title}
    </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </where>
</select>
<!--
相当于SQL拼接前缀为where(prefix="where"),去除sql语句前面的关键字或者字符and(prefixOverrides="and")
具体如下所示
-->
<select id="queryBlog" parameterType="map" resultType="blog">
    select * from blog
    <trim prefix="where" prefixOverrides="and">
        <if test="title != null">
        and title = #{title}
    </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </trim>
</select>

12.5、foreach

mybatis的foreach标签经常用于遍历集合,构建in条件语句或者批量操作语句

属性 描述
collection 表示迭代集合的名称,可以使用@Param注解指定
item 表示本次迭代获取的元素,若collection为List、Set或者数组,则表示其中的元素;若collection为map,则代表key-value的value,该参数为必选
open 表示该语句以什么开始,最常用的是左括弧’(’,注意:mybatis会将该字符拼接到整体的sql语句之前,并且只拼接一次,该参数为可选项
close 表示该语句以什么结束,最常用的是右括弧’)’,注意:mybatis会将该字符拼接到整体的sql语句之后,该参数为可选项
separator mybatis会在每次迭代后给sql语句append上separator属性指定的字符,该参数为可选项
index 在list、Set和数组中,index表示当前迭代的位置,在map中,index代指是元素的key,该参数是可选项

测试:

<select id="queryBlogByID" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <foreach collection="ids" open="(" item="id" close=")" separator="or">
            id=#{id}
        </foreach>
    </where>
</select>
@org.junit.Test
public void queryBlogByID(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    ArrayList<String> ids = new ArrayList<String>();
    ids.add("1");
    HashMap map = new HashMap();
    map.put("ids",ids);
    blogMapper.queryBlogByID(map);
    sqlSession.close();
}

12.6、SQL片段

  1. 使用SQL标签抽取公共部分可

    <sql id="if-title-author">
        <if test="title!=null">
            title = #{title}
        </if>
        <if test="author!=null">
            and author = #{author}
        </if>
    </sql>
    
  2. 在需要使用的地方使用Include标签引用即可

    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <include refid="if-title-author"></include>
        </where>
    </select>
    

注意事项:

  • 最好基于单标来定义SQL片段
  • 不要存在where标签

缓存

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/147371.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!