MyBatis学习笔记——4

news2024/11/28 1:52:46

MyBatis学习笔记——4

  • 一、MyBatis的高级映射及延迟加载
    • 1.1、多对一
      • 1.1.1、第一种方式:级联属性映射
      • 1.1.2、第二种方式:association
      • 1.1.3、第三种方式:分步查询
    • 1.2、一对多
      • 1.2.1、第一种方式:collection
      • 1.2.1、第二种方式:分步查询
  • 二、MyBatis的缓存
    • 2.1、一级缓存
    • 2.2、二级缓存
    • 2.3、MyBatis集成EhCache
  • 三、MyBatis的逆向工程
    • 3.1、 逆向工程配置与生成
  • 3.2、测试逆向工程生成的是否好用
  • 四、MyBatis使用PageHelper
    • 4.1、limit分页
    • 4.2、PageHelper插件
  • 五、MyBatis的注解式开发
    • 5.1、 @Insert
    • 5.2、@Delete
    • 5.3、@Update
    • 5.4、@Select

一、MyBatis的高级映射及延迟加载

1.1、多对一

在这里插入图片描述
多种方式,常见的包括三种:

  • 第一种方式:一条SQL语句,级联属性映射。
  • 第二种方式:一条SQL语句,association。
  • 第三种方式:两条SQL语句,分步查询。(这种方式常用:优点一是可复用。优点二是支持懒加载。)

1.1.1、第一种方式:级联属性映射

pojo类Student中添加一个属性:Clazz clazz; 表示学生关联的班级对象。

package com.powernode.mybatis.pojo;

public class Student {
    private Integer sid;
    private String sname;
    private Clazz clazz;

    public Clazz getClazz() {
        return clazz;
    }

    public void setClazz(Clazz clazz) {
        this.clazz = clazz;
    }

    @Override
    public String toString() {
        return "Student{" +
                "sid=" + sid +
                ", sname='" + sname + '\'' +
                ", clazz=" + clazz +
                '}';
    }

    public Student() {
    }

    public Student(Integer sid, String sname) {
        this.sid = sid;
        this.sname = sname;
    }

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }
}

<?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.powernode.mybatis.mapper.StudentMapper">

    <resultMap id="studentResultMap" type="Student">
        <id property="sid" column="sid"/>
        <result property="sname" column="sname"/>
        <result property="clazz.cid" column="cid"/>
        <result property="clazz.cname" column="cname"/>
    </resultMap>

    <select id="selectBySid" resultMap="studentResultMap">
        select s.*, c.* from t_student s join t_clazz c on s.cid = c.cid where sid = #{sid}
    </select>

</mapper>
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.StudentMapper;
import com.powernode.mybatis.pojo.Student;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.junit.Test;

public class StudentMapperTest {
    @Test
    public void testSelectBySid(){
        StudentMapper mapper = SqlSessionUtil.openSession().getMapper(StudentMapper.class);
        Student student = mapper.selectBySid(1);
        System.out.println(student);
    }
}

1.1.2、第二种方式:association

其他位置都不需要修改,只需要修改resultMap中的配置:association即可。

<resultMap id="studentResultMap" type="Student">
  <id property="sid" column="sid"/>
  <result property="sname" column="sname"/>
  <association property="clazz" javaType="Clazz">
    <id property="cid" column="cid"/>
    <result property="cname" column="cname"/>
  </association>
</resultMap>

association翻译为:关联。
学生对象关联一个班级对象。

1.1.3、第三种方式:分步查询

其他位置不需要修改,只需要修改以及添加以下三处:

第一处associationselect位置填写sqlIdsqlId=namespace+id。其中column属性作为这条子sql语句的条件。

<resultMap id="studentResultMap" type="Student">
  <id property="sid" column="sid"/>
  <result property="sname" column="sname"/>
  <association property="clazz"
               select="com.powernode.mybatis.mapper.ClazzMapper.selectByCid"
               column="cid"/>
</resultMap>

<select id="selectBySid" resultMap="studentResultMap">
  select s.* from t_student s where sid = #{sid}
</select>

第二处:在ClazzMapper接口中添加方法

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Clazz;

/**
 * Clazz映射器接口
 * @author 老杜
 * @version 1.0
 * @since 1.0
 */
public interface ClazzMapper {

    /**
     * 根据cid获取Clazz信息
     * @param cid
     * @return
     */
    Clazz selectByCid(Integer cid);
}

