13.Java- MyBatis框架

一、MyBatis简介

1. 什么是Mybatis

在这里插入图片描述

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

2. Mybatis下载

  • 【1】Maven 仓库

  • 在maven仓库中搜索mybatis:maven搜索链接,点击跳转
    在这里插入图片描述

  • 选择版本跳转
    在这里插入图片描述

  • 进入详情,可以复制当前代码,拷贝到配置文件pom.xml
    在这里插入图片描述

  • 代码如下

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>

在这里插入图片描述

3. 持久化

  • 【1】 数据持久化
  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化。
  • 【2】 为什么需要持久化?
  • 有一些对象,不能让他丢掉
  • 内存太贵

4. 持久层

Dao层,Service层,Controller层

  • 完成持久化工作的代码块
  • 层界限十分明显

5. 为什么需要MyBatis

  • 方便
  • 传统的DBC代码太复杂。简化。框架。自动化
  • 不用Mybatis也可以。学了这个更容易上手

二、第一个Mybatis程序

思路:环境搭建—>导入Mybatis–>编写代码---->测试
在这里插入图片描述

1. 搭建环境

1.创建数据库

sql代码

# 创建数据库
CREATE DATABASE mybatis;

# use mybatis; 报错 [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'information_schema.PROFILING.SEQ' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
# 解决:根据异常信息分析能发现,这个问题主要是由于sql_mode引起,所以先查看sql_mode后修改即可,主要是去除only_full_group_by
-- 查看SQL_MODE
# SELECT @@sql_mode;
-- 修改SQL_MODE
SET sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));
USE mybatis;

# 创建表
#  ENGINE=INNODB  设置引擎 
#  PRIMARY KEY 设置主键
CREATE TABLE `user` (
	`id` INT (20) NOT NULL,
	`name` VARCHAR (30) DEFAULT NULL,
	`pwd` VARCHAR (30) DEFAULT NULL,
   PRIMARY KEY(`id`) 

)ENGINE=INNODB CHARSET=utf8;
# 插入数据
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES(1,'jalu','123456');
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES(2,'mari','123456');
INSERT INTO `user`(`id`,`name`,`pwd`) VALUES(3,'练练','123456');

2. 新建项目

创建项目前,查看下自己的maven的配置是否是自己指定的jdk.

1. 新建maven项目
1. 添加Mybatis-Study空项目

在这里插入图片描述

2. 修改pom.xml
  • mysql 依赖
  <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
  • mybatis 依赖
 <!--mybatis-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
  • junit依赖
 <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
  • pom.xml文件代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!--父工程-->
    <groupId>com.xxx</groupId>
    <artifactId>Mybatis-Study</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <!--添加子模块自动在父类创建一个model-->
    <modules>
        <module>mybatis-01</module>
    </modules>

    <!-- 配置-->
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>


    <!--导入依赖-->
    <dependencies>
        <!--mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <!--mybatis-->
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.7</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

<!--在build中配置resource,来防止我们资源到处失败问题-->
    <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>

</project>

2. 创建模块

1. 创建空模块

创建一个空模块mybatis-01
在这里插入图片描述
空模块pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Mybatis-Study</artifactId>
        <groupId>com.xxx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatis-01</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <!--在build中配置resource,来防止我们资源到处失败问题-->
    <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>
</project>

2.编写mybatis的核心配置文件(连接数据库)

流程:mybatis-01->右键resources-New->File,新建名为mybatis-config.xml的配置文件在这里插入图片描述
输入mybatis-config.xml配置

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--configuration核心配置文件-->
<configuration>
    <!--环境  default 默认当前环境是development-->
    <environments default="development">
        <!--development 开发环境-->
        <environment id="development">
            <!--事务管理,默认使用jdbc-->
            <transactionManager type="JDBC"/>
             <!--数据源  汇集-->
            <dataSource type="POOLED">
                <!--  驱动 ${driver}   com.mysql.jdbc.Driver -->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!-- 链接地址  ${url}    jdbc:mysql://localhost:3306/mybatis?useSSL=TRUE&amp;useUnicode=true&amp;characterEncoding=UTF-8  -->
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=TRUE&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                 <!--用户名  ${username}  root  -->
                <property name="username" value="root"/>
                <!--秘密   ${password}   root-->
                <property name="password" value="root"/>
            </dataSource>
        </environment>


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

3. IDEA 链接数据库

在这里插入图片描述
链接数据库配置,测试
在这里插入图片描述

4. 编写mybatis工具类

新建工具类
在这里插入图片描述
MybatisUtils工具类代码

package com.xxx.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

//工具类 sqlSessionFactory->sqlSession
public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //获使用mybatis第一步:取sqlSessionFactory 对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //既然有了sqlSessionFactory,顾名思义,我们就可以从中获得SqlSession的实力了。
    //SqlSession 完全包含了面向数据库执行sql命令所需要的所有方法
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }


}

3. 编写代码

1. 实体类

package com.xxx.pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    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;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

2. Dao接口

package com.xxx.dao;
package com.xxx.dao;

import com.xxx.pojo.User;

import java.util.List;

public interface UserMapper {
    //获取全部用户
    public List<User> getUserList();

}


  • 接口实现由原来的UserMapperlmpl转变为一个Mapper配置文件
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--select 查询语句 id 对应方法名称  resultType -->
    <select id="getUserList" resultType="com.xxx.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

3.接口实现类

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {
   @Test
    public void test() {
        //第一部 :获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二部:方式一:执行SQL
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        //关闭sqlSession
        sqlSession.close();
    }
}


运行成功:

Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
User{id=1, name='jalu', pwd='123456'}
User{id=2, name='mari', pwd='123456'}
User{id=3, name='练练', pwd='123456'}

Process finished with exit code 0

运行报错:

  • 【1】 错误:注意点:org.apache.ibatis.binding.BindingException: Type interface com.xxx.dao.UserMapper is not known to the MapperRegistry.
  • 解决:在 Mybatis-Study\mybatis-01\src\main\resources\mybatis-config.xml 中添加一下代码
 <!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/xxx/dao/UserMapper.xml"/>
    </mappers>
  • 【2】错误:java.lang.ExceptionInInitializerError at com.xxx.dao.UserDaoTest.test(UserDaoTest.java:14)
  • 解决1: 在pom.xml里面,模块和父类的里面都添加一下代码
<!--在build中配置resource,来防止我们资源到处失败问题-->
    <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】错误3:
  • Error building SqlSession.
    The error may exist in com/xxx/dao/UserMapper.xml
    Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: Error creating document instance. Cause: org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 17; 1 字节的 UTF-8 序列的字节 1 无效。
  • 解决:resouces 和 java目录里面的xml文件 <?xml version="1.0" encoding="utf-8" ?> 改为 <?xml version="1.0" encoding="UTF8" ?>
  • 【4】错误4:Loading class com.mysql.jdbc.Driver'. This is deprecated. The new driver class iscom.mysql.cj.jdbc.Driver’. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.
  • 解决:这个是mybatis-config.xml配置driver驱动升级问题,不影响程序运行可以吧
 <property name="driver" value="com.mysql.jdbc.Driver"/>
  • 修改为
   <property name="driver" value="com.mysql.cj.jdbc.Driver"/>

4. 流程总结

流程:1.空模块->2.数据库连接工具类->3.数据库数据配置->4.实体类->5.数据库连接接口->6.sql语句->7.测试
在这里插入图片描述

三、CURD

1. namespase

  • namespase 里面的包名要和Dao/mapper的接口包名一致!

  • 注意点:增删改必须提交事务在这里插入图片描述

2. select

选择,查询语句在这里插入图片描述

  • id:对应的namespace中的方法名;
  • resultType:sql语句执行的返回值!
  • parameterType:参数类型

1. com.xxx.dao接口类添加接口

package com.xxx.dao;

import com.xxx.pojo.User;

import java.util.List;

public interface UserMapper {
    //获取全部用户
    public List<User> getUserList();

    //根据id查询用户,返回user
    User getUserById(int id);

}

2. com.xxx.dao 里xml添加sql

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--查询全部用户 select 查询语句 id: UserMapper对应方法名称  resultType:对应的实体类类型     parameterType: 参数类型 -->
    <select id="getUserList" resultType="com.xxx.pojo.User">
        select *
        from mybatis.user
    </select>
    <!--根据id查询一个用户  id:接口类名称 parameterType:参数类型  resultType:返回类型-->
    <select id="getUserById" parameterType="int" resultType="com.xxx.pojo.User">
        select *
        from mybatis.user
        where id = #{id}
    </select>

