MyBatis的重点知识

MyBatis的基本概念及使用方法

目录

SSM-MyBatis

第一章  MyBatis简介

1.SSM框架及整合

2.MyBatis:

3.MyBatis特性

第二章 搭建Mybatis

1.注意事项

2.创建Mybatis的核心配置文件

3.mapper接口

4.创建Maven工程的步骤

5..日志的级别

6.在utils工具类

7.使用Mybatis进行增删改查

8.核心配置文件讲解:四个标签讲解

9.在idea中创建mybatis核心配置文件和映射文件的模版

第三章 mybatis的操作方法

1.为什么要获取方法参数

2.mybatis获取参数值的两种方式

3.字面量类型

4.获取mapper接口方法中的参数值

5.mybatis的各种查询功能

6.Mybatis中的几个特殊SQL的执行

7.字段名和属性名不一致时,如何处理映射关系

8.处理多对一的映射关系

9.一对多的映射关系

第四章 Mybatis其他方面

1.动态SQL

2.多条件查询中条件拼接存在的问题

3.Mybatis的一级缓存

4. Mybatis的二级缓存

5.Mybatis缓存查询的顺序

6.二级缓存可以整合第三方缓存EHCache

7.Mybatis的逆向工程

8.sql中实现分页功能

9.使用分页插件


SSM-MyBatis

重点:增删改查;查中包含:多对一:一对多;自定义映射;动态SQL等

第一章  MyBatis简介

1.SSM框架及整合

* MyBatis:封装JDBC,负责访问数据库,完成持久化操作。

* Spring:使用其核心思想IOC管理组件,使用AOP思想实现功能增强

* SpringMVC:接收浏览器发送的请求,并响应浏览器数据

* SSM整合:结合案例整合SSM,进一步了解各个框架的功能

2.MyBatis:

* 原称为iBatis,是一个基于Java的持久层框架;ibatis提供的持久层框架包括SQL Maps和Data Access Object(DAO)

* 优势:性能出色;java和SQL语句编码分开。java代码专注业务,SQL语句专注数据

3.MyBatis特性

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

    * mybatis中的SQL语句都需要自己去写,因此在定制化SQL中,mybatis利于维护SQL语句;

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

    * mybatis将大部分jdbc代码进行封装,不需要再手动写代码;SQL语句中的许多东西不能写死,jdbc中使用SQL拼接/占位符赋值进行,mybatis使用xml文件即可;结果集在mybatis中不需要再解析,能直接拿到

3. MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录

4. MyBatis是一个半自动的ORM(Object Relation Mapping-对象关系映射)框架

    * mybatis实现数据库和java映射比较方便

第二章 搭建Mybatis

1.注意事项

2.创建Mybatis的核心配置文件

* 核心配置文件主要用于配制连接数据库的环境以及Mybatis的全局配置信息

* 映射文件的作用:设置如何操作数据库;

* 核心配置文件的作用:设置如何连接数据库

* 将映射文件配置到核心配置文件中,然后通过加载核心配置文件找到相对应的映射文件中的SQL语句,之后执行SQL语句达到操作数据库的目的

3.mapper接口

* mybatis中的mapper接口相当于以前的DAO,区别在于mapper仅仅是接口,不需要实现类

* mapper接口和映射文件要保证两个一致

    1. mapper接口的全类名和映射文件的namespace一致

    2. mapper接口中的方法的方法名要和映射文件中的SQL的ID保持一致

public interface UserMapper {

    //添加用户信息
    int insertUser();

    //删除用户信息
    void deleteUser(@Param("username") String username);

    //更新用户信息
    void updateUser(@Param("username") String username);

    //查询用户信息
    User getUserByName(@Param("username") String username);

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

<mapper namespace="com.gz.mapper.UserMapper">
<!--    int insertUser();-->
    <insert id="insertUser">
        insert into t_user values(null,'wanghao','123456',78,'男','121@qq.com')
    </insert>

<!--    void deleteUser(@Param("username") String username);-->
    <delete id="deleteUser">
        delete from t_user where username = #{username}
    </delete>

<!--    void updateUser(@Param("username") String username);-->
    <update id="updateUser">
        update t_user set age = 10 where username = #{username}
    </update>

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

</mapper>

4.创建Maven工程的步骤

        1. 在module中的pom.xml中配置好依赖:Mybatis核心、junit测试、mysql驱动

<dependencies>
        <!-- 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>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
    </dependencies>