第三处:在ClazzMapper.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">

<mapper namespace="com.powernode.mybatis.mapper.ClazzMapper">
    <select id="selectByCid" resultType="Clazz">
        select * from t_clazz where cid = #{cid}
    </select>
</mapper>

在这里插入图片描述

分步优点:

  • 第一个优点:代码复用性增强。
  • 第二个优点:支持延迟加载。【暂时访问不到的数据可以先不查询。提高程序的执行效率。】
  • 懒加载作用:
    • 提高性能,尽可能地不查,或者说尽可能的少查,来提高性能
  • 如何开启懒加载
    • association标签中添加fetchType="lazy"
    • 注意:默认情况下是没有开启延迟加载的。需要设置: fetchType="lazy"
    • 这种在association标签中配置fetchType="lazy",是局部的设置,只对当前association关联的sql语句起作用。
    • 通过fetchType="eager"来关闭懒加载
  • 如何设置全局的懒加载开关?
    • 在mybatis的核心配置文件中添加lazyLoadingEnabled属性,设置为true

在这里插入图片描述

  • 在实际开发中,开启全局的延迟加载机制,对于特殊不需要使用懒加载的通过fetchType="eager"来关闭懒加载

1.2、一对多

一对多的实现,通常是在一的一方中有List集合属性。

在Clazz类中添加List<Student> stus; 属性。

public class Clazz {
    private Integer cid;
    private String cname;
    private List<Student> stus;
    // set get方法
    // 构造方法
    // toString方法
}

一对多的实现通常包括两种实现方式:

  • 第一种方式:collection
  • 第二种方式:分步查询

1.2.1、第一种方式:collection

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Clazz;
public interface ClazzMapper {

    /**
     * 根据cid获取Clazz信息
     * @param cid
     * @return
     */
    Clazz selectByCid(Integer cid);

    /**
     * 根据班级编号查询班级信息。同时班级中所有的学生信息也要查询。
     * @param cid
     * @return
     */
    Clazz selectClazzAndStusByCid(Integer cid);
}

<resultMap id="clazzResultMap" type="Clazz">
  <id property="cid" column="cid"/>
  <result property="cname" column="cname"/>
  <collection property="stus" ofType="Student">
    <id property="sid" column="sid"/>
    <result property="sname" column="sname"/>
  </collection>
</resultMap>

<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
  select * from t_clazz c join t_student s on c.cid = s.cid where c.cid = #{cid}
</select>

注意是ofType,表示“集合中的类型”。

package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.ClazzMapper;
import com.powernode.mybatis.pojo.Clazz;
import com.powernode.mybatis.utils.SqlSessionUtil;
import org.junit.Test;

public class ClazzMapperTest {
    @Test
    public void testSelectClazzAndStusByCid() {
        ClazzMapper mapper = SqlSessionUtil.openSession().getMapper(ClazzMapper.class);
        Clazz clazz = mapper.selectClazzAndStusByCid(1001);
        System.out.println(clazz);
    }
}

1.2.1、第二种方式:分步查询

修改以下三个位置即可:

<resultMap id="clazzResultMap" type="Clazz">
  <id property="cid" column="cid"/>
  <result property="cname" column="cname"/>
  <!--主要看这里-->
  <collection property="stus"
              select="com.powernode.mybatis.mapper.StudentMapper.selectByCid"
              column="cid"/>
</resultMap>

<!--sql语句也变化了-->
<select id="selectClazzAndStusByCid" resultMap="clazzResultMap">
  select * from t_clazz c where c.cid = #{cid}
</select>
/**
* 根据班级编号获取所有的学生。
* @param cid
* @return
*/
List<Student> selectByCid(Integer cid);
<select id="selectByCid" resultType="Student">
  select * from t_student where cid = #{cid}
</select>

一对多延迟加载机制和多对一是一样的。同样是通过两种方式:

  • 第一种:fetchType=“lazy”
  • 第二种:修改全局的配置setting,lazyLoadingEnabled=true,如果开启全局延迟加载,想让某个sql不使用延迟加载:fetchType=“eager”

二、MyBatis的缓存

缓存:cache

缓存的作用:通过减少IO的方式,来提高程序的执行效率。

mybatis的缓存:将select语句的查询结果放到缓存(内存)当中,下一次还是这条select语句的话,直接从缓存中取,不再查数据库。一方面是减少了IO。另一方面不再执行繁琐的查找算法。效率大大提升。