3. 测试类测试

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserMapperTest {
    @Test
    public void test() {
        //第一部 :获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //第二部:方式一:执行SQL
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        //关闭sqlSession
        sqlSession.close();
    }

    @Test
    public void getUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
        sqlSession.close();
    }

3. add

1. com.xxx.dao接口类添加接口

package com.xxx.dao;

import com.xxx.pojo.User;

import java.util.List;

public interface UserMapper {

    //增加用户
    int addUser(User user);
}

2. com.xxx.dao 里xml添加sql

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--添加用户 parameterType:参数类型-->
    <insert id="addUser" parameterType="com.xxx.pojo.User">
        insert into mybatis.user(id, name, pwd) value (#{id},#{name},#{pwd})
    </insert>
</mapper>

3. 测试类测试

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserMapperTest {
 
    @Test
    public void addUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int resultId = mapper.addUser(new User(4, "haha", "123456"));
        if (resultId > 0) {
            System.out.println("添加成功");
        }
        //提交事务
        sqlSession.commit();
        System.out.println(resultId);
        sqlSession.close();
    }

3. update

1. com.xxx.dao接口类添加接口

package com.xxx.dao;

import com.xxx.pojo.User;

import java.util.List;

public interface UserMapper {
    
    //修改用户
    int updateUser(User user);

}

2. com.xxx.dao 里xml添加sql

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--修改用户-->
    <update id="updateUser" parameterType="com.xxx.pojo.User">
        update mybatis.user
        set name=#{name},
            pwd=#{pwd}
        where id = #{id}
    </update>
</mapper>

3. 测试类测试

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserMapperTest {

    @Test
    public void updateUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int lili = mapper.updateUser(new User(4, "lili", "123456"));
        System.out.println(lili);
        sqlSession.commit();
        sqlSession.close();
    }

 
}

4. delete

1. com.xxx.dao接口类添加接口

package com.xxx.dao;

import com.xxx.pojo.User;

import java.util.List;

public interface UserMapper {
    //删除
    int delUser(int id);

}

2. com.xxx.dao 里xml添加sql

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--删除用户-->
    <delete id="delUser">
        delete  from mybatis.user where id = #{id}
    </delete>
</mapper>

3. 测试类测试

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserMapperTest {

    @Test
    public void delUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.delUser(4);
        sqlSession.commit();
        System.out.println(i);
        sqlSession.close();

    }
}

5. 万能Map

数据添加和修改可以按自己需要的字段去修改添加,不用必须每个都要写

1. com.xxx.dao接口类添加接口

 package com.xxx.dao;

import com.xxx.pojo.User;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    //万能的map
    int addUser2(Map<String, Object> map);
   // 万能的map 根据id查询用户
    User getUserById2(Map<String, Object> map);


}

2. com.xxx.dao 里xml添加sql

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--万能的map添加用户 parameterType:参数类型-->
    <insert id="addUser2" parameterType="map">
        insert into mybatis.user(id, pwd) value (#{userid},#{passWord})
    </insert>


     <!--根据id查询一个用户-->
    <select id="getUserById2" parameterType="Map" resultType="com.xxx.pojo.User">
        select *
        from mybatis.user
        where id = #{helloId}
          and name = #{name}
    </select>
</mapper>

3. 测试类测试

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;

public class UserMapperTest {
    @Test
    public void addUser2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("userid", 5);
        map.put("passWord", "11111");
        mapper.addUser2(map);
        sqlSession.commit();
        sqlSession.close();
    }

  @Test
    public void getUserById2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("helloId",1);
        map.put("name","jalu");
        User userById2 = mapper.getUserById2(map);
        System.out.println(userById2);
        sqlSession.close();
    }
}

  • Map传递参数,直接在sql中取出key即可
  • parameterType=“Map”
  • 对象传递参数,直接在sql中取出对象的属性即可
  • parameterType=“Object”
  • 只有一个基本类型参数的情况下,可以直接在sql中取到
  • 多个参数用Map或者注解

6. 模糊查询

模糊查询怎么写?

  • Java代码执行的时候,传递通配符%%
     List<User> userlike = mapper.getUserLike("%ja%");
  • 在sql拼接中使用通配符
    select * from  mybatis.user where name like "%"#{value}"%"

1. com.xxx.dao接口类添加接口

package com.xxx.dao;

import com.xxx.pojo.User;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    //获取全部用户
  
    //模糊查询
    List<User> getUserLike(String name);

}

2. com.xxx.dao 里xml添加sql

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--模糊查询-->
    <select id="getUserLike" resultType="com.xxx.pojo.User">
        select * from  mybatis.user where name like "%"#{value}"%"
    </select>
</mapper>

3. 测试类测试

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.HashMap;
import java.util.List;

public class UserMapperTest {
    @Test
    public void getUserLike(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userlike = mapper.getUserLike("ja");
        for (User user : userlike) {
            System.out.println(user);
        }
        System.out.println(userlike);
    }
}

四、配置解析

1. 核心配置文件

  • mybatis-config.xml
  • MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

2. 环境配置(environments)

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

  • mybatis默认的事务管理是:JDBC,数据池:POOLED

3. 属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置

1. 编写配置文件

文件地址:src/main/resources/db.properties
文件内容:

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=TRUE&amp;useUnicode=true&amp;characterEncoding=UTF-8
username=root
password=root

2. 在核心配置文件中引入

核心配置文件地址:src/main/resources/mybatis-config.xml
文件内容:

<configuration>
    <!--引入外部配置文件-->
    <properties resource="db.properties">
        <!--配置用户名密码可以单独管理-->
        <!--<property name="username" value="root"/>
        <property name="password" value="root"/>-->
    </properties>

全部文件内容:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--configuration核心配置文件-->
<configuration>
    <!--引入外部配置文件-->
    <properties resource="db.properties">
        <!--配置用户名密码可以单独管理-->
        <!--<property name="username" value="root"/>
        <property name="password" value="root"/>-->
    </properties>
    <!--环境  default 默认当前环境是development-->
    <environments default="development">
        <!--development 开发环境-->
        <environment id="development">
            <!--事务管理,默认使用jdbc-->
            <transactionManager type="JDBC"/>
            <!--数据源  汇集 POOLED数据池 用完就回收-->
            <dataSource type="POOLED">
                <!--  驱动 ${driver}   com.mysql.jdbc.Driver -->
                <property name="driver" value="${driver}"/>
                <!-- 链接地址  ${url}    jdbc:mysql://localhost:3306/mybatis?useSSL=TRUE&amp;useUnicode=true&amp;characterEncoding=UTF-8  -->
                <property name="url" value="${url}"/>
                <!--用户名  ${username}  root  -->
                <property name="username" value="${username}"/>
                <!--秘密   ${password}   root-->
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>

    </environments>
    <!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper resource="com/xxx/dao/UserMapper.xml"/>
    </mappers>
</configuration>
  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件

4.类型别名(typeAliases)

  • 类型别名是为Java类型设置一个短名字
  • 存在的意义在于减少类完全限定名的冗余

1. 添加命名别名user

文件修改路径:src/main/resources/mybatis-config.xml
添加以下配置:

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

2. 扫码实体类包,默认小写类名是别名

文件修改路径:src/main/resources/mybatis-config.xml
添加以下配置:

  <!--可以给实体类设置别名-->
    <typeAliases>
        <package name="com.xxx.pojo"/>
    </typeAliases>
  • 可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
  • 扫码实体类的包,它的默认别名就是为这个类的类名,首字母小写

3. 使用别名

  • 在实体类比较少的时候,使用第一种方式
  • 如果实体类十分多,建议使用第二种
  • 第一种可以DIY别名,第二种则不行,如果非要改,需在在实体类上增加注解
package com.xxx.dao;

import com.xxx.pojo.User;
import org.apache.ibatis.type.Alias;

import java.util.List;
import java.util.Map;

@Alias("user")
public interface UserMapper {
    //获取全部用户
    public List<User> getUserList();

    //根据id查询用户
    User getUserById(int id);

    //增加用户
    int addUser(User user);

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

    //删除
    int delUser(int id);


}

文件路径:src/main/java/com/xxx/dao/UserMapper.xml
使用代码: resultType="com.xxx.pojo.User" 修改为resultType="User"

  <!--查询全部用户 select 查询语句 id: UserMapper对应方法名称  resultType:对应的实体类类型 com.xxx.pojo.User       parameterType: 参数类型 -->
    <select id="getUserList" resultType="User">
        select *
        from mybatis.user
    </select>

