MyBatis学习笔记

大家好呀,我是陌陌~

提供Markdown格式的笔记,百度网盘请自提👇

链接:https://pan.baidu.com/s/1SRyMIt4SondNm8hDFQfrdg
提取码:x1ho

文章目录

1. MyBatis简介

1.1 MyBatis特性

1) MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架

2) MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集

3) MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java

Objects,普通的Java对象)映射成数据库中的记录

4) MyBatis 是一个 半自动的ORM(Object Relation Mapping)框架

1.2 MyBatis下载

1.3 MyBatis特点

轻量级,性能出色

SQL 和 Java 编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据

开发效率稍逊于HIbernate,但是完全能够接受

2.搭建MyBatis

2.1 开发环境

IDE : IDEA2019.2

构建工具:maven 3.5.4

MySql版本:Mysql8MyBatis版本:MyBatis

2.2 创建maven工程

  1. 打包方式:jar

  2. 引入依赖

    <dependencies>
                   <dependency>
                       <groupId>org.mybatis</groupId>
                       <artifactId>mybatis</artifactId>
                       <version>3.5.7</version>
                   </dependency>
                   <dependency>
                       <groupId>mysql</groupId>
                       <artifactId>mysql-connector-java</artifactId>
                       <version>8.0.16</version>
                   </dependency>
                   <dependency>
                       <groupId>junit</groupId>
                       <artifactId>junit</artifactId>
                       <version>4.12</version>
                       <scope>test</scope>
                   </dependency>
        </dependencies>
    

2.3 创建MyBatis的核心配置文件

<environments default="development">
    <!--environment:配置某个具体的环境 属性:id:表示连接数据库的环境的唯一标识,不能重复 -->
    <environment id="development">
        <!--transactionManager:设置事务管理方式 属性:type="JDBC|MANAGED" JDBC:表示当前环境中,执行SQL时,使用的是JDBC中原生的事务管理方式,事 务的提交或回滚需要手动处理MANAGED:被管理,例如Spring -->
        <transactionManager type="JDBC"/>
        <!--dataSource:配置数据源 属性:type:设置数据源的类型 type="POOLED|UNPOOLED|JNDI" POOLED:表示使用数据库连接池缓存数据库连接 UNPOOLED:表示不使用数据库连接池 JNDI:表示使用上下文中的数据源 -->
        <dataSource type="POOLED"> <!--设置连接数据库的驱动-->
            <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
            <!--设置连接数据库的连接地址-->
            <property name="url" value="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"/>
            <!--设置连接数据库的用户名-->
            <property name="username" value="root"/>
            <!--设置连接数据库的密码-->
            <property name="password" value="123456"/>
        </dataSource>
    </environment>
</environments>

2.4 创建mapper接口

Mybatis中的mapper接口相当于以前的dao,但是区别在于,mapper仅仅是接口,我们不需要提供实现类

public interface UserMapper {
    int insertUser();
}

2.5 创建MyBatis的映射文件

相关概念:ORM(Object Relationship Mapping)对象关系映射

对象:java中的实体类对象

关系:关系型数据库

映射:二者之间的对应关系

  1. 映射文件的命名规则:

    表所对应的实体类的类名+Mapping.xml

    例如:表t_user对应的实体类是Usr,所对应的映射文件是UserMapper.xml

    因此一个映射文件对应一个实体类。对应一张表的操作

    MyBatis映射文件用于编写SQL语句,访问以及操作表中的数据

    MyBatis映射文件存放的位置是src/main/resources/mappers目录下

  2. MyBatis中可以面向接口操作数据,要保证一致

    mapper接口的全类名和映射文件的命名空间(namespace)保持一致

    mapper接口中的方法民和映射文件中编写SQL的标签的id熟悉保持一致

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace 的路径要和mapper接口的全类名保持一致-->
<mapper namespace="com.lh.mybatis.mapper.UserMapper">
    <!--
        mapper接口要和映射文件要保证两个一致
        1. mapper接口的全类名和映射文件的namespace一致
        2. mapper中的方法名要和映射文件中的sql的id保持一致
    -->
<!--    int insertUser();方法民要和sql语句的id保持一致-->
    <insert id="insertUser">
        insert into t_user values (null,"admin",'123456',12,'男','12345@qq.com')
    </insert>
</mapper>

在MyBatis的核心配置文件中写上映射

<!--引入mybatis的映射文件-->
<mappers>
    <mapper resource="mappers/UserMapper.xml"/>
</mappers>

2.6 测试

@Test
public  void testInsert() throws IOException {
    //1. 获取好像配置文件的输入流
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    //2. 获取SqlSessionFactoryBuilder对象
    SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
    //3. 获取sqlSessionFactory对象
    SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(is);
    //4. 获取sql的会话对象sqlSession;是myBatis提供的操作数据库的对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //5. 获取UserMapper的代理实现类对象
    /*通过UserMapper全类名找到MyBatis映射文件,再通过UserMapper中的方法找到映射文件中的sql语句来执行,并且返回值*/
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    //6. 调用mapper中的方法,来实现添加用户信息的功能
    int result = mapper.insertUser();
    System.out.println("结果:"+result);
    /*得我们手动提交事务*/
        sqlSession.commit();
    //7. 关闭sqlSession
    sqlSession.close();
}

注意

如果没有事务的提交这一代码,我们的操作是不会执行的,但是当我们写上了sqlSession.commit()再起添加的时候,发现id值并不是从1开始的,原因就是我们之前执行了insert但是没有提交

2.7 1 增删改

2.7.2 查询

public void tstGetByUserId(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    System.out.println(mapper.getUserById());
    List<User> allUser = mapper.getAllUser();
    allUser.forEach(System.out::println);

    sqlSession.close();
}
 /**
     * 根据id来查询用户信息
     * @return
     */
User getUserById();


/**
     * 查询所有的用户信息
     * @return
     */
List<User> getAllUser();
<!--
        resultType:设置结果类型,即查询的数据要转换为的java类型
        resultMap:自定义映射,处理多对一,一对多的映射关系
        这两个熟悉只能设置一个,有你没我
    -->