mybatis缓存包括:

  • 一级缓存:将查询到的数据存储到SqlSession中。
  • 二级缓存:将查询到的数据存储到SqlSessionFactory中。
  • 或者集成其它第三方的缓存:比如EhCache【Java语言开发的】、Memcache【C语言开发的】等。

常见的缓存技术:
+ 字符串常量池
+ 整数型常量池
+ 线程池
+ 连接池
+ …

缓存只针对于DQL语句,也就是说缓存机制只对应select语句。

2.1、一级缓存

一级缓存默认是开启的。不需要做任何配置。

原理:只要使用同一个SqlSession对象执行同一条SQL语句,就会走缓存。

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;

public interface CarMapper {

    /**
     * 根据id获取Car信息。
     * @param id
     * @return
     */
    Car selectById(Long 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">

<mapper namespace="com.powernode.mybatis.mapper.CarMapper">

  <select id="selectById" resultType="Car">
    select * from t_car where id = #{id}
  </select>

</mapper>
**package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.utils.SqlSessionUtil;
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 org.junit.Test;

public class CarMapperTest {

    @Test
    public void testSelectById() throws Exception{
        // 注意:不能使用我们封装的SqlSessionUtil工具类。
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory sqlSessionFactory = builder.build(Resources.getResourceAsStream("mybatis-config.xml"));

        SqlSession sqlSession1 = sqlSessionFactory.openSession();

        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(83L);
        System.out.println(car1);

        CarMapper mapper2 = sqlSession1.getMapper(CarMapper.class);
        Car car2 = mapper2.selectById(83L);
        System.out.println(car2);

        SqlSession sqlSession2 = sqlSessionFactory.openSession();

        CarMapper mapper3 = sqlSession2.getMapper(CarMapper.class);
        Car car3 = mapper3.selectById(83L);
        System.out.println(car3);

        CarMapper mapper4 = sqlSession2.getMapper(CarMapper.class);
        Car car4 = mapper4.selectById(83L);
        System.out.println(car4);

    }
}

什么情况下不走缓存?

  • 第一种:不同的SqlSession对象。
  • 第二种:查询条件变化了。

一级缓存失效情况包括两种:

  • 第一种:第一次查询和第二次查询之间,手动清空了一级缓存。
sqlSession.clearCache();
  • 第二种:第一次查询和第二次查询之间,执行了增删改操作。【这个增删改和哪张表没有关系,只要有insert delete update操作,一级缓存就失效。】
/**
* 保存账户信息
*/
void insertAccount();
<insert id="insertAccount">
  insert into t_act values(3, 'act003', 10000)
</insert>

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

2.2、二级缓存

二级缓存的范围是SqlSessionFactory
使用二级缓存需要具备以下几个条件:

  1. <setting name="cacheEnabled" value="true"> 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认就是true,无需设置。
  2. 在需要使用二级缓存的SqlMapper.xml文件中添加配置:<cache />
  3. 使用二级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接口
  4. SqlSession对象关闭或提交之后,一级缓存中的数据才会被写入到二级缓存当中。此时二级缓存才可用。

测试二级缓存:

XxxMapper.xml文件

<cache/>

Xxx类文件

public class Car implements Serializable {
//......
}

测试类

@Test
public void testSelectById2() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));

    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
    Car car1 = mapper1.selectById(83L);
    System.out.println(car1);

    // 关键一步
    sqlSession1.close();

    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
    Car car2 = mapper2.selectById(83L);
    System.out.println(car2);
}

二级缓存的失效:只要两次查询之间出现了增删改操作。二级缓存就会失效。【一级缓存也会失效】

在这里插入图片描述

  1. eviction:指定从缓存中移除某个对象的淘汰算法。默认采用LRU策略。
    • LRU:Least Recently Used。最近最少使用。优先淘汰在间隔时间内使用频率最低的对象。(其实还有一种淘汰算法LFU,最不常用。)
    • FIFO:First In First Out。一种先进先出的数据缓存器。先进入二级缓存的对象最先被淘汰。
    • SOFT:软引用。淘汰软引用指向的对象。具体算法和JVM的垃圾回收算法有关。
    • WEAK:弱引用。淘汰弱引用指向的对象。具体算法和JVM的垃圾回收算法有关。
  2. flushInterval:
    • 二级缓存的刷新时间间隔。单位毫秒。如果没有设置。就代表不刷新缓存,只要内存足够大,一直会向二级缓存中缓存数据。除非执行了增删改。
  3. readOnly:
    • true:多条相同的sql语句执行之后返回的对象是共享的同一个。性能好。但是多线程并发可能会存在安全问题。
    • false:多条相同的sql语句执行之后返回的对象是副本,调用了clone方法。性能一般。但安全。
  4. size:
    • 设置二级缓存中最多可存储的java对象数量。默认值1024。