5.其他设置

  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
    。MyBatis Generator Core
    。MyBatis Plus
    。通用mapper

6.映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件;
方式一:【推荐使用】


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

方式二:使用class文件绑定

<mappers>
       <!-- <mapper resource="com/xxx/dao/UserMapper.xml"/>-->
        <mapper class="com.xxx.dao.UserMapper"/>
    </mappers>

注意点:

  • 接口和他的mappe配置文件必须同名
  • 接口和他的配置文件必须在通过包下

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

   <mappers>
       <!-- <mapper resource="com/xxx/dao/UserMapper.xml"/>-->
       <!-- <mapper class="com.xxx.dao.UserMapper"/>-->
        <package name="com.xxx.dao"/>
    </mappers>

注意点:

  • 接口和他的mappe配置文件必须同名
  • 接口和他的配置文件必须在通过包下

7.生命周期和作用域

在这里插入图片描述

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

** 【1】SqlSessionFactoryBuilder:**

  • 一旦创建了SqlSessionFactory,就不在需要它了
  • 局部变量
    【2】SqlSessionFactory:
  • 说白了就是可以想象为:数据库连接池
  • SqlSessionFactory一旦创建就应该在应用的运行期间一直存在,没有任何理由丢其他或者重新创建另一个实例
  • 因此SqlSessionFactory的最佳作用域是应用作用域
  • 最简单的就是使用单例模式或者静态单例模式
    【3】SqlSession
  • 链接到连接池的一个请求
  • SqlSession的实例不是线程安全的,因此是不能被共享的,所以他的最佳作用域是请求或方法作用域
  • 用完之后需要赶紧关闭,否则资源被占用
    在这里插入图片描述
  • 这里面的每一个Mapper,就代表一个具体的业务

五、ResultMap结果集映射

1. 解决属性名和字段名不一致的问题

1. 问题

1. 数据库中的字段

在这里插入图片描述

2. 新建一个项目,拷贝之前的,情况测试实体类字段不一致的情况
package com.xxx.pojo;

public class User {
    private int id;
    private String name;
    private String password;
3. 出现问题

在这里插入图片描述

2. 解决

1. 起别名
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--根据id查询一个用户
     sql 1: 根据id查询用户
     select * from mybatis.user where id = #{id}
     sql 2 : 根据id查询用户,重命名字段,起别名
     select id, name, pwd as password from mybatis.user where id = #{id}
    -->
    <select id="getUserById" parameterType="int" resultType="com.xxx.pojo.User">
        select id, name, pwd as password
        from mybatis.user
        where id = #{id}
    </select>


</mapper>

2.resultMap

结果集映射

id name pwd
id name password

创建一个结果集UserMap,绑定到select的返回结果resultMap

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--根据id查询一个用户
    sql 1: 根据id查询用户
     select * from mybatis.user where id = #{id}
     sql 2 : 根据id查询用户,重命名字段
     select id, name, pwd as password from mybatis.user where id = #{id}
    -->
    <!-- <select id="getUserById" parameterType="int" resultType="User">
         select * from mybatis.user where id = #{id}
     </select>-->

    <!--返回结果是UserMap结果集-->
    <select id="getUserById" resultMap="UserMap">
        select *
        from mybatis.user
        where id = #{id}
    </select>

    <!--结果集映射,只需要映射不一样的属性-->
    <resultMap id="UserMap" type="com.xxx.pojo.User">
        <!--column 数据库中的字段   property实体类中的属性-->
         <!--<result column="id" property="id"/>
        <result column="name" property="name"/>-->
        <result column="pwd" property="password"/>
    </resultMap>
</mapper>

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

六、日志

1. 日志工厂

如果一个数据库操作,出现了异常,进行排错,日志是最好的助手
曾经:sout、debug
现在:日志工厂
在这里插入图片描述

在Mybatis中具体使用哪个日志实现,在设置中设定
STD

1.STDOUT_LOGGING标准日志输出

在mybatis核心配置文件中,配置我们的日志

 <!--设置日志-->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

输出结果
在这里插入图片描述

2.LOG4J

1. 导包
  • 什么是LOG4J?
  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  1. 先导入log4j的包
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  • 【3】 复制到当前model的pom.xml

     <!--导入依赖-->
    <dependencies>
        <!--导入log4j-->
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>
2.配置log4j.properties

新建src/main/resources/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/kuang.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.sql.PreparedStatement=DEBUG
3.配置log4j为日志的实现

配置src/main/resources/mybatis-config.xml文件,添加日志文件设置代码,在configuration标签里面

 <!--设置日志-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
4.LOG4J的使用

直接测试链接,刚才的查询
在这里插入图片描述

1. 简单使用
  1. 在使用LOG4J的类中,导入包import org.apache.log4j.Logger;
  2. 日志对象,参数为当前类的class
    在当前使用的测试类中src/test/java/com/xxx/dao/UserMapperTest.java加入以下代码
src/test/java/com/xxx/dao/UserMapperTest.java
  1. 使用log4j,代码为
package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
//导入包
import org.apache.log4j.Logger;

public class UserMapperTest {
    //日志对象
    static Logger logger = Logger.getLogger(UserMapperTest.class);

    @Test
    public void getUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
        sqlSession.close();
    }

    @Test
    public void testLog4l() {
        logger.info("info:进入了testLOG4J");
        logger.debug("debug:进入了testLOG4J");
        logger.error("error:进入了testLOG4J");
    }

}

  1. 运行结果
    在这里插入图片描述

七、分页

思考:为什么分页?

  • 减少数据的处理量

1. 使用limit分页

1. 接口类

添加路径:src/main/java/com/xxx/dao/UserMapper.java

//分页
    List<User> getUserByLimit(Map<String, Object> map);

2. mapper.xml

添加路径:src/main/java/com/xxx/dao/UserMapper.xml

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace = 绑定一个对应的Dao接口/Mapper接口-->
<mapper namespace="com.xxx.dao.UserMapper">
    <!--根据id查询一个用户
    sql 1: 根据id查询用户
     select * from mybatis.user where id = #{id}
     sql 2 : 根据id查询用户,重命名字段
     select id, name, pwd as password from mybatis.user where id = #{id}
    -->
    <!-- <select id="getUserById" parameterType="int" resultType="User">
         select * from mybatis.user where id = #{id}
     </select>-->

    <!--返回结果是UserMap结果集-->
    <select id="getUserById" resultMap="UserMap">
        select *
        from mybatis.user
        where id = #{id}
    </select>

    <!--结果集映射-->
    <resultMap id="UserMap" type="com.xxx.pojo.User">
        <!--column 数据库中的字段   property实体类中的属性-->
        <!--  <result column="id" property="id"/>
          <result column="name" property="name"/>-->
        <result column="pwd" property="password"/>
    </resultMap>


    <!--分页查询  parameterType="map" resultType="user"-->
    <select id="getUserByLimit"  resultMap="UserMap">
        select *
        from mybatis.user limit #{startIndex},#{pageSize}

    </select>

</mapper>


2. 测试

路径:src/test/java/com/xxx/dao/UserMapperTest.java

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
//导入包
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserMapperTest {
    //日志对象
    static Logger logger = Logger.getLogger(UserMapperTest.class);

    @Test
    public void getUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
        sqlSession.close();
    }

    @Test
    public void testLog4l() {
        logger.info("info:进入了testLOG4J");
        logger.debug("debug:进入了testLOG4J");
        logger.error("error:进入了testLOG4J");
    }

    @Test
    public void getUserByLimit() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Object> map = new HashMap<>();
        map.put("startIndex", 0);
        map.put("pageSize", 2);
        List<User> userByLimit = mapper.getUserByLimit(map);
        for (User user : userByLimit) {
            System.out.println(user);
        }
        sqlSession.close();
    }

}

2. RowBounds分页

不在使用SQL实现分页

1. 接口类

 //分页2 RowBounds分页
    List<User> getUserByRowBounds();

2. mapper.xml

 <!-- 分页查询2:RowBounds分页-->
    <select id="getUserByRowBounds" resultMap="UserMap">
        select * from mybatis.user;
    </select>

3. 测试

    @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //RowBounds实现
        RowBounds rowBounds = new RowBounds(1, 2);
        // 通过Java代码层面实现分页
        List<User> userByLimit = sqlSession.selectList("com.xxx.dao.UserMapper.getUserByRowBounds", null, rowBounds);
        for (User user : userByLimit) {
            System.out.println(user);
        }
        sqlSession.close();
    }