        2. 创建Mybatis的核心配置文件:配置连接数据库的环境、Mybatis的全局配置信息

        3. 创建表,及表对应映射的实体类

        4. 创建mapper接口,相当于dao,用来操作数据库,但在mybatis中不需要实现类

        5. 创建mybatis的映射文件;注意mybatis的映射文件包名和mapper接口中对应的mapper方法相对应(在本章第8段中详细讲解)

    * 一个映射文件对应一个实体类,对应一张表的操作;

    * mybatis映射文件用来编写SQL,操作数据库中的数据;

        6. 通过Junit测试功能,步骤固定,因此可以作为一个utils工具类封装起来

  @Test
    public void testSelectById() throws IOException {

        //1.获取核心配置文件输入流
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        //2.new 一个 SqlSessionFactoryBuilder 对象
        SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();

        //3.build一个SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = ssfb.build(is);

        //4.利用sqlSessionFactory打开一个sqlSession会话
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //5.获取UserMapper的代理实现类对象
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        //6.调用添加用户功能
        User result = mapper.getUserByName("mary");
        System.out.println(result);
        sqlSession.close();
    }

        7. 加入log4j日志

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <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>

5..日志的级别

        fatal(致命)- error()- warn()-info(信息)-debug(调试);从左到右打印的内容越来越清晰

6.在utils工具类

        工具类中的异常都需要try- catch一下;若是throws抛出的话就会抛给调用它的方法,在调用处还需要在处理异常;工具类封装如下:

 public static SqlSession getSqlSession(){
        //1.获取核心配置文件输入流
        SqlSession sqlSession = null;
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            //2.new 一个 SqlSessionFactoryBuilder 对象
            SqlSessionFactoryBuilder ssfb = new SqlSessionFactoryBuilder();

            //3.build一个SqlSessionFactory
            SqlSessionFactory sqlSessionFactory = ssfb.build(is);

            //4.利用sqlSessionFactory打开一个sqlSession会话
            sqlSession = sqlSessionFactory.openSession(true);

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

7.使用Mybatis进行增删改查

* 步骤都相似

    1. 在DAO接口(mapper接口)中创建方法

    2. 在对应的映射文件中写SQL语句(注意:此时映射文件和mapper接口应该保证两个一致)

    3. 在test中测试

* 查询操作时,要设置查询的数据对应的实体类的类型;使用两种方式

    1. resultType:设置结果类型,即查询的数据要转换为的java类型

    2. resultMap:自定义映射,处理多对一或一对多的映射关系

    3. 注意:两者不能同时存在,但也不能没有

* 增加

* 删除

* 修改

简单的代码示例:

<mapper namespace="com.gz.mapper.UserMapper">

<!--    int insertUser();-->
    <insert id="insertUser">
        insert into t_user values(null,'wanghao','123456',78,'男','121@qq.com')
    </insert>

<!--    void deleteUser(@Param("username") String username);-->
    <delete id="deleteUser">
        delete from t_user where username = #{username}
    </delete>

<!--    void updateUser(@Param("username") String username);-->
    <update id="updateUser">
        update t_user set age = 10 where username = #{username}
    </update>

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

</mapper>

8.核心配置文件讲解:四个标签讲解

* environments:配置连接数据库的环境

    1. environments的属性:default:设置默认使用的环境的ID

    2. environment:设置一个具体的连接数据库的环境;属性为:ID:设置环境的唯一标识,不能重复

    3. 每一个环境-environment有两个子标签组成

        1. 第一个标签:transactionManager设置事务管理器;

                                属性为type:设置事务管理的方式;type只有两个值:JDBC/MANAGED

        2. 第二个标签:dataSource:设置数据源;

                                属性:type:设置数据源的类型;三个值:POOLED/UNPOOLED/JNDI

 

       在datasource中,各种参数可以用配置文件来写;首先在核心配置文件中引入配置文件,此后可以在当前文件中使用${key}方式访问value

 

* properties:在核心配置文件中使用

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <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>
        </environment>
    </environments>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql:///ssm
jdbc.username=root
jdbc.password=admin//这个是自己登陆数据库的密码

* typeAliases:为文件起别名,在处理结果数据时能够使用别名标识一个具体的类型

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

如:查询语句中使用resultType时可以使用

<select id="getUserByUsername" resultType="User">
    select * from t_user where username = '${username}'
</select>

* mappers:引入mybatis的映射文件;在引入映射文件时比较麻烦,因此可以通过包的方式引入映射文件,必须满足两个条件

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

    2. mapper接口的名字和映射文件的名字必须一致

    3. 此时如果报错是因为没有clean掉缓存中的xml文件,clean即可

    4. 在maven工程下,main目录中的java类用来写主程序,resources类用来放配置文件;虽然在自己设置时目录不一样,但当加载之后,这两者的目录在同一个target目录中,因此保持了一致

* 对于一个maven工程,创建后就会产生一个main目录一个test目录;main中有java和resources;test中写java文件

9.在idea中创建mybatis核心配置文件和映射文件的模版

* 将一个自己写好的模版粘贴进去,删掉注释即可

* 注意:typeAliases和mappers都需要删掉内容,其他两个不用,以后复制就可以

第三章 mybatis的操作方法

1.为什么要获取方法参数

        mapper接口中的方法对应映射文件中的一个SQL语句;若SQL语句需要传入的参数,因此在映射文件中获取方法参数,然后拼接到SQL语句中

2.mybatis获取参数值的两种方式

* ${}:字符串拼接;在为字符串类型/日期类型赋值时需要手动加单引号

    * 在底层解析时被视为一个字段

* #{}:占位符赋值;在底层被解析时自动添加单引号

    * 在底层解析时被视为一个问号❓,对应的量赋值后自动加单引号

3.字面量类型

        看上去的东西就是字面量:字符串、基本数据类型、包装类

4.获取mapper接口方法中的参数值

        1. 单个参数时

            * 此时${}和#{}中可以写任意字符获取参数值,只是推荐写的有意义一些

        2. 多个参数时

            * 此时在${}和#{}中使用arg0,arg1…或param1,param2…作为键,以参数为值

            * 因为在底层多个参数存放在一个map集合中,通过调用键值对获取参数,参数作为键值对的值存在

        3. 参数为map集合类型时

            * 通过${}和#{}来获取map的键,此时的键是自己put到map集合中的键

        4. mapper接口方法的参数为实体类类型的参数:mybatis中只看get、set方法中的参数名(即将get、set去掉后的属性名,而不是成员变量)

        5. 可以在mapper接口方法的参数上设置@param注解(除了实体类,都用这个)

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

                    a>以@param注解的value属性值为键,以参数为值

                    b>以param1…为键,以参数为值

方法中加入@Param注解,注解的value值为键,在配置文件中可以使用#{}获取注解标识的value值

public interface UserMapper {

    /**
     * 根据用户名查询用户信息
     * @param username
     * @return
     */
    User getUserByUsername(@Param("username") String username);

    /**
     * 验证登录
     * @param username
     * @param password
     * @return
     */
    User checkLogin(@Param("username")String username,@Param("password")String password);

    /**
     * 验证登录,以Map集合作为参数
     * @param map
     * @return
     */
//    List<Map<String,Object>> checkLoginByMap(Map<String,Object> map);
    User checkLoginByMap(Map<String,Object> map);

    /**
     * 添加用户信息
     */
    void insertUser(User user);
}
<mapper namespace="com.gz.mybatis.mapper.UserMapper">

  <!--  User getUserByUsername(String username); -->
    <select id="getUserByUsername" resultType="User">
        select * from t_user where username = '${username}'
    </select>
<!--User checkLogin(@Param("username")String username,@Param("password")String password);-->
    <select id="checkLogin" resultType="User">
        select * from t_user where username = #{username} and password = #{password}
    </select>

<!--        User checkLoginByMap(Map<String,Object> map);   -->
    <select id="checkLoginByMap" resultType="User">
        select * from t_user where username = #{username} and password = #{password};
    </select>

<!--     void insertUser(User user); -->
    <insert id="insertUser">
        insert into t_user values (null,#{username},#{password},#{age},#{gender},#{email})
    </insert>
</mapper>

5.mybatis的各种查询功能

        1. 查询一个实体类对象

            * 此时若返回多条记录,会报错:TooManyResultException

        2. 查询一个list集合

            * 若返回一条结果,使用实体类类型或list集合类型都可以

        3. 查询单个数据

            * 比如查询表中某一字段的个数,返回单行单列数据

            * mybatis为java中常用的类型设置了类型别名;比如:

                    * Integer:int,Integer

                    * int:_int,_integer

                    * Map:map

                    * String:string

                    * 除了基本数据类型外,其他类型大部分都是相对应驼峰形式的

        4. 查询一条数据为map集合

            * 与实体类类型查询出来的结果相比较而言:

                        map集合查询出的结果若有null则不会放入map中;

                        实体类类型查询会将所有值都查询出来,即使有null值也会赋给键值对

        5. 查询多条数据为map集合

            * 第一种方法:使用一个list存储所有查出来的map结果(用得多)

            * 第二种方法:使用@MapKey()注解的方法,注解中必须将查询到的某个字段的值作为大的Map的键,查询的一个个map集合作为值存储到一个大的Map集合中

代码示例:

public interface SelectMapper {

    /**
     * 根据id获取一个实体类对象
     * @param id
     * @return
     */
    User getUserById(@Param("id")Integer id);

    /**
     * 使用List获取所有的用户信息
     * @return
     */
    List<User> getAllUser();

    /**
     * 获取当前职员的数量
     * @return
     */
    Integer getUserCount();

    /**
     * 根据用户名获取一条数据为Map集合
     * @return
     */
    Map<String,Object> getUserByMapUsername(@Param("username")String username);

    /**
     * 使用list获取所有用户信息
     * @return
     */
    List<Map<String,Object>> getAllUserByList();

    /**
     * 使用Map获取所有用户信息
     * @return
     */
    @MapKey("id")
    Map<String,Object> getAllUserByMap();

}

注意:resultType的类型随查询的Java类型而变

<mapper namespace="com.gz.mybatis.mapper.SelectMapper">

<!--    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>

<!--       Integer getUserCount(); -->
    <select id="getUserCount" resultType="Integer">
        select count(*) from t_user
    </select>

<!--    Map<String,Object> getUserByMapUsername(@Param("username")String username); -->
    <select id="getUserByMapUsername" resultType="map">
        select * from t_user where username = #{username}
    </select>

<!--        List<Map<String,Object>> getAllUserByList(); -->
    <select id="getAllUserByList" resultType="User">
        select * from t_user
    </select>

<!--    Map<String,Object> getAllUserByMap(); -->
    <select id="getAllUserByMap" resultType="User">
        select * from t_user
    </select>

</mapper>

6.Mybatis中的几个特殊SQL的执行

* 模糊查询(#{}和${}都可以)

    1. 第一种方法:在查询时若直接使用#{},会被当作字符串的一部分看待,而不是占位符,使用${}方式进行模糊查询就不会出问题

    2. 第二种方法:若非要使用#{},则需要使用concat拼接的方式

    3. 第三种方法:将模糊查询中的%用双引号包起来,中间使用#{}来获取map的键 即可

<!--    User getLike(@Param("part")String part);  -->
<!--    模糊查询的实现方法:三种-->
    <select id="getLike" resultType="User">
        select * from t_user where username like '%${part}%'
        select * from t_user where username like concat('%',#{part},'%')
        select * from t_user where username like "%"#{part}"%"
    </select>

* 批量删除(只能${})

    只能使用${}方式来拼接,因为使用#{}时,in中的数据会被加上单引号,这会导致删除错误

<!--    void deleteSeveralRecords(@Param("ids")String ids); -->
<!--    批量删除在范围内的id记录 -->
    <delete id="deleteSeveralRecords">
        delete from t_user where id in (${ids})
    </delete>

* 动态设置表名(只能${})

    * 查询不同的表名

    * 表名不能加单引号,因此也只能使用${}

<!--    List<User> setTableName(@Param("tableName") String tableName);    -->
    <select id="setTableName" resultType="User">
        select * from ${tableName}
    </select>

* 添加功能获取自增的主键(用得多)

    * 表关系无论是多对一还是一对多设置都一样,都需要在’多’的这一方设置’一’的主键

    * 在insert语句中要写上useGeneratedkeys和keyproperty,后者将得到的自增主键写到User的id属性存入到user中输出

<!--        void insertUser(User user);    -->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
   insert into t_user values (null,#{username},#{password},#{age},#{gender},#{email})
</insert>

7.字段名和属性名不一致时,如何处理映射关系

1.将字段名设置别名

        如果别名和属性名相等就可以成功输出值,否则不一致的名字输出将为null

<!--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>

2.将下划线映射为驼峰

        当字段符合Mysql的要求使用_,而属性符合java的要求使用驼峰;此时可以在MyBatis的核心配置文件设置一个全局配置,可以自动将下划线映射为驼峰

<settings>
    <!-- 将下划线映射为驼峰 -->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

 3.  使用resultMap自定义映射处理

    * id:唯一标识

    * type:处理映射关系的实体类的类型

    * 其他标签:

            * id:处理主键和实体类中属性的映射关系

            * result:处理普通字段和实体类中属性的映射关系

                    * column:设置映射关系的字段名,必须是SQL查询出的某个字段

                    * property:设置映射关系中的属性的属性名,必须是处理的实体类类型中的属性名

<!--     Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);      -->
    
    <resultMap id="getDeptAndEmpByStepOne" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps"
                    select="com.gz.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
                    column="dept_id"></collection>
    </resultMap>
    
    <select id="getDeptAndEmpByStepOne" resultMap="getDeptAndEmpByStepOne">
        select * from t_dept where dept_id = #{deptId}
    </select>

8.处理多对一的映射关系

1.Java类型和数据库数据的对应关系

        表-实体类,字段-属性,一行-一个对象

2.多对一与一对多的处理:对一:一个对象;对多:一个集合

    * 三种处理方式(方法极其固定,记不住就做成模版,到时候复制粘贴即可)

    /**
     * 获取员工以及所对应的部门信息:多 对 一
     * @param empId
     * @return
     */
    Emp getEmpAndDeptByEmpId(@Param("empId")Integer empId);

        * 第一种方法:级联方式处理

<!--    处理多对一映射关系的三种方法  -->
<!--        Emp getEmpAndDeptByEmpId(@Param("id")Integer id);  -->

<!--    第一种方法:级联方式处理    -->
    <resultMap id="getEmpAndDeptResultMap" 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>
        <result column="dept_id" property="dept.deptId"></result>
        <result column="dept_name" property="dept.deptName"></result>
    </resultMap>

    <select id="getEmpAndDeptByEmpId" resultMap="getEmpAndDeptResultMap">
        SELECT *
        FROM t_emp
        LEFT JOIN t_dept
        ON t_emp.dept_id = t_dept.dept_id
        WHERE t_emp.emp_id = #{empId};
    </select>

        * 第二种方法:association;专门用来处理多对一的映射关系(专门处理实体类类型的属性)

<!--    第二种方法:association处理     -->
    <resultMap id="getEmpAndDeptResultMap" 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="getEmpAndDeptResultMap">
        SELECT *
        FROM t_emp
        LEFT JOIN t_dept
        ON t_emp.dept_id = t_dept.dept_id
        WHERE t_emp.emp_id = #{empId};
    </select>

        * 第三种方法:分步查询

            * 注意:此时应将分步查询的不同步骤写在对应的映射文件中

            * select的唯一标识:namespace.SQL Id

    /**
     * 通过分步查询员工以及对应的部门信息的第一步
     * @param empId
     * @return
     */
    Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);
    /**
     * 通过分步查询员工以及对应的部门信息的第二步
     * @param deptId
     * @return
     */
    Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);
<!--    第三种方法:分步查询-->

<!--    Emp getEmpAndDeptByStepOne(@Param("empId") Integer empId);-->

    <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" fetchType="lazy"
                     select="com.gz.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
                     column="dept_id"></association>
    </resultMap>

    <select id="getEmpAndDeptByStep" resultMap="empAndDeptByStepResultMap">
        select * from t_emp where emp_id = #{empId}
    </select>
<!--    Dept getEmpAndDeptByStepTwo(@Param("deptId") Integer deptId);       -->
    <select id="getEmpAndDeptByStepTwo" resultType="Dept">
        select * from t_dept where dept_id = #{deptId}
    </select>

3. 分步查询写着麻烦,有什么优势?

    * 可以实现延迟加载

    * 在分步查询中,可以先给出查询的第一步结果,第二步结果如果暂时不需要可以不给出。减少内存消耗

    * 但要实现延迟加载,必须先在核心配置文件中设置两个全局配置信息

        * lazyLoadingEnabled:延迟加载的全局开关。开启后,所有关联对象都会延迟加载;默认为false

        * aggressiveLazyLoading:开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载;默认为true

    <settings>
        <!-- 将下划线映射为驼峰 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
<!--          开启延迟加载      -->
        <setting name="lazyLoadingEnabled" value="true"/>
<!--          按需加载      -->
        <setting name="aggressiveLazyLoading" value="false"/>

    </settings>

    * 这两个方法可以实现按需加载,要获取的数据是什么,就执行相应的SQL。

    * 此时存在一个问题,在核心配置文件中写了全局配置,会让所有分步查询都实现延迟加载。但如果需要一次将所有结果都查询出来,就会出现问题

         解决方法:在association中使用fetchType:在开启了延迟加载的环境中,通过该属性设置当前的分步查询是否使用延迟加载

<!--    fetchType = "eager"(立即加载)-->
<!--    fetchType = "lazy"(延迟加载)-->
<association property="dept" fetchType="lazy"
      select="com.gz.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
      column="dept_id"></association>
</resultMap>

9.一对多的映射关系

        1.表关系映射到实体类中时,实体类如何处理对应的复杂的表的关系呢?

                    * 对一,对应一个对象;对多,对应一个集合

                    * 比如,员工表和部门表;一个部门对应多个员工;若在查员工时要查部门,就是多对一,此时在员工实体类对象中写上一个部门对象;

 

                    * 若是查询一个部门的多个员工,就是一对多;在部门的实体类对象中为多个员工写一个list集合

public class Dept {

    private Integer deptId;

    private String deptName;

    private List<Map> emps;
}

 

        2.处理一对多的映射关系的方法

                    * 第一种方法:collection(也是一个模版)

<!--     
        2.处理一对多的映射关系的方法
        第一种方法:collection(也是一个模版)
-->
<!--        Dept getDeptAndEmpByDeptId(@Param("deptId") Integer deptId);     --> 
    <resultMap id="getDeptIdByRestultMap" 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="getDeptIdByRestultMap">
        select *
        from t_dept
        left join t_emp
        on t_dept.dept_id = t_emp.dept_id
        where t_dept.dept_id = #{deptId}
    </select>

                    * 第二种方法:分步查询

<!--    第二种方法:分步查询-->
<!--     Dept getDeptAndEmpByStepOne(@Param("deptId") Integer deptId);      -->
<!--    分步查询的第一步-->
    <resultMap id="getDeptAndEmpByStepOne" type="Dept">
        <id column="dept_id" property="deptId"></id>
        <result column="dept_name" property="deptName"></result>
        <collection property="emps"
                    select="com.gz.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo"
                    column="dept_id"></collection>
    </resultMap>
    
    <select id="getDeptAndEmpByStepOne" resultMap="getDeptAndEmpByStepOne">
        select * from t_dept where dept_id = #{deptId}
    </select>
<!--    List<Emp> getDeptAndEmpByStepTwo(@Param("deptId") Integer deptId);      -->

    <select id="getDeptAndEmpByStepTwo" resultType="Emp">
        select * from t_emp where dept_id = #{deptId}
    </select>

第四章 Mybatis其他方面

1.动态SQL

* 作用:根据特定条件动态拼装SQL语句的功能,存在的意义是为了解决拼接SQL语句字符串时的问题

* 第一个标签:if:通过test属性中的表达式判断标签中的内容是否有效(是否会拼接到SQL中)

* 第二个标签:where:(与if结合使用)

    * 第一个功能:若where标签中有表达式成立,则自动生成where

    * 第二个功能:能将内容中前面多余的and去掉,但是内容后面的and无法去掉

    * 第三个功能:若where标签中的表达式都不成立,则where标签没有任何功能

* 第三个标签:trim:用来截取条件中的内容;具有四个标签

    * prefix,suffix:在标签中内容的前面或后面添加指定内容

    * prefixOverrides,suffixOverrides:在标签中内容前面或后面去掉指定内容

* 第四组标签:foreach(极其重要,掌握);可以实现批量添加和批量删除(三种方法),共有五个属性

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

    * item:用一个字符串表示数组或集合中的每一个数据

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

    * open:循环的所有内容以什么开始

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

<!--
        foreach:五个属性
        collection:设置要循环的数组或集合
        item:用一个字符串表示数组中的每一个数据
        separator:设置每次循环的数据之间的分隔符
-->
<!--     void insertManyEmp(@Param("emps") List<Emp> emps); -->
    <insert id="insertManyEmpOne">
        insert into t_emp values
        <foreach collection="emps" item="emp" separator="," open="(" close=")">
            null,#{emp.empName},#{emp.age},#{emp.gender},null
        </foreach>
    </insert>

* 第五个标签:choose,when,otherwise:相当于:if-else if-else(用的不多)

    * when至少设置一个;otherwise至多设置一个

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

    <sql id="empColumns">
        emp_id,emp_name,age,gender,dept_id
    </sql>

2.多条件查询中条件拼接存在的问题

* 若条件中所有条件都不成立,就会出现很大的漏洞,这需要解决

* 第一种方法:where 后面加上一个恒成立的表达式:1=1

    <select id="getEmpByConditionOne" 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 != ''">
                gender = #{gender}
            </if>
    </select>

* 第二种方法:使用<where>标签

    <select id="getEmpByConditionTwo" resultType="Emp">
        select * from t_emp
        <where>
            <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>
        </where>
    </select>

* 第三种方法:使用<trim>标签

    <select id="getEmpByConditionThree" 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>

* 第四种方法:使用组标签:choose、when、otherwise

    <select id="getEmpByCondition" 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>

    </select>

3.Mybatis的一级缓存

* 一级缓存:sqlSession级别,通过同一个sqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问(默认开启)

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

    * 不同的sqlSession对应不同的一级缓存

    * 同一个sqlSession但是查询条件不同

    * 同一个sqlSession两次查询期间执行了任何一次增删改操作;原因:增删改会修改数据库中的信息,缓存信息可能会被改变,而查询的信息必须是数据库实时存在的信息,因此缓存必须被清空

    * 同一个sqlSession两次查询期间手动清空了缓存(clearCache)

4. Mybatis的二级缓存

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

* 二级缓存开启的条件:

    * 在核心配置文件中,设置全局配置属性cacheEnabled=true;当然默认为true,不需要设置(不用管)

    * 在映射文件中设置标签<cache/>

<cache />

    * 二级缓存必须在sqlSession关闭或提交之后有效(必须close)

    * 查询的数据所转换的实体类类型必须实现序列化的接口

public class Emp implements Serializable {

    private Integer empId;

    private String empName;

    private Integer age;

    private String gender;

}

* 二级缓存失效的情况:

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

* 二级缓存存在缓存命中率,只要不为零,就说明缓存被命中了;也就是说明当前的所查询的数据在缓存中存在;

5.Mybatis缓存查询的顺序

* 先查询二级缓存,未命中;则查询一级缓存,又未命中;则查询数据库

* sqlSession关闭后,一级缓存中的数据会写入二级缓存

* 一级缓存中的数据不一定在二级缓存中;因为只有一级缓存关闭后才会写入二级缓存

6.二级缓存可以整合第三方缓存EHCache

7.Mybatis的逆向工程

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

* 逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成:java实体类、Mapper接口、Mapper映射文件

* 逆向工程如果要是第二次生成时,要把前一次生成的删掉

* 逆向工程版本:

    * 简单版:MyBatis3Simple-生成基本的curd

    * MyBatis3:生成带条件的Curd:可以实现对单表几乎所有的操作;

8.sql中实现分页功能

* SQL语句中:使用:limit

* limit 数据偏移量 条目数

#每页显示2条数据,此时显示第一页
SELECT *
FROM t_user
LIMIT 2

#每页显示2条数据,此时显示第三页
SELECT *
FROM t_user
LIMIT 4,2

#每页显示2条数据,此时显示第四页
SELECT *
FROM t_user
LIMIT 6,2

* 每页显示pagesize条记录,此时显示第 pageNumber页:公式:

                imit (pageNum-1)*pagesize,pagesize

* 如limit 2;表示第一页的前2条数据;默认表示第一页可以省略不写index;

9.使用分页插件

* pom.xml中添加依赖

* 配置分页插件

* 分页插件的使用:

    * 第一步:查询功能之前使用PageHelper.startPage(pageNum,pageSize)开启分页功能

        * pageNum:当前页的页码

        * pageSize:每页显示的条数

    * 第二步:在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo(list, navigatePages)获取分页相关数据;

        * list:分页之后的数据

        * navigatePages:导航分页的页码数(就是一共能显示从第几页到第几页)

    * 第三步:输出分页数据

代码示例如下:

    @Test
    public void testLimit2(){

        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //1.开启分页功能
        Page<Object> page = PageHelper.startPage(5, 4);

        //2.获取分页信息
        List<Emp> list = mapper.selectByExample(null);

        PageInfo<Emp> pageInfo = new PageInfo<>(list,5);
        System.out.println(pageInfo);
    }

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值