2.3、MyBatis集成EhCache

集成EhCache是为了代替mybatis自带的二级缓存。一级缓存是无法替代的。

mybatis对外提供了接口,也可以集成第三方的缓存组件。比如EhCache、Memcache等。都可以。

EhCache是Java写的。Memcache是C语言写的。所以mybatis集成EhCache较为常见,按照以下步骤操作,就可以完成集成:

第一步:引入mybatis整合ehcache的依赖。

<!--mybatis集成ehcache的组件-->
<dependency>
  <groupId>org.mybatis.caches</groupId>
  <artifactId>mybatis-ehcache</artifactId>
  <version>1.2.2</version>
</dependency>

第二步:在类的根路径下新建echcache.xml文件,并提供以下配置信息。

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存-->
    <diskStore path="e:/ehcache"/>
  
    <!--defaultCache:默认的管理策略-->
    <!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断-->
    <!--maxElementsInMemory:在内存中缓存的element的最大数目-->
    <!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上-->
    <!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false-->
    <!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问-->
    <!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问-->
    <!--memoryStoreEvictionPolicy:缓存的3 种清空策略-->
    <!--FIFO:first in first out (先进先出)-->
    <!--LFU:Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存-->
    <!--LRU:Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存-->
    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false" diskPersistent="false"
                  timeToIdleSeconds="0" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU"/>

</ehcache>

第三步:修改SqlMapper.xml文件中的标签,添加type属性。

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

第四步:编写测试程序使用。

@Test
public void testSelectById2() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    
    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
    Car car1 = mapper1.selectById(83L);
    System.out.println(car1);
    
    sqlSession1.close();
    
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
    Car car2 = mapper2.selectById(83L);
    System.out.println(car2);
}

在这里插入图片描述

三、MyBatis的逆向工程

所谓的逆向工程是:根据数据库表逆向生成Java的pojo类,SqlMapper.xml文件,以及Mapper接口类等。
要完成这个工作,需要借助别人写好的逆向工程插件。
思考:使用这个插件的话,需要给这个插件配置哪些信息?

  • pojo类名、包名以及生成位置。
  • SqlMapper.xml文件名以及生成位置。
  • Mapper接口名以及生成位置。
  • 连接数据库的信息。
  • 指定哪些表参与逆向工程。

3.1、 逆向工程配置与生成

第一步:基础环境准备
新建模块:模块名
打包方式:jar

第二步:在pom中添加逆向工程插件

<!--定制构建过程-->
<build>
  <!--可配置多个插件-->
  <plugins>
    <!--其中的一个插件:mybatis逆向工程插件-->
    <plugin>
      <!--插件的GAV坐标-->
      <groupId>org.mybatis.generator</groupId>
      <artifactId>mybatis-generator-maven-plugin</artifactId>
      <version>1.3.7</version>
      <!--允许覆盖-->
      <configuration>
        <overwrite>true</overwrite>
      </configuration>
      <!--插件的依赖-->
      <dependencies>
        <!--mysql驱动依赖-->
        <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.30</version>
        </dependency>
      </dependencies>
    </plugin>
  </plugins>
</build>

第三步:配置generatorConfig.xml

该文件名必须叫做: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:生成的是基础版,只有基本的增删改查。
            MyBatis3:生成的是增强版,除了基本的增删改查之外还有复杂的增删改查。
    -->
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <!--防止生成重复代码-->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin"/>
      
        <commentGenerator>
            <!--是否去掉生成日期-->
            <property name="suppressDate" value="true"/>
            <!--是否去除注释-->
            <property name="suppressAllComments" value="true"/>
        </commentGenerator>

        <!--连接数据库信息-->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/powernode"
                        userId="root"
                        password="root">
        </jdbcConnection>

        <!-- 生成pojo包名和位置 -->
        <javaModelGenerator targetPackage="com.powernode.mybatis.pojo" targetProject="src/main/java">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
            <!--是否去除字段名的前后空白-->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <!-- 生成SQL映射文件的包名和位置 -->
        <sqlMapGenerator targetPackage="com.powernode.mybatis.mapper" targetProject="src/main/resources">
            <!--是否开启子包-->
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>

        <!-- 生成Mapper接口的包名和位置 -->
        <javaClientGenerator
                type="xmlMapper"
                targetPackage="com.powernode.mybatis.mapper"
                targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>

        <!-- 表名和对应的实体类名-->
        <table tableName="t_car" domainObjectName="Car"/>

    </context>