3. 分页插件pagehelper

网址页面:https://pagehelper.github.io/
使用文档:https://pagehelper.github.io/docs/howtouse/
在这里插入图片描述

八、注解开发

在这里插入图片描述
在这里插入图片描述

1. 注解的使用

1. 接口类

package com.xxx.dao;

import com.xxx.pojo.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    @Select("select * from user")
    List<User> getUsers();


}

2. 核心配置文件绑定接口

src/main/resources/mybatis-config.xml

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

3. 测试

package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;


public class UserMapperTest {
    //日志对象
   // static Logger logger = Logger.getLogger(UserMapperTest.class);

    @Test
    public void getUsers() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //利用反射原理
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }


}

  • 本质: 反射机制实现
  • 底层:动态代理
    在这里插入图片描述
  • MyBatis详细执行流程
    在这里插入图片描述

2. curd

我们可以在工具类创建的时候实现自动提交事务!

  • 修改数据库链接工具类:
  • 修改 地址: src/main/java/com/xxx/utils/MybatisUtils.java
  • 把return返回添加上true,自动提交事务
 //既然有了sqlSessionFactory,顾名思义,我们就可以从中获得SqlSession的实力了。
    //SqlSession 完全包含了面向数据库执行sql命令所需要的所有方法
    // 设置为true,自动提交事务
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);
    }

1. select

1. 类接口
package com.xxx.dao;

import com.xxx.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    @Select("select * from user")
    List<User> getUsers();
    //通过id查询数据 方法存在多个参数,所有参数前面必须加上@Param("id")的注解
    @Select("select * from user where id = #{id} and name = #{name}")
    User getUserById(@Param("id") int id,@Param("name") String name);


}

2. 测试
package com.xxx.dao;

import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;


public class UserMapperTest {
    //日志对象
   // static Logger logger = Logger.getLogger(UserMapperTest.class);

    @Test
    public void getUsers() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //利用反射原理
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }

    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //利用反射原理
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User jalu = mapper.getUserById(1, "jalu");
        System.out.println(jalu);
    }


}

1. add

1. 类接口
   @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
    int addUser(User user);
2. 测试
 @Test
    public void addUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //利用反射原理
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int hello = mapper.addUser(new User(4, "hello", "123456"));
        System.out.println(hello);
        sqlSession.close();

    }

1. delete

1. 类接口

    @Delete("delete from user where id=#{id}")
    int deleteUser(@Param("id") int id);
2. 测试
   @Test
    public void deleteUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //利用反射原理
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int hello = mapper.deleteUser(1);
        System.out.println(hello);
        sqlSession.close();
    }

1. update

1. 类接口

    @Update("update user set name=#{name},pwd=#{password} where id = #{id}")
    int updateUser(User user);
2. 测试
  @Test
    public void updateUser() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //利用反射原理
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int hello = mapper.updateUser(new User(5, "Hello", "12345"));
        System.out.println(hello);
        sqlSession.close();
    }
  • 注意:我们必须要将接口注册绑定到我们的核心配置文件中!

3、关于@Param( )注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
  • 我们在SQL中引用的就是我们这里的@Param()中设定的属性名
  • #{} 和 KaTeX parse error: Expected ‘EOF’, got ‘#’ at position 11: {} 有区别,能用 #̲ 尽量用 #,可以防止sql注… 不能防止 sql 注入

九、Lombok插件

1. 简介

Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。

  • java library
  • plugs
  • build tools
  • with one annotation your class

2. 使用步骤

1. 在IDEA中安装Lombok插件

File->Settings->Plugins
在这里插入图片描述

2、在项目中导入lombok的jar包

导入文件路径:当前项目的pom.xml

 <!--导入依赖-->
    <dependencies>
        <!--导入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

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

  • @Data:
  • 无参构造、getter、setter、tostring、hashcode、equals
  • @AllArgsConstructor : 有参构造
  • @NoArgsConstructor: 无参构造

十、多对一处理

在这里插入图片描述

  • 多个学生对应一个老师
  • 对于学生这边而言,关联…多个学生,关联一个老师【多对一是关联】
  • 对于老师而言,集合,一个老师,有很多学生【一对多是集合】

在这里插入图片描述

1. 环境搭建

在这里插入图片描述

1. 创建关联表sql


## ERRORS Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'loser.tank_admin.login_ip' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

set @@sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';

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

INSERT INTO teacher (`id`, `name`) VALUES (1, 'hou');

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=utf8;

INSERT INTO student (`id`, `name`, `tid`) VALUES (1, 'xiao1', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (2, 'xiao2', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (3, 'xiao3', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (4, 'xiao4', 1);
INSERT INTO student (`id`, `name`, `tid`) VALUES (5, 'xiao5', 1);


2.pom.xml 导入lombok

  <!--导入依赖-->
    <dependencies>
        <!--导入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

3.新建实体类Teacher,Student

1. 创建Student实体类

地址:src\main\java\com\xxx\pojo\Student.java
代码:

package com.xxx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private int id;
    private String name;
    //学生需要关联老师
    private Teacher teacher;

}

2 创建Teacher实体类

地址:src\main\java\com\xxx\pojo\Teacher.java
代码:

package com.xxx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
}

4.建立Mapper接口

1. 创建StudentMapper接口

地址:src\main\java\com\xxx\dao\StudentMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;

import java.util.List;

public interface StudentMapper {

    @Select("select * from teacher where id = #{tid}")
	Teacher getTeacher(@Param("tid") int id);
}

2. 创建TeacherMapper接口

地址:src\main\java\com\xxx\dao\TeacherMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface TeacherMapper {
    /*@Select("select * from teacher where id = #{tid}")
    Teacher getTeacher(@Param("tid") int id);*/
    Teacher getTeacher(int id);
}

5.建立Mapper.xml文件

1. 创建StudentMapper.xml文件

地址:src\main\resources\com\xxx\dao\StudentMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.StudentMapper">

   

</mapper>
2. 创建TeacherMapper.xml文件

地址:src\main\resources\com\xxx\dao\TeacherMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.TeacherMapper">

    <!--查询老师信息-->
    <select id="getTeacher" resultType="com.xxx.pojo.Teacher">
        select *  from teacher  where id = #{id}
    </select>

</mapper>

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

地址:src\main\resources\mybatis-config.xml
代码:

   <!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
    <mappers>
        <mapper class="com.xxx.dao.TeacherMapper"/>
        <mapper class="com.xxx.dao.StudentMapper"/>

    </mappers>

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

import com.xxx.dao.StudentMapper;
import com.xxx.dao.TeacherMapper;
import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {

    @Test
    public void getTeacher() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
        sqlSession.close();

    }

}


2. 按照子查询嵌套处理

如果想获得学生同时获得老师

sql语句:select s.id,s.name,t.name from student s,teacher t where s.tid = t.id

select 查找,显示:s.id,s.name,t.name,由表格:student s表,teacher t表 where且 s.tid = t.id

但是方法怎么写?

1.StudentMapper.java接口

路径:src\main\java\com\xxx\dao\StudentMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;

import java.util.List;

public interface StudentMapper {
    //查询所有的学生信息,以及对应的老师信息
    public List<Student> getStudent();

}

2.StudentMapper.xml 配置文件

路径:src\main\resources\com\xxx\dao\StudentMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.StudentMapper">

    <!--
        方式1: 安照查询嵌套处理
       查询所有的学生信息,以及对应的老师信息
       思路:
          1. 查询所有的学生信息
          2. 根据查询出来的学生tid,寻找对应的老师

    -->
    <select id="getStudent" resultMap="StudentTeacher">
        select *
        from student
    </select>
    <!--结果集处理-->
    <resultMap id="StudentTeacher" type="com.xxx.pojo.Student">
        <!--property:实体类中的属性名称  column:数据库中的属性名称-->
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--复杂的属性,我们需要单独处理     对象:association 集合:collection  -->
        <association property="teacher" column="tid" javaType="com.xxx.pojo.Teacher" select="getTeacher"/>
    </resultMap>
    <!--查询老师信息-->
    <select id="getTeacher" resultType="com.xxx.pojo.Teacher">
        select *
        from teacher
        where id = #{id}
    </select>
 
</mapper>

3.测试