<select id="getUserById" resultType="com.lh.mybatis.pojo.User">
    select * from t_user where id = 1
</select>
<select id="getAllUser" resultType="com.lh.mybatis.pojo.User">
    select * from t_user
</select>
image-20221008172432931

2.7 细节

可以设置主动提交

 //4. 获取sql的会话对象sqlSession(不会主动提交事务);是myBatis提供的操作数据库的对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//4. 获取sql的会话对象sqlSession(会主动提交事务);是myBatis提供的操作数据库的对象
SqlSession sqlSession1 = sqlSessionFactory.openSession(true);

执行insert语句也可以直接如下,很少使用

sqlSession.insert("com.lh.mybatis.mapper.UserMapper.insertUser");

2.8 添加日志功能

2.8.1 添加依赖

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

2.8.2 加入log4j的配置文件

log4j的配置文件名为log4j.xml,存放的位置是src/main/resources目录下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<!--    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">-->
    <log4j:configuration debug="true">
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
        <param name="Encoding" value="UTF-8" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS}
%m  (%F:%L) \n" />
        </layout>
    </appender>
    <logger name="java.sql">
        <level value="debug" />
    </logger>
    <logger name="org.apache.ibatis">
        <level value="info" />
    </logger>
    <root>
        <level value="debug" />
        <appender-ref ref="STDOUT" />
    </root>
</log4j:configuration>

日志级别

FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试)

从左到右打印的越来越详细;打印出来的是大于等于当前日志级别的信息

2.9 使用properties文件配置mysql相关信息

2.9.1 相关步骤

在resource目录下创建jdbc.proprties文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.username=root
jdbc.password=123456

在MyBatis的核心配置文件中使用properties标签映入文件

<properties resource="jdbc.properties"/>

在MyBaitis的核心配置文件中使用${value}的方式映入

<dataSource type="POOLED"> <!--设置连接数据库的驱动-->
    <property name="driver" value="${jdbc.driver}"/>
    <!--设置连接数据库的连接地址-->
    <property name="url" value="${jdbc.url}"/>
    <!--设置连接数据库的用户名-->
    <property name="username" value="${jdbc.username}"/>
    <!--设置连接数据库的密码-->
    <property name="password" value="${jdbc.password}"/>
</dataSource>

2.10 MyBaties核心配置文件中的其它标签介绍

2.10.1 typeAliases

typeAliases表示为某个具体的类型来设置一个别名,在MyBatis范围中我们就可以使用别名来表示具体的类型

<!--注意:配置文件中的相关的标签是有配置顺序的-->
<!--
        MyBatis中二档标签要按照顺序来配置
        The content of element type "configuration" must match "(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?
        ,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
    -->
1) typeAlias

注意下边我写了两种配置别名的方式

<typeAliases>
        <!--为com.lh.mybatis.pojo.User起别名为abc-->
        <!--
            type属性:设置想要起别名的类型
            alias:设置某个类型的别名
        -->
		<typeAlias type="com.lh.mybatis.pojo.User" alias="abc"></typeAlias>
        <!--这样设置的别名有默认的别名:它的类名,且不区分大小写-->
        <typeAlias type="com.lh.mybatis.pojo.User"></typeAlias>
</typeAliases>
2) package

通过包来设置类型的别名,指定包下所有的类型将全部拥有默认的别名,用其类名且不区分大小写

<typeAliases>  
    <package name="com.lh.mybatis.pojo"/>
</typeAliases>

2.10.2 mappers

1) mapper
<mappers>
    <mapper resource="mappers/UserMapper.xml"/>
</mappers>

来引入MyBaties的映射文件的!当表多了,映射就多了,映射文件的引入就变得繁琐了

2) package(通过包的方式引入映射)

package是以包的方式来引入映射文件的,但是必须要满足两个条件

  1. 你的mapper接口和映射文件所在的包必须一致

    java目录和resources目录加载之后在目录中,即虽然我们表面看resources和java是两个目录,但是加载完之后里面的内容会在同一个目录下,不会说你加载完之后,再创建一个java目录和resources目录

  2. mapper接口的名字和映射文件的名字保持一致

<mappers>
    <package name="com.lh.mybatis.mapper"/>
</mappers>

注意:

当我们创建目录的时候,写法不能是"."了,按下回车,不然给你创建一个叫 com.lh.mybatis.mapper的目录出来了,创建目录和创建包的方式是不同的

image-20221008200717918

2.11 使用模板来搭建MyBatis

设置——>Editor——>File and Code Templates

记住模板应该设置在文件下面,而不是包含,如下!

image-20221008203135109

3. MyBatis获取参数值

  1. 先搭建MyBatis

3.1 MyBatis获取参数的两种方式

MyBatis获取参数的两种方式:${}和&{}

${}就是字符串的拼接,#{}方式的本质就是占位符赋值

${}:如果是字符串类型或者日期类型的字段进行赋值时,想要手动加单引号 ;会造成sql注入

#{}:如果时字符串或者日期类型的字段进行赋值时,可自动添加单引号;可以避免sql注入

更常用的是#{}但是在特殊情况下,必须使用${}

3.2 单个字面量类型的参数

字面量:字符串,基本数据类型,包装类

大括号里边可以写任何东西(但是${}里边不可以写数字)

  1. 如果mapper接口方法的参数为单个的字面量类型,此时可以通过#{} 和${} 以任意的内容来获取参数值,但是一定要注意${}的单引号问题,因为#{}的本质时占位符赋值,而${}的本质时字符串拼接

  2. 如果mapper的参数是多个字面量的类型,此时MyBatis会将参数放在map集合中,以两种方式来存储数据

    1. 以arg0,arg1…为map集合的键,以参数为值
    2. 以param1,param2…为键,以参数为值

    因此我们只需要通过 ${}和#{}来访问map的键来取值,神奇的是可以param和arg可以混合使用,但是不要作哦~

  3. 如果mapper接口的参数是map集合类型的参数

    只需要通过${}和#{}来访问map集合的键,还是要注意${}的的单引号问题

  4. 如果mapper接口方法的参数是实体类类型的参数,我们只需要通过${}和#{}来访问我们实体类中的属性名

    只需要通过#{}和${}访问实体类中的属性名,就可以获取相对应的属性值,一定要注意${}的单引号问题

    属性名只和get和set方法有关,将get和set去掉,剩余部分第一个字母小写的过程就是我们当前的属性名字

  5. 我们可以在mapper接口方法的参数上来设置param注解

    此时MyBatis会将这些参数放在map中,以两种方式进行存储

    1. 以@param注解的value属性值为键,以参数值为值
    2. 以param1,param2…为键以参数为值