</generatorConfiguration>

第四步:运行插件

在这里插入图片描述

3.2、测试逆向工程生成的是否好用

第一步:环境准备

  • 依赖:mybatis依赖、mysql驱动依赖、junit依赖、logback依赖
  • jdbc.properties
  • mybatis-config.xml
  • logback.xml

第二步:编写测试程序

package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
import com.powernode.mybatis.pojo.CarExample;
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 org.junit.Test;

import java.math.BigDecimal;
import java.util.List;

public class GeneratorTest {
    @Test
    public void testGenerator() throws Exception{
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        // 增
        /*Car car = new Car();
        car.setCarNum("1111");
        car.setBrand("比亚迪唐");
        car.setGuidePrice(new BigDecimal(30.0));
        car.setProduceTime("2010-10-12");
        car.setCarType("燃油车");
        int count = mapper.insert(car);
        System.out.println("插入了几条记录:" + count);*/
        // 删
        /*int count = mapper.deleteByPrimaryKey(83L);
        System.out.println("删除了几条记录:" + count);*/
        // 改
        // 根据主键修改
        /*Car car = new Car();
        car.setId(89L);
        car.setGuidePrice(new BigDecimal(20.0));
        car.setCarType("新能源");
        int count = mapper.updateByPrimaryKey(car);
        System.out.println("更新了几条记录:" + count);*/
        // 根据主键选择性修改
        /*car = new Car();
        car.setId(89L);
        car.setCarNum("3333");
        car.setBrand("宝马520Li");
        car.setProduceTime("1999-01-10");
        count = mapper.updateByPrimaryKeySelective(car);
        System.out.println("更新了几条记录:" + count);*/

        // 查一个
        Car car = mapper.selectByPrimaryKey(89L);
        System.out.println(car);
        // 查所有
        List<Car> cars = mapper.selectByExample(null);
        cars.forEach(c -> System.out.println(c));
        // 多条件查询
        // QBC 风格:Query By Criteria 一种查询方式,比较面向对象,看不到sql语句。
        CarExample carExample = new CarExample();
        carExample.createCriteria()
                .andBrandEqualTo("丰田霸道")
                .andGuidePriceGreaterThan(new BigDecimal(60.0));
        carExample.or().andProduceTimeBetween("2000-10-11", "2022-10-11");

        mapper.selectByExample(carExample);
        sqlSession.commit();
    }
}

QBC 风格:Query By Criteria 一种查询方式,比较面向对象,看不到sql语句

四、MyBatis使用PageHelper

4.1、limit分页

mysql的limit后面两个数字:

  • 第一个数字:startIndex(起始下标。下标从0开始。)
  • 第二个数字:pageSize(每页显示的记录条数)

假设已知页码pageNum,还有每页显示的记录条数pageSize,第一个数字可以动态的获取吗?

  • startIndex = (pageNum - 1) * pageSize

所以,标准通用的mysql分页SQL:

select 
  * 
from 
  tableName ...... 
limit 
  (pageNum - 1) * pageSize, pageSize

使用mybatis应该怎么做?

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface CarMapper {
    
    /**
    * 通过分页的方式获取Car列表
    * @param startIndex 页码
    * @param pageSize 每页显示记录条数
    * @return
    */
    List<Car> selectAllByPage(@Param("startIndex") Integer startIndex, @Param("pageSize") Integer pageSize);
}
<?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.powernode.mybatis.mapper.CarMapper">

    <select id="selectAllByPage" resultType="Car">
        select * from t_car limit #{startIndex},#{pageSize}
    </select>
</mapper>
package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
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 org.junit.Test;

import java.util.List;

public class PageTest {
    @Test
    public void testPage()throws Exception{
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);