import com.xxx.dao.StudentMapper;
import com.xxx.dao.TeacherMapper;
import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {

    @Test
    public void getTeacher() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
        sqlSession.close();

    }

    @Test
    public void getStudent() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.getStudent();
        for (Student student : studentList) {
            System.out.println(student);
        }
        sqlSession.close();
    }
 
}


  • 复制属性:对象association,集合collection
  • javaType给对象设定一个类型(子类的类型)
  • select如果查出来要做什么,去执行了getTeacher子查询

3. 按照结果嵌套处理

1.StudentMapper.java接口

路径:src\main\java\com\xxx\dao\StudentMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;

import java.util.List;

public interface StudentMapper {
    //查询所有的学生信息,以及对应的老师信息
    public List<Student> getStudent();
    //查询所有的学生信息,以及对应的老师信息2
    public List<Student> getStudent2();
}

2.StudentMapper.xml 配置文件

路径:src\main\resources\com\xxx\dao\StudentMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.StudentMapper">

    <!--
        方式1: 安照查询嵌套处理
       查询所有的学生信息,以及对应的老师信息
       思路:
          1. 查询所有的学生信息
          2. 根据查询出来的学生tid,寻找对应的老师

    -->
    <select id="getStudent" resultMap="StudentTeacher">
        select *
        from student
    </select>
    <!--结果集处理-->
    <resultMap id="StudentTeacher" type="com.xxx.pojo.Student">
        <!--property:实体类中的属性名称  column:数据库中的属性名称-->
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--复杂的属性,我们需要单独处理     对象:association 集合:collection  -->
        <association property="teacher" column="tid" javaType="com.xxx.pojo.Teacher" select="getTeacher"/>
    </resultMap>
    <!--查询老师信息-->
    <select id="getTeacher" resultType="com.xxx.pojo.Teacher">
        select *
        from teacher
        where id = #{id}
    </select>
    <!--============================================================================================-->
    <!--
        方式2: 安照结果嵌套处理
       查询所有的学生信息,以及对应的老师信息
    -->
    <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="com.xxx.pojo.Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <!--复杂类型association-->
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>

</mapper>

3.测试

import com.xxx.dao.StudentMapper;
import com.xxx.dao.TeacherMapper;
import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {

    @Test
    public void getTeacher() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
        sqlSession.close();

    }

    @Test
    public void getStudent() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.getStudent();
        for (Student student : studentList) {
            System.out.println(student);
        }
        sqlSession.close();
    }
    @Test
    public void getStudent2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.getStudent2();
        for (Student student : studentList) {
            System.out.println(student);
        }
        sqlSession.close();
    }

}


  • 回顾Mysql多对一查询方式:
  • 子查询 (按照查询嵌套)
  • 联表查询 (按照结果嵌套)

十一、一对多处理

  • 一个老师多个学生
  • 对于老师而言,就是一对多的关系

1. 环境搭建

1. 和十一样环境

2. 创建实体类

1. 创建Student

路径:com/xxx/pojo/Student.java
代码:

package com.xxx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private int id;
    private String name;
    private int tid;

}

2. 创建Teacher

路径:com/xxx/pojo/Teacher.java
代码:

package com.xxx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;
}

3.创建接口

1. 创建Student

路径:src/main/java/com/xxx/dao/StudentMapper.java
代码:

package com.xxx.dao;



public interface StudentMapper {

}

2. 创建Teacher

路径:src/main/java/com/xxx/dao/TeacherMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.Teacher;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface TeacherMapper {
    //获取老师
    List<Teacher> getTeacher();

}

4.创建xml文件

1. 创建Student

路径:src/main/resources/com/xxx/dao/StudentMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.StudentMapper">


</mapper>
2. 创建Teacher

路径:src/main/resources/com/xxx/dao/TeacherMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.TeacherMapper">
    <!--查询所有老师信息-->
    <select id="getTeacher" resultType="com.xxx.pojo.Teacher">
        select *
        from teacher;
    </select>

</mapper>
5. 测试

路径:src/test/java/MyTest.java
代码:

import com.xxx.dao.StudentMapper;
import com.xxx.dao.TeacherMapper;
import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {
    @Test
    public void getTeacher() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher = mapper.getTeacher();
        for (Teacher teacher1 : teacher) {
            System.out.println(teacher1);
        }
        sqlSession.close();
    }




2. 按照结果查询

1. 接口类

地址:src/main/java/com/xxx/dao/TeacherMapper.java
代码:getTeacher2

package com.xxx.dao;

import com.xxx.pojo.Teacher;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface TeacherMapper {
    //获取老师
    List<Teacher> getTeacher();

    //获取指定老师下所有的学生及老师信息
    Teacher getTeacher2(@Param("tid") int id);

}


2. xml文件

地址:src/main/resources/com/xxx/dao/TeacherMapper.xml
代码:getTeacher2

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.TeacherMapper">
    <!--查询所有老师信息-->
    <select id="getTeacher" resultType="com.xxx.pojo.Teacher">
        select *
        from teacher;
    </select>

    <!--1. 按照结果获取集合:获取指定老师下所有的学生及老师信息-->
    <select id="getTeacher2" resultMap="TeacherStudent">
        SELECT s.id   sid,
               s.name sname,
               t.name tname,
               t.id   tid
        FROM student s,
             teacher t
        WHERE s.tid = t.id
          and t.id = #{tid};
    </select>
    <resultMap id="TeacherStudent" type="com.xxx.pojo.Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--复杂的属性,我们需要单独处理,
        对象:association    List<Student> getStudent2();
        集合 collection     Teacher getTeacher2(@Param("tid") int id);
        javaType:指定属性的类型
        集合中的泛型信息,我们使用ofType获取
    -->
        <collection property="students" ofType="com.xxx.pojo.Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

  
</mapper>

3. 测试

getTeacher2

import com.xxx.dao.StudentMapper;
import com.xxx.dao.TeacherMapper;
import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {
    @Test
    public void getTeacher() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher = mapper.getTeacher();
        for (Teacher teacher1 : teacher) {
            System.out.println(teacher1);
        }
        sqlSession.close();
    }

    @Test
    public void getTeacher2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher2 = mapper.getTeacher2(1);
        System.out.println(teacher2);
        //Teacher(id=1, name=张老师, students=[Student(id=1, name=xiao1, tid=1), Student(id=2, name=xiao2, tid=1), Student(id=3, name=xiao3, tid=1), Student(id=4, name=xiao4, tid=1), Student(id=5, name=xiao5, tid=1)])

        sqlSession.close();
    }

 
}


3. 按照子查询查询

1. 接口类

地址:地址:src/main/java/com/xxx/dao/TeacherMapper.java
代码:getTeacher3

package com.xxx.dao;

import com.xxx.pojo.Teacher;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface TeacherMapper {
    //获取老师
    List<Teacher> getTeacher();

    //获取指定老师下所有的学生及老师信息
    Teacher getTeacher2(@Param("tid") int id);

    //获取指定老师下所有的学生及老师信息
    Teacher getTeacher3(@Param("tid") int id);
}

2. xml文件

地址:src/main/resources/com/xxx/dao/TeacherMapper.xml
代码:getTeacher3

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.TeacherMapper">
    <!--查询所有老师信息-->
    <select id="getTeacher" resultType="com.xxx.pojo.Teacher">
        select *
        from teacher;
    </select>

    <!--1. 按照结果获取集合:获取指定老师下所有的学生及老师信息-->
    <select id="getTeacher2" resultMap="TeacherStudent">
        SELECT s.id   sid,
               s.name sname,
               t.name tname,
               t.id   tid
        FROM student s,
             teacher t
        WHERE s.tid = t.id
          and t.id = #{tid};
    </select>
    <resultMap id="TeacherStudent" type="com.xxx.pojo.Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--复杂的属性,我们需要单独处理,
        对象:association    List<Student> getStudent2();
        集合 collection     Teacher getTeacher2(@Param("tid") int id);
        javaType:指定属性的类型
        集合中的泛型信息,我们使用ofType获取
    -->
        <collection property="students" ofType="com.xxx.pojo.Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

    <!--======================================================================================================-->

    <!--2. 按照子查询获取集合:获取指定老师下所有的学生及老师信息-->

    <select id="getTeacher3" resultMap="TeacherStudent1">
        SELECT *
        FROM mybatis.teacher
        where id = #{tid}
    </select>

    <resultMap id="TeacherStudent1" type="com.xxx.pojo.Teacher">
       <collection property="students" javaType="ArrayList" ofType="com.xxx.pojo.Student" select="getStudentByTeacherId" column="id"/>
    </resultMap>
    <select id="getStudentByTeacherId" resultType="com.xxx.pojo.Student">
        select * from mybatis.student where  tid = #{tid}
    </select>