情 况 一 \textcolor{green}{情况一}

<select id="getUserByUserName" resultType="User">
    <!--方式一-->
    select * from t_user where username = #{username}
    <!--方式二-->
    select * from t_user where username = '${username}'
</select>

情 况 二 \textcolor{green}{情况二}

<select id="checkLogin" resultType="User">
    <!--方式一-->
    select * from t_user where username=#{arg0} and password = #{arg1}
    <!--方式二-->
    select * from t_user where username='${param1}' and password = '${param2}'
</select>
<!--注意xml文件中的注释用的不是/**/,如果用它会报错的-->

情 况 三 \textcolor{green}{情况三}

@Test
public void tstGetUserByMap(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String,Object> map = new HashMap<>();
    map.put("username","王一博");
    map.put("password","123");
    System.out.println(mapper.checkLoginByMap(map));
    sqlSession.close();
}
<!--checkLoginByMap(Map<String,Object> map);-->
<select id="checkLoginByMap" resultType="User">
    select * from t_user where username='${userName}' and password = '${password}'
</select>

情 况 四 \textcolor{green}{情况四}

  1. 当属性和成员变量一致的时候,没有成员变量的情况下不影响我们获取属性,只和我们的get和set方法有关
  2. 如果要取值就找get,如果要赋值就找set,然后我们将方法名中的get和set去掉,剩余部分的内容首字母变为小写的结果就是属性
@Test
public void tstInsertUser(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    mapper.insertUser(new User(null,"肖战","123456",33,"男","123@qq.com"));
    sqlSession.close();
}
<!--void insertUser(User user);-->
<select id="insertUser">
    <!--当属性和成员变量一致的时候,没有成员变量的情况下不影响我们获取属性,只和我们的get和set方法有关-->
    <!--如果要取值就找get,如果要赋值就找set,然后我们将方法名中的get和set去掉,剩余部分的内容首字母变为小写的结果就是属性-->
    insert into t_user values(null,#{userName},#{password},#{age},#{gender},#{email})
</select>

情 况 五 ( 常 用 ) \textcolor{green}{情况五(常用)} ()

这个时候我们可以在select中使用arg、param、你设置的参数名

@Test
public void testByParam(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    System.out.println(mapper.checkLoginByParam("王一博", "123"));
    sqlSession.close();
}
<!--    User checkLoginByParam(@Param(value="username") String username, @Param("password") String password);-->
<select id="checkLoginByParam" resultType="User">
    select * from t_user where username=#{username} and password= #{password}
</select>
 /**
     * 验证登录(使用@Param注解)
     * @return
     */
User checkLoginByParam(@Param(value="username") String username, @Param("password") String password);

4. MyBatis的各种查询功能

5.1 查询一个实体类对象

如果sql语句查询的结果为多条时,不要实体类作为方法的返回值,如果查询的结果为一条或多条时候,可以使用List集合来查询

@Test
public void test1(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    System.out.println(mapper.getUserById(4));
    sqlSession.close();
}
<!--User getUserById(@Param("id")Integer id);-->
<select id="getUserById" resultType="User">
    select * from t_user where id=#{id}
</select>
<!--List<User> getAllUser();-->
<select id="getAllUser" resultType="User">
    select * from t_user
</select>

5.2 查询List集合

@Test
public void test2(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    mapper.getAllUser().forEach(System.out::println);
    sqlSession.close();
}
<!--User getUserById(@Param("id")Integer id);-->
<select id="getUserById" resultType="User">
    select * from t_user where id=#{id}
</select>
<!--List<User> getAllUser();-->
<select id="getAllUser" resultType="User">
    select * from t_user
</select>

5.3 查询其它

我们发现在配置接口映射文件的时候,我们对于返回值的别名可以写Java.lang.Integer或者Integer或者integer或者int…

MyBatis为我们的java中常用的类型设置类型别名
Integer:Integer,int
int:_int ,_integer

Map : map

String : string

@Test
public void test3(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    Integer count = mapper.getCount();
    System.out.println(count);
    sqlSession.close();
}
<!--Integer getCount();-->
<select id="getCount" resultType="java.lang.Integer">
    select count(*) from t_user
</select>

5.5 查询一条数据为map集合

并不是说你查寻出来的sql结果都有实体类与之对应

比如说查询一个部门的最高薪资,平均薪资…

以map作为返回值,你查询出来的东西会以字段名作为键,字段值作为值

当某个字段的值为Null的时候,并不会放到map集合中

 /**
     * 通过id来获取值,以map的形式返回
     * @return
     */
Map<String,Object> getUserByIdToMap(Integer id);
<!--getUserByIdToMap(Integer id);-->
<!--我们现在不是要将起转换为实体类对象,而是要将其转换map-->
<select id="getUserByIdToMap" resultType="map">
    select * from t_user where id = #{id}
</select>
 @Test
    public void test4(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
        /**
         * 将数据查询出来后,就会以字段名为键以字段值为值
         */
        Map<String, Object> map = mapper.getUserByIdToMap(9);
        System.out.println(map);
        sqlSession.close();
    }

5.6 查询多条数据为map集合

这种情况一般是查询的结果没有对应的实体类,我们就将其放到map集合中去

傻子别想了~会报错,一个map只能对应一条记录,相当于你之前学过的查询一个实体类返回值为User但是,实际返回值为多个User的时候就会报错

org.apache.ibatis.exceptions.TooManyResultsException:

当我们查询的数据有多条时候,并且要将每条数据转换为map集合

此时我们有两种方法

  1. 将mapper接口方法的返回值设置为泛型是Map的List集合
  2. 可以将每条数据转换的Map集合放在一个大的Map集合中,但是必须要通过@MapKey()这个注解将查询的某个字段的值作为一个大的map的键

5.6.1 解决TooManyResultsException

1)方法一(常用)