        // 页码
        Integer pageNum = 2;
        // 每页显示记录条数
        Integer pageSize = 3;
        // 起始下标
        Integer startIndex = (pageNum - 1) * pageSize;

        List<Car> cars = mapper.selectAllByPage(startIndex, pageSize);
        cars.forEach(car -> System.out.println(car));

        sqlSession.commit();
        sqlSession.close();
    }
}

在这里插入图片描述

获取数据不难,难的是获取分页相关的数据比较难。可以借助mybatis的PageHelper插件。

4.2、PageHelper插件

使用PageHelper插件进行分页,更加的便捷。

第一步:引入依赖

<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper</artifactId>
  <version>5.3.1</version>
</dependency>

第二步:在mybatis-config.xml文件中配置插件

typeAliases标签下面进行配置:

<plugins>
  <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

第三步:编写Java代码

List<Car> selectAll();
<select id="selectAll" resultType="Car">
  select * from t_car
</select>

关键点:

  • 在查询语句之前开启分页功能。
  • 在查询语句之后封装PageInfo对象。(PageInfo对象将来会存储到request域当中。在页面上展示。)
@Test
public void testPageHelper() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);

    // 开启分页
    PageHelper.startPage(2, 2);

    // 执行查询语句
    List<Car> cars = mapper.selectAll();

    // 获取分页信息对象
    PageInfo<Car> pageInfo = new PageInfo<>(cars, 5);

    System.out.println(pageInfo);
}

执行结果:

PageInfo{pageNum=2, pageSize=2, size=2, startRow=3, endRow=4, total=6, pages=3, list=Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=6, pages=3, reasonable=false, pageSizeZero=false}[Car{id=86, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'}, Car{id=87, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'}], prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, navigatePages=5, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]}

对执行结果进行格式化:

PageInfo{
  pageNum=2, pageSize=2, size=2, startRow=3, endRow=4, total=6, pages=3, 
  list=Page{count=true, pageNum=2, pageSize=2, startRow=2, endRow=4, total=6, pages=3, reasonable=false, pageSizeZero=false}
  [Car{id=86, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'}, 
  Car{id=87, carNum='1234', brand='丰田霸道', guidePrice=50.5, produceTime='2020-10-11', carType='燃油车'}], 
  prePage=1, nextPage=3, isFirstPage=false, isLastPage=false, hasPreviousPage=true, hasNextPage=true, 
  navigatePages=5, navigateFirstPage=1, navigateLastPage=3, navigatepageNums=[1, 2, 3]
}

五、MyBatis的注解式开发

mybatis中也提供了注解式开发方式,采用注解可以减少Sql映射文件的配置。
当然,使用注解式开发的话,sql语句是写在java程序中的,这种方式也会给sql语句的维护带来成本。
官方是这么说的:

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

使用注解编写复杂的SQL是这样的:
在这里插入图片描述
原则:简单sql可以注解。复杂sql使用xml。

5.1、 @Insert

package com.powernode.mybatis.mapper;

import com.powernode.mybatis.pojo.Car;
import org.apache.ibatis.annotations.Insert;

public interface CarMapper {

    @Insert(value="insert into t_car values(null,#{carNum},#{brand},#{guidePrice},#{produceTime},#{carType})")
    int insert(Car car);
}

package com.powernode.mybatis.test;

import com.powernode.mybatis.mapper.CarMapper;
import com.powernode.mybatis.pojo.Car;
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 org.junit.Test;

public class AnnotationTest {
    @Test
    public void testInsert() throws Exception{
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        SqlSession sqlSession = sqlSessionFactory.openSession();
        CarMapper mapper = sqlSession.getMapper(CarMapper.class);
        Car car = new Car(null, "1112", "卡罗拉", 30.0, "2000-10-10", "燃油车");
        int count = mapper.insert(car);
        System.out.println("插入了几条记录:" + count);
        sqlSession.commit();
        sqlSession.close();
    }
}

5.2、@Delete

@Delete("delete from t_car where id = #{id}")
int deleteById(Long id);
@Test
public void testDelete() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    mapper.deleteById(89L);
    sqlSession.commit();
    sqlSession.close();
}

5.3、@Update