</mapper>

3. 测试

代码:getTeacher3

import com.xxx.dao.StudentMapper;
import com.xxx.dao.TeacherMapper;
import com.xxx.pojo.Student;
import com.xxx.pojo.Teacher;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class MyTest {
    @Test
    public void getTeacher() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        List<Teacher> teacher = mapper.getTeacher();
        for (Teacher teacher1 : teacher) {
            System.out.println(teacher1);
        }
        sqlSession.close();
    }

    @Test
    public void getTeacher2() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher2 = mapper.getTeacher2(1);
        System.out.println(teacher2);
        //Teacher(id=1, name=张老师, students=[Student(id=1, name=xiao1, tid=1), Student(id=2, name=xiao2, tid=1), Student(id=3, name=xiao3, tid=1), Student(id=4, name=xiao4, tid=1), Student(id=5, name=xiao5, tid=1)])

        sqlSession.close();
    }

    @Test
    public void getTeacher3() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher2 = mapper.getTeacher3(1);
        System.out.println(teacher2);
        sqlSession.close();
    }
}


4. 小结

【1】关联 、集合 
    关联 - association 【多对一】
    集合 - collection 【一对多】
【2】javaType & ofType
    JavaType用来指定实体类中的类型
    ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
【3】注意点:
    保证SQL的可读性,尽量保证通俗易懂
    注意一对多和多对一,属性名和字段的问题
    如果问题不好排查错误,可以使用日志,建议使用Log4j
    避免慢SQL,当数据量多的时候,需要使用索引,不然你的代码会比别人慢很多
【4】面试高频
    Mysql引擎
    InnoDB底层原理
    索引
    索引优化

十二、动态sql

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

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

如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL 元素可能会感觉似曾相识。
在 MyBatis 之前的版本中,需要花时间了解大量的元素。
借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

if
choose (when, otherwise)
trim (where, set)
foreac

1.搭建环境

1. 创建sql


DROP TABLE IF EXISTS `blog`;
CREATE TABLE `blog` (
  `id` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '博客id',
  `title` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '博客标题',
  `author` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '博客作者',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  `views` int(30) NOT NULL COMMENT '浏览量',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


2.创建一个基础工程

1.导包

地址:pom.xml
代码:导入lombok

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Mybatis-Study</artifactId>
        <groupId>com.xxx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatis-08</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <!--导入依赖-->
    <dependencies>
        <!--导入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>
2.编写配置文件
  1. 编写数据库配置
    路径:src/main/resources/db.properties
    代码:
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=TRUE&useUnicode=true&characterEncoding=UTF-8
username=root
password=root
  1. 编写核心配置代码
    路径:src/main/resources/mybatis-config.xml
    代码:
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--总:configuration核心配置文件-->
<configuration>
    <!--1. 引入外部配置文件-->
    <properties resource="db.properties">
        <!--配置用户名密码可以单独管理-->
        <!--<property name="username" value="root"/>
        <property name="password" value="root"/>-->
    </properties>
    <!--设置日志-->
    <!--  <settings>
          <setting name="logImpl" value="LOG4J"/>
      </settings>
  -->
    <!--可以给实体类设置别名-->
    <typeAliases>
        <!--<typeAlias type="com.xxx.pojo.User" alias="User"/>-->
        <package name="com.xxx.pojo"/>
    </typeAliases>
    <!--2. 环境  default 默认当前环境是development-->
    <environments default="development">
        <!--development 开发环境-->
        <environment id="development">
            <!--事务管理,默认使用jdbc-->
            <transactionManager type="JDBC"/>
            <!--数据源  汇集 POOLED数据池 用完就回收-->
            <dataSource type="POOLED">
                <!--  驱动 ${driver}   com.mysql.jdbc.Driver -->
                <property name="driver" value="${driver}"/>
                <!-- 链接地址  ${url}    jdbc:mysql://localhost:3306/mybatis?useSSL=TRUE&amp;useUnicode=true&amp;characterEncoding=UTF-8  -->
                <property name="url" value="${url}"/>
                <!--用户名  ${username}  root  -->
                <property name="username" value="${username}"/>
                <!--秘密   ${password}   root-->
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>

    </environments>

    <!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册!-->
    <mappers>
         <mapper class="com.xxx.dao.BlogMapper"/>

    </mappers>

</configuration>
  1. 编写数据库链接文件
    路径:src/main/java/com/xxx/pojo/utils/MybatisUtils.java
    代码:
package com.xxx.pojo.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

//工具类 sqlSessionFactory->sqlSession
public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //获使用mybatis第一步:取sqlSessionFactory 对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //既然有了sqlSessionFactory,顾名思义,我们就可以从中获得SqlSession的实力了。
    //SqlSession 完全包含了面向数据库执行sql命令所需要的所有方法
    // 设置为true,自动提交事务
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);
    }


}

3.编写实体类

路径:src/main/java/com/xxx/pojo/Blog.java
代码:

package com.xxx.pojo;

import lombok.Data;

import java.util.Date;

@Data
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;//属性名和字段名不一致
    private int views;

}


4.编写Mapper接口类

地址:src/main/java/com/xxx/dao/BlogMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.Blog;

public interface BlogMapper {
    //添加数据
    int addBlog(Blog blog);
}


5.编写Mapper.xml文件

地址:src/main/java/com/xxx/dao/BlogMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.BlogMapper">
<insert id="addBlog" parameterType="blog">
    insert into mybatis.blog (id,title,author,create_time,views)
    values (#{id},#{title},#{author},#{createTime},#{views});
</insert>

</mapper>
6.配置公共方法文件IDutils.java

地址:src/main/java/com/xxx/utils/IDUtils.java
代码:

package com.xxx.utils;

import org.junit.Test;

import java.util.UUID;


//@SuppressWarnings("all")//抑制警告
public class IDUtils {
    public static String getId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    @Test
    public void test() {
        System.out.println(IDUtils.getId());
    }


}

7.核心文件配置驼峰命名转换

mapUnderscoreToCamelCase:
是否开启自动驼峰命名规则转换,即从经典数据库列明A_COLUMN到经典Java属性名aColumn的类似转换

地址:src/main/resources/mybatis-config.xml
代码:

 <settings>
        <!--设置日志-->
        <!--<setting name="logImpl" value="LOG4J"/>-->
        <!--核心文件配置驼峰命名转换-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

8. 测试
import com.xxx.dao.BlogMapper;
import com.xxx.pojo.Blog;
import com.xxx.utils.IDUtils;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;

public class MyTest {
    @Test
    public void addBlog(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        //new一个实体类,设置数据
        Blog blog = new Blog();
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Mybatis如此简单");
        blog.setAuthor("fj学习");
        blog.setCreateTime(new Date());
        blog.setViews(9999);
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Spring如此简单");
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("微服务如此简单");
        //添加数据
        mapper.addBlog(blog);
        sqlSession.close();
    }
}

结果:
在这里插入图片描述

2.IF

1. Mapper接口类

地址:src/main/java/com/xxx/dao/BlogMapper.java
代码:queryBlogIF

package com.xxx.dao;

import com.xxx.pojo.Blog;

import java.util.List;
import java.util.Map;

public interface BlogMapper {
    //添加数据
    int addBlog(Blog blog);

    //查询博客
    List<Blog> queryBlogIF(Map map);
}

2. Mapper.xml

地址:src/main/java/com/xxx/dao/BlogMapper.xml
代码:queryBlogIF

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.BlogMapper">
    <!--添加-->
    <insert id="addBlog" parameterType="blog">
        insert into mybatis.blog (id, title, author, create_time, views)
        values (#{id}, #{title}, #{author}, #{createTime}, #{views});
    </insert>
    <!--查询
    resultType="blog" 直接这样写是因为在核心配置文件mybatis-config.xml中设置了别名
    <typeAliases>
        <package name="com.xxx.pojo"/>
    </typeAliases>
    -->
    <select id="queryBlogIF" parameterType="map" resultType="blog">

        select *
        from mybatis.blog where 1=1
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </select>

</mapper>

3.测试

代码: queryBlogIF

import com.xxx.dao.BlogMapper;
import com.xxx.pojo.Blog;
import com.xxx.utils.IDUtils;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class MyTest {
    @Test
    public void addBlog() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        //new一个实体类,设置数据
        Blog blog = new Blog();
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Mybatis如此简单");
        blog.setAuthor("fj学习");
        blog.setCreateTime(new Date());
        blog.setViews(9999);
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Spring如此简单");
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("微服务如此简单");
        //添加数据
        mapper.addBlog(blog);
        sqlSession.close();
    }

    @Test
    public void queryBlogIF() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
       // hashMap.put("title", "Java如此简单");
        hashMap.put("author", "fj学习");
        List<Blog> blogs = mapper.queryBlogIF(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }
}

结果:

Blog(id=7b047e82deda4ef7bb6f1a3f9beb5d3d, title=Mybatis如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=9999)
Blog(id=f4b1d31b446b4802a2c24eef95f1de10, title=Spring如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=9999)
Blog(id=5404fcd424c34c639cdf4a573f22415a, title=微服务如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=9999)
Blog(id=55985622c552148f6684226e56qwd5gf, title=Java如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=1000)

Process finished with exit code 0

3. trim(where、set)

1. where

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

代码为:

   <!--查询,根据查询的条件搜索
    resultType="blog" 直接这样写是因为在核心配置文件mybatis-config.xml中设置了别名
    <typeAliases>
        <package name="com.xxx.pojo"/>
    </typeAliases>
    <where> 标签   </where>只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
    -->
    <select id="queryBlogIF" parameterType="map" resultType="blog">

        select *
        from mybatis.blog
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>

    </select>

测试:

import com.xxx.dao.BlogMapper;
import com.xxx.pojo.Blog;
import com.xxx.utils.IDUtils;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class MyTest {
    @Test
    public void addBlog() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        //new一个实体类,设置数据
        Blog blog = new Blog();
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Mybatis如此简单");
        blog.setAuthor("fj学习");
        blog.setCreateTime(new Date());
        blog.setViews(9999);
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Spring如此简单");
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("微服务如此简单");
        //添加数据
        mapper.addBlog(blog);
        sqlSession.close();
    }

    @Test
    public void queryBlogIF() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        hashMap.put("title", "Java如此简单");
        hashMap.put("author", "fj学习");
        List<Blog> blogs = mapper.queryBlogIF(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }
}

