• mybatis



    一、特性介绍

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

    2、mybatis支持定制化sql、存储过程、以及高级映射

    3、支持jdbcTemplate模板,减少模板代码和硬编码

    4、MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录

    二、MyBatis的缓存

    默认打开一级缓存,二级没有打开

    1、MyBatis的一级缓存

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

    1.1、使一级缓存失效的四种情况:

    不同的SqlSession对应不同的一级缓存

    同一个SqlSession但是查询条件不同

    同一个SqlSession两次查询期间执行了任何一次增删改操作

    同一个SqlSession两次查询期间手动清空了缓存

    2、MyBatis的二级缓存

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

    2.1二级缓存开启的条件:

    a>在核心配置文件中,设置全局配置属性cacheEnabled=“true”,默认为true,不需要设置
    b>在mapper映射文件中设置标签
    c>二级缓存必须在SqlSession关闭或提交之后有效
    d>查询的数据所转换的实体类类型必须实现序列化的接口

    2.2使二级缓存失效的情况:

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

    3、二级缓存的相关配置

    在mapper配置文件中添加的cache标签可以设置一些属性:

    <cache eviction="FIFO" flushInterval="60000" size="512"  readOnly="true"/>
    
    • 1

    3.1、eviction属性:缓存回收策略,默认的是 LRU

    LRU(Least Recently Used) – 最近最少使用的:移除最长时间不被使用的对象。
    FIFO(First in First out) – 先进先出:按对象进入缓存的顺序来移除它们。
    SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。

    WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

    3.2、flushInterval属性:刷新间隔,单位毫秒

    默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新(清空缓存的意识)

    3.3、size属性:引用数目,正整数

    代表缓存最多可以存储多少个对象,太大容易导致内存溢出

    3.4 、readOnly属性:只读, true/false

    true:只读缓存;会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了 很重要的性能优势。

    false:读写缓存;会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。

    4、MyBatis缓存查询的顺序

    先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
    如果二级缓存没有命中,再查询一级缓存
    如果一级缓存也没有命中,则查询数据库
    SqlSession关闭之后,一级缓存中的数据会写入二级缓存

    三、开发注意的点

    1、传入参数到mapper.xml的sql中

    1、@Param注解可以设置参数的可以名,方便在mapper中 #{key} 或 ${key} 取值可以以这个key名

    Student selectByNameId(@Param("name") String name, @Param("id") String id);
    
    • 1

    2、传入的参数是实体类,直接可以#{属性} 、${属性}获取属性值,

    3、如上多个参数传入映射SQL,写在映射SQL中都是以rg1, arg0, param1, param2为键的map存储

    4、@MapKey注解设置map集合的键,值是每条数据所对应的map集合

    @MapKey("id") //设置每条数据的id为键值为整条数据,这样可以多条放入map中,如下是mapper接口方法
    Map<String, Object> getAllUserToMap();  
    
    • 1
    • 2

    2、${} 和 #{} 的区别

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

    2、${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引
    号;但是#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,
    可以自动添加单引号。

    3、#{}可以防止sql注入,${}不可以

    4、如下方式即避免了${}的注入危险,也达到了拼接字符串的功能。

    select * from t_user where username like "%"#{模糊}"%"
    
    • 1

    3、mapper接口 和 mapper.xml映射文件注意点

    1、mapper接口的全类名和映射文件的命名空间(namespace)保持一致
    2、mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致

    4、动态sql

    1、where标签会将将if条件最前方多余的and去掉 ,不能去掉条件最后多余的and

    2、choose、when、 otherwise相当于if…else if…else

    3、trim用于去掉或添加标签中的内容
    常用属性:
    prefix:在trim标签中的内容的前面添加某些内容
    prefixOverrides:在trim标签中的内容的前面去掉某些内容
    suffix:在trim标签中的内容的后面添加某些内容
    suffixOverrides:在trim标签中的内容的后面去掉某些内容

    <select id="getEmpListByMoreTJ" resultType="Emp">
    	select * from t_emp
    	<trim prefix="where" suffixOverrides="and">
            <if test="ename != '' and ename != null">
            	ename = #{ename} and
            if>
            <if test="age != '' and age != null">
            	age = #{age} and
            if>
            <if test="sex != '' and sex != null">
            	sex = #{sex}
            if>
        trim>
    select>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4、foreach标签,separator分隔符,index 是当前迭代的序号

    <foreach collection="emps" item="emp" open="(" separator="," close=")" index="index">
    	#{emp.id}
    foreach>
    
    • 1
    • 2
    • 3

    四、相关运用讲解

    1、核心配置文件 mybatis_config.xml

    
    DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        
        <properties resource="jdbc.properties"/>
        
        <settings>
            
            <setting name="mapUnderscoreToCamelCase" value="true"/>
            
            <setting name="lazyLoadingEnabled" value="true"/>
            
            <setting name="aggressiveLazyLoading" value="false"/>
        settings>
        
        
        <typeAliases>
            <package name="entity.*"/>
        typeAliases>
        
        <plugins>
            
            <plugin interceptor="com.github.pagehelper.PageHelper">plugin>
        plugins>
        
        
        <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>
    
    
        
        <mappers>
            
            <package name="mapper"/>
            
        mappers>
    
    configuration>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    2、查询结果集中含有实体对象 或 集合 或者 分步查询

    2.1、DeptAndEmpMapper 接口

    package mapper;
    
    import entity.Dept;
    import entity.Emp;
    import org.apache.ibatis.annotations.Param;
    
    public interface DeptAndEmpMapper {
    
        Dept getAllEmpByDept(@Param("deptId") Integer deptId);
    
        Emp getEmpDeptByEmpId(@Param("empId") Integer empId);
    
        Emp getEmpDeptByTowStep(@Param("empId") Integer empId);
    
        Dept getDeptById(@Param("deptId") Integer deptId);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.1核心配置文件中的映射文件 mapper.xml

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="mapper.DeptAndEmpMapper">
        
        <resultMap id="empMap" type="entity.Emp">
            <id column="id" property="id"/>
            <result column="name" property="name"/>
        resultMap>
        <resultMap id="deptMap" type="entity.Dept">
            <id property="deptId" column="dept_id" />
            <result property="deptName" column="dept_name"/>
        resultMap>
    
    
        <resultMap id="empDeptMap" type="entity.Emp">
            <id column="id" property="id"/>
            <result column="name" property="name"/>
            <association property="dept" resultMap="deptMap"/>
        resultMap>
        
        <select id="getEmpDeptByEmpId" parameterType="java.lang.Integer" resultMap="empDeptMap">
            select * from emp e left join dept d on d.dept_id = e.dept_id where e. id = #{empId}
        select>
    
    
        <resultMap id="empByDeptMap" type="entity.Dept">
            <id property="deptId" column="dept_id" />
            <result property="deptName" column="dept_name"/>
            
            <collection property="empList" resultMap="empMap" />
        resultMap>
        
        <select id="getAllEmpByDept" parameterType="java.lang.Integer" resultMap="empByDeptMap">
            select * from dept d left join emp e on d.dept_id = e.dept_id where d.dept_id = #{deptId}
        select>
    
    
        <resultMap id="empDeptByTowStepMap" type="entity.Emp">
            <id column="id" property="id"/>
            <result column="name" property="name"/>
            
            <association property="dept" fetchType="lazy" select="mapper.DeptAndEmpMapper.getDeptById" column="dept_id"/>
        resultMap>
        
        <select id="getEmpDeptByTowStep" parameterType="java.lang.Integer" resultMap="empDeptByTowStepMap">
            select * from emp e where e.id = #{empId}
        select>
        
        <select id="getDeptById" parameterType="java.lang.Integer" resultMap="deptMap">
            select * from dept e where e.dept_id = #{deptId}
        select>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    2.3、测试

    public class DeptAndEmpTest {
    
        private SqlSession getSqlSession() throws IOException {
            //读取核心配置文件
            InputStream resource = Resources.getResourceAsStream("mybatis_config.xml");
            //创建SQLSession工厂类
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resource);
            //创建会话,并设置自动提交事务 true
            return sqlSessionFactory.openSession(true);
    
        }
    
        @Test//3、一对多关系,对象中含有集合-
        public void test01() throws IOException {
            SqlSession sqlSession = getSqlSession();
            DeptAndEmpMapper mapper = sqlSession.getMapper(DeptAndEmpMapper.class);
            Dept allEmpByDept = mapper.getAllEmpByDept(1);
            System.out.println(allEmpByDept);
    
        }
    
        @Test//2、一对一关系,对象中含有对象
        public void test02() throws IOException {
            SqlSession sqlSession = getSqlSession();
            DeptAndEmpMapper mapper = sqlSession.getMapper(DeptAndEmpMapper.class);
            Emp emp = mapper.getEmpDeptByEmpId(1);
            System.out.println(emp);
    
        }
    
        @Test//1、分两次查询sql
        public void test03() throws IOException {
            SqlSession sqlSession = getSqlSession();
            DeptAndEmpMapper mapper = sqlSession.getMapper(DeptAndEmpMapper.class);
            Emp emp = mapper.getEmpDeptByTowStep(1);
            System.out.println(emp.getName());
    
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    3、MyBatis获取参数值的方式

    3.1、StudentMapper 接口

    package mapper;
    
    import entity.Student;
    import org.apache.ibatis.annotations.Param;
    
    public interface StudentMapper {
    
        Student selectStudent(String id);
    
        Student selectByName(String name);
    
        //封装参数以param值为key存入map
        Student selectByNameId(@Param("name") String name, @Param("id") String id);
    
        Student selectByStudent(Student student);
    
        int selectById(String id);
    
        int insertAreaDict(@Param("name") String name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.2、StudentMapper.xml

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="mapper.StudentMapper">
        <resultMap id="studentMap" type="entity.Student">
            <id property="sId" column="s_id"/>
            <result property="sName" column="s_name"/>
            <result property="sBirth" column="s_birth"/>
            <result property="sSex" column="s_sex"/>
        resultMap>
        
        <select id="selectStudent"  resultType="entity.Student" parameterType="java.lang.String">
          select * from student where s_id = #{id}
        select>
    
        <select id="selectById"  resultType="java.lang.Integer">
          select count(*) from student where s_id = #{id}
        select>
    
        
        <select id="selectByName"  resultMap="studentMap" >
          select * from student where s_name = '${value}'
        select>
    
        
        <select id="selectByNameId"  resultMap="studentMap" >
          select * from student where s_name = #{name} and s_id = #{id}
          
          
        select>
    
        
        <select id="selectByStudent"  resultMap="studentMap" parameterType="entity.Student">
          select * from student where s_name = #{SName} and s_id = #{sId}
        select>
    
        
        <insert id="insertAreaDict" useGeneratedKeys="true" keyProperty="UUID">
          INSERT INTO mooc_area_dict_t (UUID,show_name) VALUES (null, #{name});
        insert>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    3.3 测试

    public class MybatisStartTest {
    
        @Test//#{}占位符
        public void test01() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //通过代理模式创建StudentMapper的代理实现类
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
            int count = studentMapper.selectById("01");
            System.out.println(count);
            sqlSession.close();
        }
    
         @Test
        public void test02() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //通过代理模式创建StudentMapper的代理实现类
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
             Student student = studentMapper.selectStudent("01");
             System.out.println(student);
            sqlSession.close();
        }
    
         @Test//${} 3.5版本需要value或者
        public void test03() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //通过代理模式创建StudentMapper的代理实现类
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
             Student student = studentMapper.selectByName("王菊");
             System.out.println(student);
            sqlSession.close();
        }
    
         @Test//@Param设置参数键名
        public void test04() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //通过代理模式创建StudentMapper的代理实现类
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
             Student student = studentMapper.selectByNameId("王菊","08");
             System.out.println(student);
            sqlSession.close();
        }
    
         @Test//参数是实体类型可以直接取属性值
        public void test05() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //通过代理模式创建StudentMapper的代理实现类
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
             Student user = new Student();
             user.setSName("王菊");
             user.setSId("08");
             Student student = studentMapper.selectByStudent(user);
             System.out.println(student);
            sqlSession.close();
        }
    
         @Test//插入数据,自动生成主键id
        public void test06() throws IOException {
            SqlSession sqlSession = getSqlSession();
            //通过代理模式创建StudentMapper的代理实现类
            StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
             studentMapper.insertAreaDict("上传");
            sqlSession.close();
        }
    
        private SqlSession getSqlSession() throws IOException {
            //读取核心配置文件
            InputStream resource = Resources.getResourceAsStream("mybatis_config.xml");
            //创建SQLSession工厂类
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(resource);
            //创建会话,并设置自动提交事务 true
            return sqlSessionFactory.openSession(true);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    五、分页插件的使用

    ①添加依赖

    <dependency>
    	<groupId>com.github.pagehelpergroupId>
    	<artifactId>pagehelperartifactId>
    	<version>5.2.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    ②配置分页插件

    <plugins>
    	
    	<plugin interceptor="com.github.pagehelper.PageInterceptor">plugin>
    plugins>
    
    • 1
    • 2
    • 3
    • 4

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

    pageNum:当前页的页码
    pageSize:每页显示的条数

    2、在查询获取list集合之后,使用PageInfo pageInfo = new PageInfo<>(List list, int navigatePages)获取分页相关数据

    list:分页之后的数据
    navigatePages:导航分页的展示的页码数

    @Test
    public void testPage(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
        //查询功能之前开启分页功能
        Page<Object> page = PageHelper.startPage(5, 4);
        List<Emp> list = mapper.selectByExample(null);
        //查询功能之后可以获取分页相关的所有数据
        PageInfo<Emp> pageInfo = new PageInfo<>(list, 5);
        list.forEach(System.out::println);
        System.out.println(pageInfo);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3、分页相关数据

    PageInfo{
    	pageNum=8, pageSize=4, size=2, startRow=29, endRow=30, total=30, pages=8,
    	list=Page{count=true, pageNum=8, pageSize=4, startRow=28, endRow=32, total=30,
    	pages=8, reasonable=false, pageSizeZero=false},
    	prePage=7, nextPage=0, isFirstPage=false, isLastPage=true, hasPreviousPage=true,
    	hasNextPage=false, navigatePages=5, navigateFirstPage4, navigateLastPage8,
    	navigatepageNums=[4, 5, 6, 7, 8]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    pageNum:当前页的页码
    pageSize:每页显示的条数
    size:当前页显示的真实条数
    total:总记录数
    pages:总页数
    prePage:上一页的页码
    nextPage:下一页的页码
    isFirstPage/isLastPage:是否为第一页/最后一页
    hasPreviousPage/hasNextPage:是否存在上一页/下一页
    navigatePages:导航分页展示的页码数
    navigatepageNums:导航分页的页码,[1,2,3,4,5]

  • 相关阅读:
    【小沐学NLP】AI辅助编程工具汇总
    薛定谔的文件上传
    微服务开发与实战Day02 - Docker
    Linux下的文件操作和文件管理
    JAVA实现PDF转图片
    YOLOv8改进 | ICLR 2022 |ODConv附修改后的C2f、Bottleneck模块代码
    一种车载监控数据存储方法
    Go 实现选择排序算法及优化
    golang学习笔记(defer基础知识)
    1.4.25 实验25:华为高级ACL
  • 原文地址:https://blog.csdn.net/jue6628/article/details/126513273