将Map集合存放在List集合中

而底层会将你查询出来的数据,以字段名为键,以字段值为值,封装为map集合,所以resultType写的是map

/**
     * 查询所有的与用户信息为map集合
     * @return
     */
List<Map<String,Object>> getAllUserToMap();
<!-- List<Map<String,Object>> getAllUserToMap();-->
<select id="getAllUserToMap" resultType="map">
    select * from t_user
</select>
@Test
public void test5(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    List<Map<String, Object>>list = mapper.getAllUserToMap();
    System.out.println(list);
    sqlSession.close();
}
2)方法二

使用@MapKey注解

将我们当前查询的数据所转换的Map集合,放到一个大的Map中,然后我们可以设置这个大的Map集合的键

@MapKey("id")/*以id为键*/
Map<String,Object> getAllUserToMap();
<!--Map<String,Object> getAllUserToMap();-->
<select id="getAllUserToMap" resultType="map">
    select * from t_user
</select>
 @Test
public void test5(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SelectMapper mapper = sqlSession.getMapper(SelectMapper.class);
    Map<String,Object> map = mapper.getAllUserToMap();
    System.out.println(map);
    sqlSession.close();
}
image-20221009093437313

5.特殊SQL的执行

5.1 模糊查询

注意:这种情况如果你使用#{}来匹配,解析之后SQL语句就是:select * from t_user username like %?%

这个时候?是不会被当作占位符来解析的,它是字符串中的一部分了!在调用set方法给占位符赋值的是,解析都会出错

5.1.1 方式一

/**
     * 通过用户名模糊查询用户信息
     * @param mohu
     * @return
     */
List<User> getUserByLike(@Param("mohu")String mohu);
 <!--    List<User> getUserByLike(@Param("mohu")String mohu);-->
<select id="getUserByLike" resultType="User">
    select * from t_user where username like '%${mohu}%'
</select>
@Test
public void testGetUsrByLike(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    List<User> list = mapper.getUserByLike("肖");
    list.forEach(System.out::println);
    sqlSession.close();
}

5.1.2 方式二

使用字符串拼接函数,解决#{}的问题