2.set

set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
代码:

<!-- set 删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)-->
    <update id="updateBlog" parameterType="map">
        update mybatis.blog
        <set>
            <if test="title !=null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author}
            </if>
        </set>
        where id = #{id};
    </update>

测试:

 @Test
    public void updateBlog() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        hashMap.put("title", "Java如此简单");
        //hashMap.put("author", "fj学习");
        hashMap.put("id", "1");
        int i = mapper.updateBlog(hashMap);
        System.out.println(i);
        sqlSession.close();
    }

3. trim

<trom prefix="" prefix="" prefixOverrides="" suffix="" suffixOverrides=""></trom>

在这里插入图片描述
在这里插入图片描述

4. choose、when、otherwise

在这里插入图片描述
Choose 相当于 switch case ,只满足一个条件就结束.
代码为:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--总:configuration核心配置文件-->
<mapper namespace="com.xxx.dao.BlogMapper">
    <!--添加-->
    <insert id="addBlog" parameterType="blog">
        insert into mybatis.blog (id, title, author, create_time, views)
        values (#{id}, #{title}, #{author}, #{createTime}, #{views});
    </insert>
    <!--查询,根据查询的条件搜索
    resultType="blog" 直接这样写是因为在核心配置文件mybatis-config.xml中设置了别名
    <typeAliases>
        <package name="com.xxx.pojo"/>
    </typeAliases>
    <where> 标签   </where>只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
    -->
    <select id="queryBlogIF" parameterType="map" resultType="blog">

        select *
        from mybatis.blog
        <where>
            <if test="title != null">
                title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>

    </select>

    <!--  Choose 相当于 switch case ,只满足一个条件就结束 -->
    <select id="queryBlogChoose" parameterType="map" resultType="blog">
        select *
        from mybatis.blog
        <where>
            <choose>
                <when test="title != null">
                    title = #{title}
                </when>
                <when test="author != null">
                    and author = #{author}
                </when>

                <otherwise>
                    and views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>
</mapper>

测试为:

import com.xxx.dao.BlogMapper;
import com.xxx.pojo.Blog;
import com.xxx.utils.IDUtils;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.List;

public class MyTest {
    @Test
    public void addBlog() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        //new一个实体类,设置数据
        Blog blog = new Blog();
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Mybatis如此简单");
        blog.setAuthor("fj学习");
        blog.setCreateTime(new Date());
        blog.setViews(9999);
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("Spring如此简单");
        //添加数据
        mapper.addBlog(blog);
        //设置数据
        blog.setId(IDUtils.getId());
        blog.setTitle("微服务如此简单");
        //添加数据
        mapper.addBlog(blog);
        sqlSession.close();
    }

    @Test
    public void queryBlogIF() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        hashMap.put("title", "Java如此简单");
        hashMap.put("author", "fj学习");
        List<Blog> blogs = mapper.queryBlogIF(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }


    @Test
    public void queryBlogChoose() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        hashMap.put("title", "Java如此简单");
        hashMap.put("author", "fj学习");
        hashMap.put("views", "9999");
        List<Blog> blogs = mapper.queryBlogChoose(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }
}

结果为:

Blog(id=55985622c552148f6684226e56qwd5gf, title=Java如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=1000)

Process finished with exit code 0

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

5.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 mybatis.blog
        <where>
            <include refid="if-title-author"></include>
        </where>

    </select>

注意事项:
最好基于单表来定义SQL片段,简单些不要有太多的链表查询
不要存在where标签,只需要简单if判断

6.Foreach

在这里插入图片描述

1. 数据库数据

在这里插入图片描述

2.接口类

   //查询1-2-3号记录的博客
    List<Blog> queryBlogForeach(Map map);

3. mapper.xml

 <!--select * from mybatis.blog where 1=1 and (id =1 or id = 2 0r id = 3)
        现在传递一个万能map,这个map中可以存在一个集合
    -->
    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from mybatis.blog
        <where>
          <foreach collection="ids" item="id" open="and (" close=")" separator="or">
              id = #{id}
          </foreach>
        </where>
    </select>

4.测试

  @Test
    public void queryBlogForeach() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
        HashMap hashMap = new HashMap();
        ArrayList<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
        hashMap.put("ids", ids);
        List<Blog> blogs = mapper.queryBlogForeach(hashMap);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
        sqlSession.close();
    }

结果:

Blog(id=1, title=Mybatis如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=9999)
Blog(id=2, title=Spring如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=9999)
Blog(id=3, title=微服务如此简单, author=fj学习, createTime=Fri Oct 22 14:28:38 CST 2021, views=9999)

Process finished with exit code 0

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:先在Mysql中写出完整的SQL,再对应的去修改成我们的动态SQL实现通用即可

十三、 缓存

1. 缓存简介

  • 查询 →需要连接数据库→就很耗资源!

  • 一次查询的结果,给他暂存一个可以直接取到的地方 --> 内存:缓存

  • 我们再次查询的相同数据的时候,直接走缓存,不走数据库了

  • 下面memcached就是缓存。使用缓存可以减少服务器压力。从数据库查询的数据存入缓存,第二次可以直接读取缓存
    在这里插入图片描述

  • 1、什么是缓存[Cache]?

  • 存在内存中的临时数据

  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库文件)查询,

  • 从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题

  • 2、为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率

  • 3、什么样的数据可以使用缓存?

  • 经常查询并且不经常改变的数据 【可以使用缓存】

2. Mybatis缓存

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便的定制和配置缓存,缓存可以极大的提高查询效率。
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存
默认情况下,只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存)
二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
为了提高可扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来定义二级缓存。
可用的清除策略有:

LRU – 最近最少使用:移除最长时间不被使用的对象。(默认LRU)
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

3. 一级缓存

  • 一级缓存也叫本地缓存:SqlSession
  • 与数据库同一次会话期间查询到的数据会放在本地缓存中
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库

1. 开启日志log4j

1. pom.xml导入
 <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
2. 创建配置文件

路径:src/main/resources/log4j.properties
代码:

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
#控制台输出由ConsoleAppender
#日志实现结果System.out
#日志实现的级别DEBUG

#日志格式[%c]-%m%n
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
#文件输出的相关设置
#File输出保存日志的地址
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

3. 核心配置设置

路径:src/main/resources/mybatis-config.xml
代码:

 <settings>
        <!--设置日志-->
        <setting name="logImpl" value="log4j"/>
    </settings>

2.测试

测试在一个Session中查询两次记录

1.实体类

地址:src/main/java/com/xxx/pojo/User.java
代码:

package com.xxx.pojo;

import lombok.Data;

@Data
public class User {
    private int id;
    private String name;
    private String pwd;

}

2.接口类

地址:src/main/java/com/xxx/dao/UserMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.User;
import org.apache.ibatis.annotations.Param;

public interface UserMapper {
    //根据id查询用户
    User queryUserById(@Param("id") int id);
}

3. mapper.xml

地址:src/main/java/com/xxx/dao/UserMapper.xml
代码:

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxx.dao.UserMapper">

    <select id="queryUserById" resultType="user">
        select *
        from user
        where id = #{id}

    </select>
</mapper>


4.测试

地址:src/test/java/MyTest.java
代码:

import com.xxx.dao.UserMapper;
import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class MyTest {

    @Test
    public void queryUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        System.out.println("==================================");
        User user2 = mapper.queryUserById(1);
        System.out.println(user2);

        System.out.println(user == user2);
        sqlSession.close();
    }
}

5. 结果

在这里插入图片描述

3. 缓存失效的情况

1.查询不同的东西

在这里插入图片描述

2.增删改操作,可能会改变原来的数据,所以必定会刷新缓存
1.实体类

地址:src/main/java/com/xxx/pojo/User.java
代码:

package com.xxx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;

}

2. 接口类

地址:src/main/java/com/xxx/dao/UserMapper.java
代码:

package com.xxx.dao;

import com.xxx.pojo.User;
import org.apache.ibatis.annotations.Param;

public interface UserMapper {
    //根据id查询用户
    User queryUserById(@Param("id") int id);

    int updateUserById(User user);
}

3.mapper.xml

地址:src/main/java/com/xxx/dao/UserMapper.xml
接口

<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxx.dao.UserMapper">

    <select id="queryUserById" resultType="user">
        select *
        from user
        where id = #{id}

    </select>
    
    <update id="updateUserById" parameterType="user" >
        update mybatis.user set name = #{name} , pwd = #{pwd} where id = #{id}
    </update>
</mapper>


4.测试
import com.xxx.dao.UserMapper;
import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class MyTest {

    @Test
    public void queryUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        mapper.updateUserById(new User(2,"aaa","bbb"));
        System.out.println("==================================");
        User user2 = mapper.queryUserById(1);
        System.out.println(user2);
        System.out.println(user == user2);
        sqlSession.close();
    }
}

5. 结果

在这里插入图片描述

3.查询不同的Mapper.xml
4. 手动清理缓存

测试代码:

import com.xxx.dao.UserMapper;
import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class MyTest {

    @Test
    public void queryUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
      //  mapper.updateUserById(new User(2,"aaa","bbb"));
        //手动清理缓存
        sqlSession.clearCache();
        System.out.println("==================================");
        User user2 = mapper.queryUserById(1);
        System.out.println(user2);
        System.out.println(user == user2);
        sqlSession.close();
    }
}

结果分析:
在这里插入图片描述

4. 小结

  • 一级缓存默认是开启的,只在一次SqlSession中有效,也就是拿到连接到关闭连接这个区间段

4. 二级缓存

  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
  • 工作机制:
    。 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    。如果会话关闭了,这个会员对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
    。 新的会话查询信息,就可以从二级缓存中获取内容
    。 不同的mapper查询出的数据会放在自己对应的缓存(map)中

1. 步骤

1. 开启全局缓存

地址:src/main/resources/mybatis-config.xml
代码:

    <!--开启全局缓存-->
        <setting name="cacheEnabled" value="true"/>
2. 使用缓存

地址:src/main/java/com/xxx/dao/UserMapper.xml

  1. 在要使用二级缓存的Mapper中开启
    代码:
   <!--在当前mapper.xml使用二级缓存-->
      <cache/>
  1. 也可以自定义一些参数
    代码:
   <!--在当前mapper.xml使用二级缓存-->
    <cache eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>
  1. xml不使用二级缓存测试
  • 代码:测试 queryUserById2
import com.xxx.dao.UserMapper;
import com.xxx.pojo.User;
import com.xxx.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class MyTest {

    @Test
    public void queryUserById() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
      //  mapper.updateUserById(new User(2,"aaa","bbb"));
        //手动清理缓存
        sqlSession.clearCache();
        System.out.println("==================================");
        User user2 = mapper.queryUserById(1);
        System.out.println(user2);
        System.out.println(user == user2);
        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        sqlSession.close();
        System.out.println("========================================");
        User user2 = mapper2.queryUserById(1);
        System.out.println(user2);
        System.out.println(user==user2);
        sqlSession2.close();

    }
}


  • 测试结果
    在这里插入图片描述
  1. xml使用二级缓存测试
  • 代码和3一样,只是在src/main/java/com/xxx/dao/UserMapper.xml加入了使用使用二级缓存代码
   <!--在当前mapper.xml使用二级缓存-->
    <cache eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>
  • 测试结果:
    在这里插入图片描述
3.小结
1. 二级缓存使用方式
  1. 带参数使用
    运行结果正常
    <!--在当前mapper.xml使用二级缓存-->
    <cache eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>
  1. 不带参数使用
    运行结果报错:Cause: java.io.NotSerializableException: com.xxx.pojo.User
    翻译报错原因:com.xxx.pojo.User需要被序列化

    <!--在当前mapper.xml使用二级缓存-->
    <cache/>
2. 问题
  1. 我们需要将实体类序列化,否则就会报错
    运行结果报错:Cause: java.io.NotSerializableException: com.xxx.pojo.User
  2. 解决:序列化User implements Serializable
package com.xxx.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.io.Serializable;

@Data
@AllArgsConstructor
public class User  implements Serializable {
    private int id;
    private String name;
    private String pwd;

}

3. 小结
  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会放在一级缓存中
  • 只有当前会话提交,或者关闭的时候,才会提交到二级缓存中

5. 缓存原理

在这里插入图片描述
注意:

只有查询才有缓存,根据数据是否需要缓存(修改是否频繁选择是否开启useCache=“true”

  <?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xxx.dao.UserMapper">

    <!--在当前mapper.xml使用二级缓存-->
    <cache eviction="FIFO"
            flushInterval="60000"
            size="512"
            readOnly="true"/>

    <select id="queryUserById" resultType="user" useCache="true">
        select *
        from user
        where id = #{id}

    </select>
    
    <update id="updateUserById" parameterType="user" >
        update mybatis.user set name = #{name} , pwd = #{pwd} where id = #{id}
    </update>
</mapper>



6. 自定义缓存-Ehcache

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

1. 导包

  1. maven->搜索mybatis-ehcache->路径:https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache

  2. 选择版本
    在这里插入图片描述

  3. 复制代码

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>

4.pom.xml导入ehcache,刷新

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Mybatis-Study</artifactId>
        <groupId>com.xxx</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mybatis-09</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <!--导入依赖-->
    <dependencies>
        <!--导入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>provided</scope>
        </dependency>
        <!--导入log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!--导入ehcache-->
        <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
        <dependency>
            <groupId>org.mybatis.caches</groupId>
            <artifactId>mybatis-ehcache</artifactId>
            <version>1.2.1</version>
        </dependency>
    </dependencies>
</project>

2. 导入到mapper.xml中

地址:src/main/java/com/xxx/dao/UserMapper.xml
代码:

   <!--在当前mapper.xml使用二级缓存-->
    <cache  type="org.mybatis.caches.ehcache.EhcacheCache"/>

3. 编写配置文件

  • 新建文件:ehcache.xml
  • 文件名地址:src/main/resources/ehcache.xml
  • 问题:复制到项目后xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"路径是红色的报错
  • 解决:alt+enter ->fetch (弹窗后默认第一个)导入,就不报错了。

代码:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--
       diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
       user.home – 用户主目录
       user.dir – 用户当前工作目录
       java.io.tmpdir – 默认临时文件路径
     -->
    <diskStore path="./tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    <!--
       defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个。
     -->
    <!--
      name:缓存名称。
      maxElementsInMemory:缓存最大数目
      maxElementsOnDisk:硬盘最大缓存个数。
      eternal:对象是否永久有效,一但设置了,timeout将不起作用。
      overflowToDisk:是否保存到磁盘,当系统当机时
      timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
      timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
      diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
      diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
      diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
      memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
      clearOnFlush:内存数量最大时是否清除。
      memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
      FIFO,first in first out,这个是大家最熟的,先进先出。
      LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
      LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
   -->

</ehcache>

4. 测试

  • 和系统带的没有太大区别
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值