IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> mybatis -> 正文阅读

[Java知识库]mybatis

框架

? 框架会将很多基本功能进行封装,程序员在框架基础上再进行业务开发

作用:简洁代码,高效开发

mybatis概述

? 原apache的一个开源项目,2010迁移到谷歌,更名为mybatis

特点

? 它是一款半自动的ORM持久层框架,具有较高的SQL灵活性,支持高级映射(一对一,一对多),动态SQL,延迟加载和缓存等特性,但它的数据库无关性较低

MVC

数据持久层(数据访问层 / M层):DAO,model

数据控制层(C层 control):servlet

前端(View)

ORM

Object Relation Mapping,对象关系映射。对象指的是Java对象,关系指的是数据库中的关系模型

? 对象关系映射,指的就是在Java对象和数据库的关系模型之间建立一种对应关系,类中的属性和表中的列一一对应。

半自动ORM框架优点

? 用mybatis进行开发,需要手动编写SQL语句。而全自动的ORM框架,如hibernate,则不需要编写SQL语句。用hibernate开发,只需要定义好ORM映射关系,就可以直接进行CRUD操作了。由于mybatis需要手写SQL语句,所以它有较高的灵活性,可以根据需要,自由地对SQL进行定制,也因为要手写SQL,当要切换数据库时,SQL语句可能就要重写,因为不同的数据库有不同的方言(Dialect),所以mybatis的数据库无关性低。虽然mybatis需要手写SQL,但相比JDBC,它提供了输入映射和输出映射,可以很方便地进行SQL参数设置,以及结果集封装。并且还提供了关联查询和动态SQL等功能,极大地提升了开发的效率。并且它的学习成本也比hibernate低很多

mybatis架构

在这里插入图片描述

mybatis搭建使用

导入MyBatis使用的jar包

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

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

创建 MyBatis 全局配置文件

? 在resources目录下创建mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--mybatis核心配置文件-->
<configuration>
    <!--在外部properties文件中使用键值对配置属性,也可以在properties元素的子元素中设置
        优先级:通过方法参数传递的属性具有最高优先级
              resource/url 属性中指定的配置文件次之
              最低优先级的则是 properties 元素中指定的属性-->
    <properties resource="config.properties"/>

    <settings>
        <setting name="logImpl" value="LOG4J"/>
        <!--开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <!--懒加载-->
        <!--<setting name="lazyLoadingEnabled" value="true"/>-->
        <setting name="lazyLoadTriggerMethods" value=""/>
    </settings>

    <!--类型别名-->
    <typeAliases>
        <typeAlias type="com.ff.mybatisPro.model.AdminUser" alias="AdminUser"/>
        <typeAlias type="com.ff.mybatisPro.model.Dept" alias="Dept"/>
        <typeAlias type="com.ff.mybatisPro.model.Employee" alias="Employee"/>
    </typeAliases>

    <!--environments:配置与数据库链接的相关信息
                default:默认使用的环境id
                        development:开发环节
                        work:生产环节-->
    <environments default="development">
        <!--配置本地开发信息   id:每个environment元素定义的环境-->
        <environment id="development">
            <!--配置事务管理类型,使用JDBC事务管理
                    事物:一次对数据库操作的若干个流程管理-->
            <transactionManager type="JDBC"/>
            <!--数据源配置:使用标准的JDBC数据源接口来配置JDBC连接对象的资源
                   UNPOOLED:不使用数据库连接池 -->
            <dataSource type="UNPOOLED">
                <!--数据库驱动-->
                <property name="driver" value="${driver}"/>
                <!--数据库地址-->
                <property name="url" value="${url}"/>
                <property name="username" value="${userName}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--映射器:告诉mybatis去哪找sql语句(映射文件)-->
    <mappers>
        <mapper resource="mapper/AdminMapper.xml"/>
        <mapper resource="mapper/DeptMapper.xml"/>
        <mapper resource="mapper/EmployeeMapper.xml"/>
    </mappers>
</configuration>

在mapper目录下创建对应的mapper接口并定义方法

package com.ff.mybatisPro.mapper;

import com.ff.mybatisPro.model.AdminUser;
import org.apache.ibatis.annotations.Param;

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

/**
 * @author Deevan
 */
public interface AdminMapper {

    /*
        sql写在xml文件中,我们不能直接访问
        mybatis让我们在业务代码可以定义接口,在接口中定义方法
            方法定义要求:
                方法名与xml中某个标签的id相同
                参数类型一致,返回值类型一致
    */