@Update("update t_car set car_num=#{carNum},brand=#{brand},guide_price=#{guidePrice},produce_time=#{produceTime},car_type=#{carType} where id=#{id}")
int update(Car car);
@Test
public void testUpdate() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CarMapper mapper = sqlSession.getMapper(CarMapper.class);
    Car car = new Car(88L,"1001", "凯美瑞", 30.0,"2000-11-11", "新能源");
    mapper.update(car);
    sqlSession.commit();
    sqlSession.close();
}

5.4、@Select

@Select("select * from t_car where id = #{id}")
@Results({
    @Result(column = "id", property = "id", id = true),
    @Result(column = "car_num", property = "carNum"),
    @Result(column = "brand", property = "brand"),
    @Result(column = "guide_price", property = "guidePrice"),
    @Result(column = "produce_time", property = "produceTime"),
    @Result(column = "car_type", property = "carType")
})
Car selectById(Long id);
@Test
public void testSelectById() throws Exception{
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    CarMapper carMapper = sqlSession.getMapper(CarMapper.class);
    Car car = carMapper.selectById(88L);
    System.out.println(car);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/780019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux Ubuntu crontab 添加错误 提示:no crontab for root - using an empty one 888

资料 错误提示&#xff1a; no crontab for root - using an empty one 888 原因剖析&#xff1a; 第一次使用crontab -e 命令时会让我们选择编辑器&#xff0c;很多人会不小心选择默认的nano&#xff08;不好用&#xff09;&#xff0c;或则提示no crontab for root - usin…

一文了解Python中的while循环语句

目录 &#x1f969;循环语句是什么 &#x1f969;while循环 &#x1f969;遍历猜数字 &#x1f969;while循环嵌套 &#x1f969;while循环嵌套案例 &#x1f990;博客主页&#xff1a;大虾好吃吗的博客 &#x1f990;专栏地址&#xff1a;Python从入门到精通专栏 循环语句是什…

【N32L40X】学习笔记11-ADC规则通道采集+dma数据传输

ADC规则通道转换 概述 支持 1 个 ADC&#xff0c;支持单端输入和差分输入&#xff0c;最多可测量 16 个外部和 3 个内部源。支持 12 位、10 位、8 位、6 位分辨率。ADC 时钟源分为工作时钟源、采样时钟源和计时时钟源 仅可配置 AHB_CLK 作为工作时钟源。可配置 PLL 作为采样时…

【安全】Sqllabs(1-4) 多种情况浅析

目录 环境⭐ 先要 ⭐⭐⭐⭐⭐ Less - 1 (information_shcema) Less - 2 (假设没有information_schema) Less - 3 (无列名注入) Less - 4 环境⭐ MySQL8.0.12 Nginx1.15.11 先要 ⭐⭐⭐⭐⭐ MySQL5.0以上有这几个数据库mysql, sys&#xff0c;information_schema informa…

前端性能优化——图片优化

一、图片优化措施 优化图片是 Web 前端优化的重要一环&#xff0c;因为图片是 Web 页面中最耗费带宽和加载时间的资源之一。以下是一些通过优化图片来优化 Web 前端的方法&#xff1a; 压缩图片&#xff1a;压缩图片可以减少图片的文件大小&#xff0c;从而减少加载时间。 使…

【数学建模】相关是一个距离指标吗?

一、说明 本文探讨最平凡的数学模型--距离模型。我们知道&#xff0c;任何数学模型如果是个距离模型&#xff0c;那么它是&#xff1a;放心的、自动的、不加任意条件的指标项目。然而另一些度量参数不是距离空间&#xff0c;因此&#xff0c;使用起来必须外加若干条件&#xff…

苹果iOS 16.6 RC发布:或为iPhone X/8系列养老版本

今天苹果向iPhone用户推送了iOS 16.6 RC更新(内部版本号&#xff1a;20G75)&#xff0c;这是时隔两个月的首次更新。 按照惯例RC版基本不会有什么问题&#xff0c;会在最近一段时间内直接变成正式版&#xff0c;向所有用户推送。 需要注意的是&#xff0c;鉴于iOS 17正式版即将…

【CN-Docker】window11下Docker下开启kubernetes

1. 安装Docker 安装docker步骤如下&#xff1a; 下载Docker启用hyper-v 2.1.powershell&#xff0c;管理员运行Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All安装wsl配置Docker镜像加速地址(阿里云) 4.1. "registry-mirrors": [&quo…

Qt/C++音视频开发48-推流到rtsp服务器

一、前言 之前已经打通了rtmp的推流&#xff0c;理论上按照同样的代码&#xff0c;只要将rtmp推流地址换成rtsp推流地址&#xff0c;然后格式将flv换成rtsp就行&#xff0c;无奈直接遇到协议不支持的错误提示&#xff0c;网上说要换成rtp&#xff0c;换了也没用&#xff0c;而…

C++之mutable关键字实例(一百六十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

【C++链表】

目录 前言一、搭建链表实现的框架二、链表的构造函数三、链表的尾插四、链表的遍历(重点)迭代器的遍历const修饰的迭代器 五、代码实现 前言 最近用C写了一下list的基本功能&#xff0c;感触颇深。本以为会跟之前用C写list一样会很轻松&#xff0c;没想到更难了。要考虑的东西…

【数据结构】C--单链表(小白入门基础知识)

前段时间写了一篇关于顺序表的博客&#xff0c;http://t.csdn.cn/0gCRp 顺序表在某些时候存在着一些不可避免的缺点: 问题&#xff1a; 1. 中间 / 头部的插入删除&#xff0c;时间复杂度为 O(N) 2. 增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不…

第110天:免杀对抗-GOC#反VT沙盒逆向调试参数加载资源分离混淆加密

知识点 #知识点&#xff1a; 1、C#-混淆&分离&反调试 2、GO-混淆&分离&反调试 3、成品程序-包含反调试VT#章节点&#xff1a; 编译代码面-ShellCode-混淆 编译代码面-编辑执行器-编写 编译代码面-分离加载器-编写 程序文件面-特征码定位-修改 程序文件面-加壳…

Progressive Dual-Branch Network for Low-Light Image Enhancement 论文阅读笔记

这是22年中科院2区期刊的一篇有监督暗图增强的论文 网络结构如下图所示&#xff1a; ARM模块如下图所示&#xff1a; CAB模块如下图所示&#xff1a; LKA模块其实就是放进去了一些大卷积核&#xff1a; AFB模块如下图所示&#xff1a; 这些网络结构没什么特别的&#xf…

【团队协作开发】将Gitee项目导入到本地IDEA中出现根目录不完整的问题解决(已解决)

前言&#xff1a;在团队协作开发过程中&#xff0c;通常我们的Gitee完整项目中会包含很多内容&#xff1a;后端代码、前端代码、项目结构图、项目文档等一系列资产。 将Gitee项目导入到本地IDEA中&#xff0c;通常会出现根目录不完整的问题。这是因为项目里面包含了后端代码、前…

Matlab的GUI设计

文章目录 AppDesigner各个版本的特点mlapp文件基本格式AppDesigner的回调函数常见控件的属性MVC模式MVC模式设计GUIMVC简单使用 其他让app designer置顶将Guide的GUI导出为m文件将app编译为exe将app中的多个控件组合在一起 AppDesigner 20200328 各个版本的特点 在2017b版本中…

用 Node.js 手写 WebSocket 协议

目录 引言 从 http 到 websocekt 的切换 Sec-WebSocket-Key 与 Sec-WebSocket-Accept 全新的二进制协议 自己实现一个 websocket 服务器 按照协议格式解析收到的Buffer 取出opcode 取出MASK与payload长度 根据mask key读取数据 根据类型处理数据 frame 帧 数据的发…

【C++模拟实现】string的模拟实现

【C模拟实现】string的模拟实现 目录 【C模拟实现】string的模拟实现string模拟实现的标准代码string模拟实现中的要点string构造函数的实现赋值运算符重载迭代器的实现对流插入和流提取运算符的重载find函数的实现insert函数的实现 作者&#xff1a;爱写代码的刚子 时间&#…

MySQL视图概念及作用、操作语法

1.什么是视图 在数据库中有一些用户的敏感数据字段不方便展示&#xff0c;需要隐藏时&#xff0c;这时候就可以利用视图这个概念来实现。 2.视图操作 如何对视图里的数据进行增删改操作呢&#xff1f; 可以直接通过insert语句向视图里面插入数据&#xff0c;语法和向表里插…

移动测试(二)

功能测试点 用户使用习惯 权限问题 硬件问题 比如双卡双待、摄像头、GPU等。 操作习惯 用户常用的有菜单键、Home键、返回键、Home键长按&#xff08;显示当前进程列表&#xff09;、调整音量、待机等。相应的作为测试工程师我们需要考虑的项就变成了&#xff1a; • 应用中的…