<!--    List<User> getUserByLike(@Param("mohu")String mohu);-->
<select id="getUserByLike" resultType="User">
    select * from t_user where username like concat('%',#{mohu},'%')
</select>

5.1.3 方式三(常用+建议)

注意一定要使用双引号

<!--    List<User> getUserByLike(@Param("mohu")String mohu);-->
<select id="getUserByLike" resultType="User">
    select * from t_user where username like "%"#{mohu}"%"
</select>

5.2 批量删除

注意这里的批量删除语句是不能使用#{}的,使用它的化,sql语句最终会变为delete from t_user where id in(‘9,10’),这本来就是个错误的SQL语句

要使用${}来进行删除操作

/**
     * 批量删除
     * @param ids
     */
void deleteMoreUser(@Param("ids")String ids);
<!--void deleteMoreUser(@Param("ids")String ids);//ids:9,10-->
<select id="deleteMoreUser" >
    delete from t_user where id in(${ids})
</select>
@Test
public void testDeleteMoreUser(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    mapper.deleteMoreUser("5,6");
    /*#{}本质就是赋值,它会给我们赋的值两边添加单引号,*/
    sqlSession.close();
}

5.3 动态设置表名

如果使用#{}的话,sql语句中的表名就会被加上单引号;只能私用${}

/**
     * 动态设置表名,案例查询用户信息
     * @param tableName
     * @return
     */
List<User> getUserList(@Param("tableName")String tableName);
<!--List<User> getUserList(@Param("tableName")String tableName);-->
<select id="getUserList" resultType="User">
    select  * from ${tableName}
</select>
@Test
public void testGetUserListByTableName(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    List<User> user = mapper.getUserList("t_user");
    user.forEach(System.out::println);
    sqlSession.close();
}

5.4 添加功能获取自增主键

场景模拟

  1. 添加班级信息
  2. 获取添加班级的id
  3. 为班级分配学生,即将某学生id修改为新添加的班级id
/**
     * 添加用户信息,并获取自增的主键
     * @param user
     */
void insertUser(User user);//如果是个实体类类型的参数,只需要写上参数名就可以了,不需要@Param()

重要知识解释

  1. useGeneratedKeys=“true” :表示当前添加功能使用自增的主键
  2. keyProperty=“id” : 表示将添加的数据的自增主键给实体类型的某个参数的属性赋值
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    insert into t_user values(null,#{userName},#{password},#{age},#{gender},#{email})
</insert>
@Test
public void tstInsertUsr(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    SpecialSQLMapper mapper = sqlSession.getMapper(SpecialSQLMapper.class);
    User user = new User(null, "林一", "123", 23, "男", "123@qq.com");
    mapper.insertUser(user);
    System.out.println(user);
    sqlSession.close();
}

6. 自定义映射 resultMap

6.1 resultMap处理字段和属性的映射关系

如果字段名和实体类中的属性名不一致,甚至是表名也不一致,则可以通过resultMap设置自定义映射

6.1.1 方式一

给字段名起别名,和属性名保持一致(麻烦)

<!--Emp getEmpByEmpId(@Param("empId") Integer empId);-->
<select id="getEmpByEmpId" resultType="Emp">
    select emp_id empId,emp_name empName,age,gender from t_emp where emp_id = #{empId}
</select>

6.1.2 方式二

当字段符合MySql要求使用的是_,而属性符合java的要求使用驼峰

可以再MyBatis的核心配置文件中设置一个全局配置,可以自动将 _ 映射为驼峰

<settings>
    <!--映射下划线为驼峰-->
    <!--
		emp_id : empId   emp_name : empName
	-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

配置以上的代码就可以实现MySql中的_ 设置和驼峰的映射了~

6.1.3 方法三

使用resultMap自定义映射处理

image-20221009160425992

重点知识详解:

  1. resultMap : 设置自定义映射的关系
  2. id : 唯一标识
  3. type : 处理映射关系的实体类的类型
  4. 常用的标签
    1. id标签:处理主键和实体类中属性的映射关系
    2. result :处理普通字段和实体类中属性的映射关系
      1. column : 设置映射关系中的字段名,必须是sql查询出来的某个字段
      2. property :设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名
<!--resultMap中写某个resultMap配置的id-->
<!--就是查询出来的字段和那个实体中的属性不一致-->
<resultMap id="empResultMap" type="Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
</resultMap>
<select id="getEmpByEmpId" resultMap="empResultMap" >
    select * from t_emp where emp_id = #{empId};
</select>

6.2 resultMap处理多对一的映射关系

小规律:对一:对应的是个对象;对多:对应的是集合💡

/**
 * @author 陌陌~
 * @version 1.0
 */
public class Emp {
    private Integer empId;
    private String empName;
    private Integer age;
    private String gender;
    private Dept dept;//注意它是个对象

这个时候的我们主要问题就是要解决,这个类中实体类类型的属性的映射问题❓

处理多对一的映射关系

  1. 级联处理(不可以设用resultType【字段名要和属性名一致】)得使用ResultMap
  2. association
  3. 分步查询

6.2.1 方式一

级联方式

<!--Emp getEmpAndDeptByEmpId(@Param("empId")Integer empId);-->
<resultMap id="empAndDeptResultMap" type="Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="dept_id" property="dept.deptId"></result>
    <result column="dept_name" property="dept.deptName"></result>
</resultMap>
<select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
    select * from
    t_emp left join t_dept
    on
    t_emp.dept_id = t_dept.dept_id
    where t_emp.emp_id = #{empId};
</select>

6.2.2 方式二

association:处理多对一的映射关系(处理实体类类型的属性)

property:来设置想要处理映射关系的属性的属性名

JavaType :来设置要处理属性的类型

注意:用association的时候,实体类中的同名属性也得配置⚠

 <!--Emp getEmpAndDeptByEmpId(@Param("empId")Integer empId);-->
<resultMap id="empAndDeptResultMap" type="Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
    <association property="dept" javaType="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
    </association>
</resultMap>
<select id="getEmpAndDeptByEmpId" resultMap="empAndDeptResultMap">
    select * from
    t_emp left join t_dept
    on
    t_emp.dept_id = t_dept.dept_id
    where t_emp.emp_id = #{empId};
</select>

6.2.3 方式三

分步查询

重点知识汇总:

  1. property : 设置想要处理映射关系的属性的属性名
  2. select : 设置分步查询的sql的唯一标识
  3. column : 将查询出的某个字段作为分布查询的sql的条件
  1. 在两个对应的实体类的接口中写对应的方法
//EmpMapper接口
/**
     * 通过分步查询来获取员工信息第一步
     * @param empId
     * @return
     */
Emp getEmpAdnDeptByStep(@Param("empId") Integer empId);
//DeptMapper接口
/**
     * 通过分步查询查询员工以及对应信息的第二步
     * @return
     */
Dept getEmpAndDeptByStepTwo(@Param("deptId")Integer deptId);
  1. 写相对应的映射文件
<!--EmpMapper中的映射文件-->
<resultMap id="empAndDeptByStepResultMap" type="Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
    <association property="dept" select="" column=""></association>
</resultMap>
<!--Emp getEmpAdnDeptByStep(@Param("empId") Integer empId);-->
<select id="getEmpAdnDeptByStep" resultMap="empAndDeptByStepResultMap">
    select * from t_emp where emp_id = #{empId}
</select>
<!--Dept中的配置文件-->
<!--Dept getEmpAndDeptByStepTwo(@Param("deptId")Integer deptId);-->
<!--这里不需要使用resultMap以为在另一个映射文件中已经设置了!-->
<select id="getEmpAndDeptByStepTwo" resultType="Dept">
    select * from t_dept where dept_id = #{deptId}
</select>
  1. 关联两种方法

要关联两个方法必须要得到它的唯一标识(类全名+方法名)

将deptMapper中的那个方法的全路径放在EmpMapper映射文件中的select 的唯一标识上

<resultMap id="empAndDeptByStepResultMap" type="Emp">
    <id column="emp_id" property="empId"></id>
    <result column="emp_name" property="empName"></result>
    <result column="age" property="age"></result>
    <result column="gender" property="gender"></result>
    <association
                 property="dept"
                 select="com.lh.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                 column="dept_id">
    </association>
</resultMap>
  1. 注意:核心配置文件中的settings标签不要注销,不然查询出来的dept是空的
<settings>
    <!--映射下划线为驼峰-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
1) 分步查询的优点
1. 延迟加载

也叫做懒加载:减小内存的消耗

lazyLoadingEnabled : 延迟加载的全局开关,当开启时,所有关联对象都会延迟加载

aggressiveLazyLoading : 当开启时,任何方法的调用都会加载该对象的所有属性,否则,某个属性会按需要、加载

  1. 在核心配置文件中开启延迟加载的功能(这个是全局配置,争对所有的分步加载都有延迟加载的功效)
<!--开启延迟加载-->
<setting name="lazyLoadingEnabled" value="true"/>
<!--按需加载-->
<setting name="aggressiveLazyLoading" value="false"/>
  1. 如果我们要对某个分步操作取消延迟加载

fetchType : 在加载的环境中通过该属性来设置当前的分步查询是否使用延迟加载

eager :立即加载

lazy:延迟加载

image-20221009193648877

6.3 resultMap处理的一对多的映射关系

处理一对多的映射关系的两种方式

  1. collection 处理一对多的映射关系,处理集合类型的属性
  2. 分步查询

6.3.1 方法一

ofType:设置集合类型的属性中存储的数据的类型

/**
     * 查询部门以及部门中的员工信息
     * @param deptId
     * @return
     */
Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);
<!--Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);-->
<resultMap id="deptAndEmpResultMap"  type="Dept">
    <id column="dept_id" property="deptId"></id>
    <result column="dept_name" property="deptName"></result>
    <collection property="emps" ofType="Emp">
        <id column="emp_id" property="empId"></id>
        <result column="emp_name" property="empName"></result>
        <result column="age"  property="age"></result>
        <result column="gender" property="gender"></result>
    </collection>