    void saveAdmin(AdminUser adminUser);

    void updateAdmin(AdminUser adminUser);

    void deleteAdmin(int id);

    AdminUser selectAdminById(int id);

}

在resources.mapper目录下创建对应的mapper.xml文件

? 基本的增删改查

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

<!--namespace="某个接口的名称"-->
<mapper namespace="com.ff.mybatisPro.mapper.AdminMapper">

    <!--
        id:接口中的方法名
        parameterType:传入参数类型
        resultType:返回类型  根据返回值的类型,创建一个对象,将数据库数据自动映射到java对象中,表中的类名与类中的属性名相同

            使用#{account}: Preparing: insert into admin(account,password,sex)values(?,?,?)
                           Parameters: admin(String), 000(String), 男(String)
            使用'${account}':Preparing: insert into admin(account,password,sex)values('admin','152475','男')
            使用${account}:传列名       例:select ${account},${password} from admin order by ${id}-->

    <!-- useGeneratedKeys="true":获取刚插入数据的id-->
    <insert id="saveAdmin" parameterType="AdminUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into admin(account, password, sex)
        values (#{account}, #{password}, #{sex})
    </insert>

    <update id="updateAdmin">
        update admin
        set account=#{account},
            password=#{password},
            sex=#{sex}
        where id = #{id}
    </update>

    <delete id="deleteAdmin">
        delete
        from admin
        where id = #{id}
    </delete>
    
	<!-- 在查询时无论返回的是对象本身还是集合,resultType都为类的类型-->
    <select id="selectAdminById" resultType="AdminUser">
        select *
        from admin
        where id = #{id}
    </select>
</mapper>

在mybatis-config.xml核心配置文件中添加mapper映射

<mappers>
        <mapper resource="mapper/AdminMapper.xml"/>
</mappers>

在util包下封装sqlSession创建过程

package com.ff.mybatisPro.util;

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.Reader;

/**
 * 封装SqlSession的创建
 * @author Deevan
 */
public class MybatisUtil {

    static SqlSessionFactory sessionFactory = null;
    //静态代码块,在类加载时执行,只执行一次
    static {
        Reader reader = null;
        try {
            //读取mybatis核心配置文件
            reader = Resources.getResourceAsReader("mybatis-config.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        /*
          创建一个SqlSessionFactory:
             创建SqlSession的工厂,负责创建SqlSession对象
             SqlSessionFactory中包含了核心配置信息
             创建SqlSessionFactory开销太大,所以一旦创建就不用销毁,一个应用程序只要有一个SqlSessionFactory
         */
        sessionFactory = new SqlSessionFactoryBuilder().build(reader);
    }

    public static SqlSession openSession(){
        return sessionFactory.openSession();
    }

}

在测试中调用方法

    /**
     * 添加
     */
    @Test
    public void saveAdmin(){
        AdminUser adminUser = new AdminUser();
        adminUser.setAccount("admin2");
        adminUser.setPassword("000");
        adminUser.setSex("男");
        /*创建SqlSession:表示一次与数据库连接会话,类似JDBC中的Connection
            每次与数据库交互一次,都会创建一个SqlSession对象,使用完后立即销毁*/
        SqlSession sqlSession = MybatisUtil.openSession();
        //获得映射接口代理对象
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        //使用代理对象调用接口中的方法,本质上并不是调用接口中的方法,实际调用的是与接口中方法名相同的xml文件中对应的某个sql
        mapper.saveAdmin(adminUser);
        //输出刚插入数据的id:在AdminMapper.xml中<insert>加入useGeneratedKeys="true" keyColumn="id" keyProperty="id"属性
        System.out.println(adminUser.getId());
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 修改
     */
    @Test
    public void updateAdmin(){
        AdminUser adminUser = new AdminUser();
        adminUser.setId(1);
        adminUser.setAccount("admin2");
        adminUser.setPassword("000");
        adminUser.setSex("男");

        SqlSession sqlSession = MybatisUtil.openSession();
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        mapper.updateAdmin(adminUser);
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 删除
     */
    @Test
    public void deleteAdmin(){
        SqlSession sqlSession = MybatisUtil.openSession();
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        mapper.deleteAdmin(1);
        sqlSession.commit();
        sqlSession.close();
    }

    /**
     * 按学号(基本类型)查询单个对象
     */
    @Test
    public void selectAdmin(){
        SqlSession sqlSession = MybatisUtil.openSession();
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        //调用默认无参构造方法
        AdminUser adminUser = mapper.selectAdminById(5);
        System.out.println(adminUser);
        sqlSession.commit();
        sqlSession.close();
    }

参数传递

? 传单个参数一般用parameterType,要指定参数就要使用@Param(‘acc’)形式

@Param(‘acc’)传参
    /**
     * 通过账号、密码查询
     * "@Param('acc')":向sql中传递形参
     *
     * @param account  账号
     * @param password 密码
     * @return AdminUser对象
     */
    AdminUser selectAdminByAccount(@Param("acc") String account, @Param("pwd") String password);
    <select id="selectAdminByAccount" resultType="AdminUser">
        select *
        from admin
        where account = #{acc}
          and password = #{pwd}
    </select>
    /**
     * 通过账号密码(字符串传递)查询单个对象
     */
    @Test
    public void selectAdminByAccount(){
        SqlSession sqlSession = MybatisUtil.openSession();
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        AdminUser adminUser = mapper.selectAdminByAccount("admin","000");
        System.out.println(adminUser);
        sqlSession.commit();
        sqlSession.close();
    }
Map键/值串传参
    /**
     * 把参数封装在map中进行传值
     *
     * @param map 传递数据
     * @return AdminUser对象
     */
    AdminUser getAdmin(Map<String, Object> map);
    <!--java中以有的类作为类型使用时,可以直接使用mybatis定义好的别名-->
    <select id="getAdmin" resultType="AdminUser" parameterType="hashmap">
        select *
        from admin
        where account = #{acc}
          and password = #{pwd}
    </select>
    /**
     * 通过账号密码(Map键/值串传递)查询单个对象
     */
    @Test
    public void getAdmin(){
        SqlSession sqlSession = MybatisUtil.openSession();
        AdminMapper mapper = sqlSession.getMapper(AdminMapper.class);
        Map<String,Object> map = new HashMap<>();
        map.put("acc","admin");
        map.put("pwd","000");
        AdminUser adminUser = mapper.getAdmin(map);
        System.out.println(adminUser);
        sqlSession.commit();
        sqlSession.close();
    }

结果返回

简单类型输出映射
int countAdmin();
    <!--整数类型-->
    <select id="countAdmin" resultType="java.lang.Integer">
        select count(*)
        from admin
    </select>
POJO对象输出映射

? resultType=“AdminUser”:返回值的类型 根据返回值的类型,创建一个对象或List 将数据库数据自动映射到java对象中,表中的类名与类中的属性名相同

List<AdminUser> adminList();
    <select id="adminList" resultType="AdminUser">
        select *
        from admin
    </select>
关联查询resultMap

? 在关联查询的时候,一个对象中需要存放其他类的属性,我们通常直接把其他类添加到该类属性中,如下把部门关联的员工集合和操作人都添加为部门的属性

public class Dept {
    private int id;
    private String name;
    private List<Employee> employees;
    private AdminUser adminUser;
}

? 之后在查询语句中,resultMap中就可以去设置属性字段的映射

而封装的其他对象个体就会创建一个association标签配置该类的映射

对象集合会创建一个collection标签配置映射

    <resultMap id="DeptMap" type="Dept">
        <id column="id" property="id"/>
        <result column="dname" property="name"/>
        
        <association property="adminUser" javaType="AdminUser">
            <result column="account" property="account"/>
        </association>
        
        <collection property="employees" javaType="list" ofType="Employee">
            <result column="ename" property="name"/>
        </collection>
    </resultMap>

    <select id="getDeptById" resultMap="DeptMap">
        SELECT d.id,d.name dname,emp.name ename,a.account
        FROM dept d LEFT JOIN employee emp ON d.id=emp.deptId
                    LEFT JOIN admin a ON d.adminId=a.id
        WHERE d.id=#{id}
    </select>

主键返回

? 在插入一条记录后,得到数据库自动生成的这条记录的主键id

<!-- useGeneratedKeys="true":获取刚插入数据的id-->
    <insert id="saveAdmin" parameterType="AdminUser" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
        insert into admin(account, password, sex)
        values (#{account}, #{password}, #{sex})
    </insert>

添加log4j日志组件

导入jar坐标

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

在resources下导入log4j.properties文件

log4j.rootLogger = debug,stdout,D
#System out Console
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%p] %d{yyyy-MM-dd HH:mm:ss,SSS} %m%n

#System out File
log4j.appender.D = org.apache.log4j.FileAppender
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = F://java project/logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ] -[%l] %m%n

在mybatis-config.xml中添加设置

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

单元测试

导入jar包

        <!-- junit 本地测试 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <!--也不会打包到war包-->
            <scope>provided</scope>
        </dependency>

懒加载

? 对于关联查询,若不采用延迟加载策略,而是一次性将关联的从信息都查询出来,则在主信息比较多的情况下,会产生N+1问题,导致性能降低。比如在查询员工信息时,设置了关联查询部门信息,如不采用延迟加载策略,查询员工信息时就会把其部门信息全部查询出来,但我们却用不到,就会造成浪费。而懒加载就会让在需要部门信息的时候才执行查询部门的sql

/**
     * 通过id获取员工(懒加载)
     */
    @Test
    public void getEmpById1(){
        SqlSession sqlSession = MybatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        Employee employee = employeeMapper.getEmpById1(1);
        System.out.println(employee.getName());
        System.out.println(employee.getDept().getName());
        System.out.println(employee.getAdminUser().getAccount());
        sqlSession.commit();
        sqlSession.close();
    }

mybatis-config,xml中设置属性:

        <!--懒加载-->
        <!--<setting name="lazyLoadingEnabled" value="true"/>--><!--使用lazy时可省略-->
        <setting name="lazyLoadTriggerMethods" value=""/>
    Employee getEmpById1(int id);
    <resultMap id="EmpMap1" type="Employee">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="age" column="age"/>
        <association property="dept" javaType="Dept" fetchType="lazy"
                     select="getDeptById" column="deptId">
            <result property="name" column="name"/>
        </association>

        <association property="adminUser" javaType="AdminUser" fetchType="lazy"
                    select="getAdminById" column="adminId">
            <result property="account" column="account"/>
        </association>
    </resultMap>

    <select id="getEmpById1" resultMap="EmpMap1">
        select id,name,age,deptId,adminId from employee where id=#{id}
    </select>
    <select id="getAdminById" resultType="AdminUser">
        select * from admin where id=#{id}
    </select>
    <select id="getDeptById" resultType="Dept">
        select * from dept where id=#{id}
    </select>

在这里插入图片描述

动态sql

where

在这里插入图片描述

当需要如上筛选查询时,返回的都是员工列,所以servlet中只用写一套方法,让在其sql中动态添加条件就行

  • name和age在第一次加载页面时传向servlet的值为null,在空值查询时为 ’ ’
  • where 可以根据里边的if是否有成立, 动态添加where关键字 会自动删除and,or等开头的关键字
public class EmployeeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter out = null;
        resp.setContentType("text/html;charset=utf-8");
        try {
            out = resp.getWriter();
            //接收姓名年龄条件瓶存储到一个员工对象中
            String name = req.getParameter("name");
            String age = req.getParameter("age");
            Employee employee = new Employee();
            employee.setName(name);
            //age使用parseInt时需要判断  (第一次查询age为null,筛选查询时为'')
            if (age!=null && !age.equals("")){
                employee.setAge(Integer.parseInt(age));
            }
            EmployeeService employeeService = new EmployeeService();
            List<Employee> empList = employeeService.getEmpList(employee);
            out.println(new Gson().toJson(empList));
        } catch (Exception e) {
            e.printStackTrace();
            out.println(500);
        }
    }
}
public class EmployeeService {
    public List<Employee> getEmpList(Employee employee){
        SqlSession sqlSession = MybatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employees = employeeMapper.getEmpList(employee);
        sqlSession.commit();
        sqlSession.close();
        return employees;
    }
}
public interface EmployeeMapper {
    List<Employee> getEmpList(Employee employee);
}
    <!--<where>:    可以根据里边的if是否有成立, 动态添加where关键字
                    会自动删除and,or等开头的关键字-->
    <select id="getEmpList" parameterType="Employee" resultMap="EmpMap">
        SELECT  emp.id,emp.name ename,emp.age,d.name dname,a.account
        FROM employee emp LEFT JOIN dept d ON emp.deptId=d.id
                          LEFT JOIN admin a ON emp.adminId=a.id
        <where>
            <if test="name!=null &amp; name !='' ">
                emp.name=#{name}
            </if>
            <if test="age!=null &amp; age !='' ">
                and emp.age=#{age}
            </if>
        </where>
    </select>

trim

动态修改

? trim prefix=“where” prefixOverrides=“and||or”

  • 当if有成立条件时,添加一个指定的前缀prefix (where)
  • 如果以prefixOverrides开头,可以覆盖掉关键字(and,or)
    <!--动态查询-->
	<select id="getEmpList" parameterType="Employee" resultMap="EmpMap">
        SELECT  emp.id,emp.name ename,emp.age,d.name dname,a.account
        FROM employee emp LEFT JOIN dept d ON emp.deptId=d.id
                          LEFT JOIN admin a ON emp.adminId=a.id

        <trim prefix="where" prefixOverrides="and||or">
            <if test="name!=null &amp; name !='' ">
                emp.name=#{name}
            </if>
            <if test="age!=null &amp; age !='' ">
                and emp.age=#{age}
            </if>
        </trim>
    </select>

动态删除

? trim prefix=“set” suffixOverrides="," suffix=“where”

  • 当有if成立时,添加前缀set,后缀where
  • 如果以","结尾,直接删除
    <!--动态修改-->
    <update id="updateEmp" parameterType="Employee">
        update employee
        <trim prefix="set" suffixOverrides="," suffix="where">
            <if test="name!=null">name=#{name},</if>
            <if test="age!=null">age=#{age},</if>
            <if test="dept.id!=null">deptId=#{dept.id},</if>
        </trim>
            id=#{id}
    </update>

choose

? 类似if,可用otherwise

    <select id="getEmpList" parameterType="Employee" resultMap="EmpMap">
        SELECT  emp.id,emp.name ename,emp.age,d.name dname,a.account
        FROM employee emp LEFT JOIN dept d ON emp.deptId=d.id
                          LEFT JOIN admin a ON emp.adminId=a.id

        <trim prefix="where" prefixOverrides="and||or">
            <choose>
                <when test="name!=null &amp; name !='' ">
                    and emp.name=#{name}
                </when>
                <!--条件不成立时-->
                <otherwise>
                    and emp.name='abc'
                </otherwise>
            </choose>
            <choose>
                <when test="age!=null &amp; age !='' ">
                    and emp.age=#{age}
                </when>
            </choose>
        </trim>
    </select>

set

? 动态添加set关键字,删掉最后一个逗号

动态修改:传入的为空不改,不为空就修改

    /**
     * 动态修改
     */
    @Test
    public void updateEmp(){
        Employee employee1 = new Employee();
                employee1.setId(1);
                employee1.setName("abc");
                employee1.setAge(20);
        Dept dept = new Dept();
             dept.setId(2);
                employee1.setDept(dept);

        SqlSession sqlSession = MybatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        employeeMapper.updateEmp(employee1);
        sqlSession.commit();
        sqlSession.close();
    }
public interface EmployeeMapper {
    void updateEmp(Employee employee);
}
    <!--动态修改-->
    <update id="updateEmp" parameterType="Employee">
        update employee
        <set>
            <if test="name!=null">name=#{name},</if>
            <if test="age!=null">age=#{age},</if>
            <if test="dept.id!=null">deptId=#{dept.id},</if>
        </set>
        where id=#{id}
    </update>

foreach

? 通过多个age查询时,就要对List中的元素进行遍历

在sql语句中是这样写的:

SELECT * FROM employee WHERE age IN(19,20)

所以使用foreach遍历时,就可以设定前缀、后缀和分隔符

  • item 表示集合中每一个元素进行迭代时的别名
  • index 指定一个名字,用于表示在迭代过程中,每次迭代到的位置
  • open 表示该语句以什么开始
  • separator 表示在每次进行迭代之间以什么符号作为分隔符
  • close 表示以什么结束
  • collection 指定传来的类型(array、list …)
    /**
     * 多个age筛选查询
     */
    @Test
    public void getEmpByAges(){
        List<Integer> ageList = new ArrayList<>();
                ageList.add(18);
                ageList.add(19);
        SqlSession sqlSession = MybatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employees = employeeMapper.getEmpByAges(ageList);
        System.out.println(employees);
        sqlSession.commit();
        sqlSession.close();
    }
public interface EmployeeMapper {
    List<Employee> getEmpByAges(List<Integer> ages);
}
    <!--通过多个age参数查询-->
    <select id="getEmpByAges" resultType="Employee">
        select * from employee
        where age in
        <foreach item="age" collection="list" open="(" separator="," close=")">
            #{age}
        </foreach>
    </select>

特殊符号

在这里插入图片描述

使用案例:通过年龄段查询

    /**
     * 年龄段筛选查询
     */
    @Test
    public void getEmpByAgeInterval(){
        SqlSession sqlSession = MybatisUtil.openSession();
        EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);
        List<Employee> employees = employeeMapper.getEmpByAgeInterval(18,20);
        System.out.println(employees);
        sqlSession.commit();
        sqlSession.close();
    }
public interface EmployeeMapper {
    List<Employee> getEmpByAgeInterval(@Param("min")int min,@Param("max")int max);
}
    <!--通过年龄段查询-->
    <select id="getEmpByAgeInterval" resultType="Employee">
        select * from employee
        where age &gt; #{min} and age &lt; #{max}
    </select>

缓存

  • 缓存(cache)的作用是为了减去数据库的压力,提高数据库的性能。
  • 缓存实现的原理是从数据库中查询出来的对象在使用完后不要销毁,而是存储在内存(缓存)中,当再次需要获取该对象时,直接从内存(缓存)中直接获取,不再向数据库执行 select 语句,从而减少了对数据库的查询次数,因此提高了数据库的性能。
  • 缓存是使用 Map 集合缓存数据的

一级缓存

在这里插入图片描述
? 一级缓存的作用域是同一个 SqlSession,在同一个 sqlSession 中两次执行相同的 sql 语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查 询,从而提高查询效率。当一个 sqlSession 结束后该 sqlSession 中的一级缓存也就不存在了。Mybatis 默认开启一级缓存

在这里插入图片描述

生命周期

  • MyBatis 在开启一个数据库会话时,会创建一个新的 SqlSession 对象,SqlSession 对象中会有一个新的 Executor 对象。Executor 对象中持有一个新的 PerpetualCache 对象,如果 SqlSession 调用了 **close()**方法,会释放掉一级缓存 PerpetualCache 对象,一级缓存将不可用。
  • 如果 SqlSession 调用了 clearCache(),会清空 PerpetualCache 对象中的数据,但是该对象仍可使用。
  • SqlSession 中执行了任何一个 update 操作(update()、delete()、insert()) ,都会清空 PerpetualCache 对象的数据,但是该对象可以继续使用

? 一级缓存时执行commit,close,增删改等操作,就会清空当前的一级缓存;当对SqlSession执行更新操作(update、delete、insert)后并执行commit时,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)

二级缓存

在这里插入图片描述

? 二级缓存是 SqlSessionFactory 级别的,根据 mapper 的 namespace 划分区域的,相同 namespace 的 mapper 查询的数据缓存在同一个区域,如果使用mapper 代理方法每个 mapper 的 namespace 都不同,此时可以理解为二级缓存区域是根据 mapper 划分

? 每次查询会先从缓存区域查找,如果找不到则从数据库查询,并将查询到数据写入缓存。Mybatis 内部存储缓存使用一个 HashMap,key 为hashCode+sqlId+Sql 语句。value 为从查询出来映射生成的 java 对象。

? sqlSession 执行 insert、update、delete 等操作 commit 提交后会清空缓存区域,防止脏读

配置

  1. 开启全局二级缓存配置,在mybatis-config.xml下加设置

    <setting name="cacheEnabled" value="true"/>
    
  2. POJO 序列化 :将所有的 POJO ()类实现序列化接口 Java.io. Serializable

  3. 配置映射文件

    在 Mapper 映射文件中添加 cache,表示此 mapper 开启二级缓存。

    当 SqlSeesion 关闭时,会将数据存入到二级缓存

        <!--配置二级缓存:
                    eviction="FIFO" 回收算法
                            ? LRU – 最近最少使用:移出最近最长时间内都没有被使用的对象
                            ? FIFO –先进先出:移除最先进入缓存的对象
                            ? SOFT – 软引用: 基于垃圾回收机制和软引用规则来移除对象(空间内存不足时才进行回收)
                            ? WEAK – 弱引用: 基于垃圾回收机制和弱引用规则(垃圾回收器扫描到时即进行回收)
                    flushInterval="5000"  刷新时间间隔,毫米为单位
                    size="512" 缓存对象大小
                    readOnly="true"
         -->
        <cache flushInterval="5000"/>
    
  4. 禁用缓存
    如测试sql语句性能时缓存会影响测试准确性 需要禁用在映射文件中:默认值是true useCache=”false”

  5. 刷新缓存
    在映射文件中:属性:flushCache=”true”刷新缓存,在查询语句中,默认值是false,在新增删除修改语句中,默认值是true(清空缓存)
    在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-10 12:16:21  更:2021-11-10 12:17:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:04:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码