</resultMap>
<select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
    select * from t_dept left join t_emp on t_dept.dept_id = t_emp.dept_id where t_dept.dept_id = #{deptId}
</select>
@Test
public void testGetDeptAndEmpByDeptId(){
SqlSession sqlSession = SqlSessionUtil.getSqlSession();
DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
Dept dept = mapper.getDeptAndEmpByDeptId(1);
System.out.println(dept);
}

6.3.2 方法二

分步查询

//DeptMapper接口
/**
     * 通过分步查询查询部门以及部门中的员工信息的第一步 
     * @param deptId
     * @return
     */
Dept getDeptAndEmpByStepOne(@Param("deptId")Integer deptId);
//EmpMapper接口
 /**
     * 通过分步查询查询部门以及部门中的员工信息的第二步
     * @param deptId
     * @return
     */
/*方法的返回值和第一步所操作的属性值一致*/
List<Emp> getDeptAndEmpByStepTwo(@Param("DeptId")Integer deptId);
<!--EmpMapper映射文件中的配置-->
<!--List<Emp> getDeptAndEmpByStepTwo(@Param("deptId")Integer deptId);-->
<select id="getDeptAndEmpByStepTwo" resultType="Emp" >
    select * from t_emp where dept_id = #{deptId}
</select>
<!--DeptMapper映射文件中的配置-->
<!--Dept getDeptAndEmpByStepOne(@Param("deptId")Integer deptId);-->
<resultMap id="deptAndEmpResultMapByStep" type="Dept">
    <id column="dept_id" property="deptId"></id>
    <result column="dept_name" property="deptName"></result>
    <collection property="emps" select="com.lh.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo" column="dept_id"></collection>
</resultMap>
<select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
    select * from t_dept where dept_id = #{deptId}
</select>

7. 动态SQL

MyBatis框架的动态SQL技术是一种根据特定条件动态拼接SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串的痛点问题

7.1 if

MyBatis的动态SQL,通过test中的表达式,来判断标签中的内容是否有效,是否会拼接到sql中

/**
     * 根据条件查询员工信息
     * @param emp
     * @return
     */
List<Emp> getEmpByCondition(Emp emp);
<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp where
    <if test="empName  != null and empName!=''">
        emp_name = #{empName}
    </if>
    <if test="age != null and age !=''">
        and age = #{age}
    </if>
    <if test="gender != null and gender != ''">
        and gender = #{gender}
    </if>
</select>
@Test
public void testGetEmpByCondition(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    Emp emp = new Emp(null,"肖战",24,"男");
    List<Emp> list = mapper.getEmpByCondition(emp);
    list.forEach(System.out::println);
    sqlSession.close();
}

注意以上的sq语句中当if中的条件都没有成立或者第一个条件不成立where之后就会直接多出一个and,这些都是bug

7.1.1 解决

在where后边添加1==1,之后的if语句中直接跟and

<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp where 1==1
    <if test="empName  != null and empName!=''">
        and emp_name = #{empName}
    </if>
    <if test="age != null and age !=''">
        and age = #{age}
    </if>
    <if test="gender != null and gender != ''">
        and gender = #{gender}
    </if>
</select>

7.2 where

这个标签就很好的解决了之前的问题

where功能

  1. 如果where中有条件成立,就会自动生成where关键字
  2. 当where后边由于拼接的原因有了and,where标签就会自动的截取掉,但是其中内容后多余的内容无法去掉
  3. 当where标签中没有成立的项,那么where标签是没有任何意义的
<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <where>
        <if test="empName  != null and empName!=''">
            emp_name = #{empName}
        </if>
        <if test="age != null and age !=''">
            and age = #{age}
        </if>
        <if test="gender != null and gender != ''">
            and gender = #{gender}
        </if>
    </where>
</select>

7.3 trim标签

会将内容后多余的and标签就会窃取掉

属性

prefix 和 suffix在标签中内容前面或后边去添加指定内容

prefixOverrides和suffixOverrides :在标签中内前面或者后边去掉指定的内容

<!--List<Emp> getEmpByCondition(Emp emp);-->
<select id="getEmpByCondition" resultType="Emp">
    select * from t_emp
    <trim prefix="where" suffixOverrides="and">
        <if test="empName  != null and empName!=''">
            emp_name = #{empName} and
        </if>
        <if test="age != null and age !=''">
            age = #{age} and
        </if>
        <if test="gender != null and gender != ''">
            gender = #{gender}
        </if>
    </trim>
</select>

7.4 choose,when,otherwise

这是一个if…else if…else if…else的结果

即只判断一个条件,当一个条件成立之后,后面的所有的条件都不会再判断了

otherwise最多设置一个

/**
     * 使用choose来查询员工信息
     * @param emp
     * @return
     */
List<Emp> getEmpByChoose(Emp emp);
<!--List<Emp> getEmpByChoose(Emp emp);-->
<select id="getEmpByChoose" resultType="Emp">
    select * from t_emp
    <where>
        <choose>
            <when test="empName != null and empName != ''">
                emp_name = #{empName}
            </when>
            <when test="age != null and age != ''">
                age = #{age}
            </when>
            <when test="gender!=null and gender != ''">
                gender = #{gender}
            </when>
        </choose>
    </where>
</select>

7.5 forEach

foreach

collection : 设置要循环的数组或集合

item : 用一个字符串标识数组或集合的每个数据

separator:设置每次循环的数据之间的分割符

open:循环的所有没人以什么开始

close:循环的所有内容以什么结束

7.5.1 批量添加

/**
     * 批量添加员工信息
     * @param emps
     */
void insertMoreEmp(@Param("emps") List<Emp> emps);
<!--void insertMoreEmp(@Param("emps") List<Emp> emps);-->
<insert id="insertMoreEmp" >
    insert into t_emp values
    <!--separator : 分隔符-->
    <foreach collection="emps" item="emp" separator=",">
        <!--当传输的是实体类对象的时候,我们可以直接写上属性名来访问-->
        (null,#{emp.empName},#{emp.age},#{emp.gender},null)
    </foreach>
</insert>
@Test
public void testInsertMoreEmp(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    DynamicSQLMapper mapper = sqlSession.getMapper(DynamicSQLMapper.class);
    Emp emp = new Emp(null,"肖战",24,"男");
    Emp emp1 = new Emp(null,"夏目",20,"男");
    Emp emp2 = new Emp(null,"少卿大人",20,"男");
    List<Emp> list = Arrays.asList(emp, emp1, emp2);
    mapper.insertMoreEmp(list);
    sqlSession.close();
}

7.5.2 批量删除

如果你的参数是集合或者数组的话,MyBatis都会将其放入到Map集合中

1) 使用in
/**
     * 批量删除
     * @param empIds
     */
void deleteMoreEmp(@Param("empIds") Integer[] empIds);
<!--void deleteMoreEmp(@Param("empIds") Integer[] empIds);-->
<delete id="deleteMoreEmp">
    delete from t_emp where emp_id in
    (
    <foreach collection="empIds" item="empId" separator=",">
        #{empId}
    </foreach>
    )
</delete>

或者

<!--void deleteMoreEmp(@Param("empIds") Integer[] empIds);-->
<delete id="deleteMoreEmp">
    delete from t_emp where emp_id in
    <foreach collection="empIds" item="empId" separator="," open="(" close=")">
        #{empId}
    </foreach>
</delete>
2)使用or
<!--void deleteMoreEmp(@Param("empIds") Integer[] empIds);-->
<delete id="deleteMoreEmp">
    delete from t_emp where
    <foreach collection="empIds" item="empId" separator="or">
        emp_id = #{empId}
    </foreach>
</delete>

7.6 sql

可以记录一段sql片段,在需要使用的地方使用include标签进行引用

<!--List<Emp> getEmpByChoose(Emp emp);-->
<sql id="empColumns">
    emp_id,emp_name,age,gender,dept_id
</sql>
<select id="getEmpByChoose" resultType="Emp">
    select <include refid="empColumns"></include> from t_emp
    <where>
        <choose>
            <when test="empName != null and empName != ''">
                emp_name = #{empName}
            </when>
            <when test="age != null and age != ''">
                age = #{age}
            </when>
            <when test="gender!=null and gender != ''">
                gender = #{gender}
            </when>
        </choose>
    </where>
</select>

8. MyBatis的缓存

8.1 MyBatis的一级缓存

8.1.1 介绍

默认开启

一级缓存的级别是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询使用同一个sqlSession的时候查询相同的数据,就会从缓存中直接获取,不会从数据库中重新访问

sqlSession级别的就是说使用同一个sqlSession其执行同一个sql的时候,h结果会被缓存

8.1.2 一级缓存失效

使得一级缓存失效的四种情况

  1. 不同的sqlSession对应不同的一级缓存
  2. 同一个sqlSession但是查询条件不同
  3. 同一个sqlSession两次查询之间,执行了任意一次增删改,任意一次增删改会清空缓存的
  4. 同一个sqlSession两次查询之间,自动清空了缓存
//清空sqlSession一级缓存
sqlSession.clearCache();

8.2 MyBatis的二级缓存

8.2.1 介绍

二级缓存是sqlSessionFactory级别的,通过同一个SqlSessionFactory创建的SqlSession查询的结果会被缓存,此后若再执行相同的查询语句,结果就会从缓存中获取

MyBatis二级缓存开启的条件:

  1. 在核心配置文件中,设置全局配置cacheEnable=“true” ,默认为true,不需要设置
  2. 在映射文件中设置 cache标签
  3. 二级必须在sqlSession关闭或者提交之后,二级缓存才会有效
  4. 查询的数据所转换的实体类类型必须实现序列化的接口,否则报异常:NotSerializableException

二级缓存失效的情况:

两次查询之间执行了任意的增删改操作,会使一级和二级的缓存同时失效

@Test
public void testCache() throws IOException {
    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    SqlSessionFactory build = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = build.openSession(true);
    CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
    Emp empById = mapper.getEmpById(1);
    System.out.println(empById);
    sqlSession.close();
    SqlSession sqlSession1 = build.openSession(true);
    CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
    Emp empById1 = mapper1.getEmpById(1);
    System.out.println(empById1);
    sqlSession1.close();
}

证明:缓存命中率不为0,终于有一点点理解机组中缓存内容了,哭死

image-20221010100115173

8.2.2 配置

  1. eviction属性:缓存回收策略

    1. LRU Least Recently Used 默认:最近最少使用的,移除最长时间不被使用的
    2. FIFO:先进先出:按照对象存入缓存的顺序来移除
    3. SOFT
    4. WEAK
  2. flushInterval属性:刷新间隔

    1. 默认不设置就是没有刷新间隔,缓存仅在调用语句时刷新
    2. 仅在调用增删改语句时刷新
  3. size属性:缓存中可以存储多少对象,使用默认的

  4. readOnly属性:true|false

    1. true 只读缓存:会把缓存的实例对象直接给调用者,如果一改就和数据库不一样了
    2. false 读写缓存:会把缓存的实例对象的拷贝的对象给调用者,速度慢了,但是安全。默认false

8.3 MyBatis缓存查询的顺序

  1. 先查询二级缓存,以为二级缓存中可能会有其它程序已经查询出来的数据,可以拿来直接使用
  2. 如果二级缓存没有命中,再查询一级缓存
  3. 如果一级缓存也没有命中,则查询数据库

SqlSession关闭之后,一级缓存中的数据,才会保存在二级缓存中

8.4 整合第三方缓存EHCache

争对二级缓存,一级缓存无法替代

8.4.1 添加依赖

9. MyBatis的逆向工程

正向工程:先创建一个java实体类,由框架负责根据实体类生成数据库表,Hibernate是支持正向工程的

逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源

  1. java实体类
  2. Mapper接口
  3. Mapper映射文件

9.1 清新简洁版(微牛逼)

  1. 添加插件(这个插件真的牛逼)
<!-- 控制Maven在构建过程中相关配置 -->
<build>

    <!-- 构建过程中用到的插件 -->
    <plugins>

        <!-- 具体插件,逆向工程的操作是以构建过程中插件形式出现的 -->
        <plugin>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-maven-plugin</artifactId>
            <version>1.3.0</version>

            <!-- 插件的依赖 -->
            <dependencies>

                <!-- 逆向工程的核心依赖 -->
                <dependency>
                    <groupId>org.mybatis.generator</groupId>
                    <artifactId>mybatis-generator-core</artifactId>
                    <version>1.3.2</version>
                </dependency>

                <!-- MySQL驱动 -->
                <dependency>
                    <groupId>mysql</groupId>
                    <artifactId>mysql-connector-java</artifactId>
                    <version>8.0.16</version>
                </dependency>
            </dependencies>
        </plugin>
    </plugins>
</build>
  1. 创建MyBatis的核心配置文件
  2. 创建逆向工程的核心配置文件

文件名必须是:generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
            targetRuntime: 执行生成的逆向工程的版本
                    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
                    MyBatis3: 生成带条件的CRUD(奢华尊享版)
     -->
    <context id="DB2Tables" targetRuntime="MyBatis3Simple">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"
                        userId="root"
                        password="123456">
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"  targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mapper"  targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>

9.2 奢华尊享版(真牛逼)

配置generatorConfig.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!--
            targetRuntime: 执行生成的逆向工程的版本
                    MyBatis3Simple: 生成基本的CRUD(清新简洁版)
                    MyBatis3: 生成带条件的CRUD(奢华尊享版)
     -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!-- 数据库的连接信息 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC"
                        userId="root"
                        password="123456">
        </jdbcConnection>
        <!-- javaBean的生成策略-->
        <javaModelGenerator targetPackage="com.atguigu.mybatis.pojo" targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true" />
        </javaModelGenerator>
        <!-- SQL映射文件的生成策略 -->
        <sqlMapGenerator targetPackage="com.atguigu.mybatis.mapper"  targetProject=".\src\main\resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <!-- Mapper接口的生成策略 -->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.atguigu.mybatis.mapper"  targetProject=".\src\main\java">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <!-- 逆向分析的表 -->
        <!-- tableName设置为*号,可以对应所有表,此时不写domainObjectName -->
        <!-- domainObjectName属性指定生成出来的实体类的类名 -->
        <table tableName="t_emp" domainObjectName="Emp"/>
        <table tableName="t_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>

点击蓝色的地方,就会自动创建出实体类,接口,映射文件

image-20221010190843520

9.2.1 根据条件查询语句

@Test
public void testMBG(){
    SqlSession sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    EmpExample empExample = new EmpExample();
    empExample.createCriteria().andEmpNameEqualTo("王一博").andAgeGreaterThanOrEqualTo(10);
    empExample.or().andGenderEqualTo("男");
    List<Emp> list = mapper.selectByExample(empExample);
    list.forEach(System.out::println);
}

看人家自动生成的sql👇

image-20221010191158892

9.2.2 测试普通修改功能

问题 :没有老师的mapper.updateByPrimaryKey(emp);方法

10. 分页插件

要实现分页

limit index,pageSize

index : 当前页的其实索引

pagSize : 每页显示的条数

pageNum : 当前页的页码

例如:

pageSize = 4;pageNum = 1;index = 0;limit 0,4

pageSize = 4;pageNum = 3;index = 0;limit 0,8

pageSize = 4;pageNum = 6;index = 0;limit 0,20

index = (pageNum - 1) * pageSize

count : 当前总记录数

totalPage : 总页数 = count / pageSize;

if(count % pageSize != 0){
    totalPage += 1;
}

分页的难度主要难在超链接中:

首页 上一页 2 3 4 5 6 下一页 未页

导航分页:

image-20221010200357104

上一页和下一页有出现的条件:当pageNum != 1的时候,显示上一页;当pageNum!=末页的时候,显示下一条

10.1 使用步骤

① 添加依赖

<!--分页插件-->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.2.0</version>
</dependency>

②配置分页插件

在MyBatis的核心配置文件中配置

里边参数的配置:点两次Shift——>输入PageInterceptor——>得到其全路径

这个路径其实是固定的不用管页可以,直接复制就可以了~

<plugins>
    <!--配置分页插件-->
    <!--一个拦截器-->
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

10.2 分页插件的使用

①PageHelper

在查询之前使用PageHelper.starPage(int pageNum,int pageSize)开启分页功能

@Test
public void testPage(){
    SqlSession  sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    //查询功能之开启分页功能
    //拦截查询功能在条件中加入条件
    PageHelper.startPage(1,4);
    List<Emp> list = mapper.selectByExample(null);
    list.forEach(System.out::println);
    sqlSession.close();
}

Page继承了ArrayList集合,所以直接可以使用Page对象来存储数据

@Test
public void testPage(){
    SqlSession  sqlSession = SqlSessionUtil.getSqlSession();
    EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
    //查询功能之开启分页功能
    //拦截查询功能在条件中加入条件
    Page<Object> page =  PageHelper.startPage(1,4);
    Page<Object> page1 = mapper.selectByExample(null);
    page.forEach(System.out::println);
    sqlSession.close();
}

下面就是我们开始分页插件执行的sql语句

仔细一点观察limit后边只有一个?,为什么呢❓表示默认访问第0页,每页条数是4,即limit 0,4

image-20221010195144097

②Page

一个字牛逼!!!

page输出的数据:

PageInfo{pageNum=1, pageSize=4, size=4, startRow=1, endRow=4, total=16, pages=4,

list=Page{count=true, pageNum=1, pageSize=4, startRow=0, endRow=4, total=16, pages=4, reasonable=false, pageSizeZero=false}

[Emp{empId=1, empName=‘肖战’, age=24, gender=‘男’, deptId=1}, Emp{empId=2, empName=‘王一博’, age=23, gender=‘男’, deptId=2}, Emp{empId=3, empName=‘王俊凯’, age=20, gender=‘男’, deptId=3}, Emp{empId=4, empName=‘易烊千玺’, age=20, gender=‘男’, deptId=1}],

prePage=0, nextPage=2, isFirstPage=true, isLastPage=false, hasPreviousPage=false, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=4, navigatepageNums=[1, 2, 3, 4]}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值