MyBatis学习笔记——4

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;}@Overridepublic 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 mapperPUBLIC "-//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 {@Testpublic 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 mapperPUBLIC "-//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 {@Testpublic 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 mapperPUBLIC "-//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 {@Testpublic 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 generatorConfigurationPUBLIC "-//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接口的包名和位置 --><javaClientGeneratortype="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 {@Testpublic 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 mapperPUBLIC "-//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 {@Testpublic 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 {@Testpublic 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.mzph.cn/news/6079.shtml

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

相关文章

Web后端开发总结

后端web开发大致流程 和对应的核心技术 对应技术的来源 springMVC可以理解为spring框架中的web开发框架 springMVCSpringMybatis就是我们熟知的ssm框架了

golang单元测试及mock总结

文章目录 一、前言1、单测的定位2、vscode中生成单测 二、构造测试case的注意事项1、项目初始化2、构造空interface{}3、构造结构体的time.Time类型4、构造json格式的test case 三、运行单测文件1、整体运行单测文件2、运行单个单测文件报错&#xff08;1&#xff09;command-l…

基于sklearn计算precision、recall等分类指标

文章目录 一、分类指标函数1.1 precision_score函数1.2 recall_score函数1.3 accuracy_score函数1.4 f1_score函数1.5 precision_recall_curve函数1.6 roc_curve函数1.7 roc_auc_score函数1.8 classification_report函数 二、二分类任务三、多分类任务3.1 Macro Average&#x…

怎样原生制作lis的CentOS容器镜像

本文介绍从一个空白的裸机CentOS自己构造检验允许的docker环境。来达到运行环境的高度定制&#xff0c;而不是只能依赖VS或者微软或者数据库厂商提供的镜像当做基础制作。更容易理解基础原理。最终输出产物为lisnew.tar&#xff0c;一个开箱即用的lis运行环境。 制作的整个过程…

os.environ[“CUDA_VISIBLE_DEVICES“]学习总结

今天发现一个很有意思的东西 import torch import os # Specify the GPU device os.environ["CUDA_VISIBLE_DEVICES"] "1" print(torch.cuda.is_available())但是如果修改下面的设置后&#xff0c;结果就变成了 import torch import os # Specify the…

Spring MVC -- 返回数据(静态页面+非静态页面+JSON对象+请求转发与请求重定向)

目录 1. 返回静态页面 2. 返回非静态页面 2.1 ResponseBody 返回页面内容 2.2 RestController ResponseBody Controller 2.3 示例:实现简单计算的功能 3. 返回JSON对象 3.1 实现登录功能&#xff0c;返回 JSON 对象 4. 请求转发(forward)或请求重定向(redirect) 4.1 请…

Rust之泛型、特性和生命期(四):验证有生存期的引用

开发环境 Windows 10Rust 1.71.0 VS Code 1.80.1 项目工程 这里继续沿用上次工程rust-demo 验证具有生存期的引用 生存期是我们已经在使用的另一种泛型。生存期不是确保一个类型具有我们想要的行为&#xff0c;而是确保引用在我们需要时有效。 我们在第4章“引用和借用”一…

<Java物联网> 从主动到被动:Java中的BACnet设备属性查询

目录 BACnet 使用软件 资源 模拟器 使用Java主动查 引入maven 创建网络对象 获取远程设备 获取设备属性 使用DeviceEventAdapter订阅 初始化本地BACnet设备和IP网络配置&#xff1a; 启动本地设备和添加监听器&#xff1a; 搜寻远程设备&#xff1a; 发送订阅COV报…

python try/except/finally

稍微总结一下&#xff0c;否则总是忘。 x abc def fetcher(obj, index): return obj[index] fetcher(x, 4) 输出&#xff1a; File "test.py", line 6, in <module> fetcher(x, 4) File "test.py", line 4, in fetcher return obj[index] …

zookeeper的应用

Zookeeper的配置文件解析: Zookeeper内部原理: 选举机制 半数机制:在集群环境中半数以上的机器存活,这个集群可用,所以在设计Zookeeper集群系统时&#xff0c;通常会选择 奇数台服务器来搭建Zookeeper的集群 虽然在配置文件中并没有指定Master和Slave。但是&#xff0c;Zookeep…

第三十二章:MySQL事务日志

第三十二章&#xff1a;MySQL事务日志 32.1&#xff1a;概述 事物有4种特性&#xff1a;原子性、一致性、隔离性和持久性。那么事务的四种特性到底是基于什么机制实现呢&#xff1f; 事物的隔离性有锁机制实现。而事物的原子性、一致性和持久性由事物的redo日志和undo日志来…

Redis入门基础命令

文章目录 一、redis1.1 redis概述1.2 redis安装 二、string2.1 基础命令2.2 存储结构2.3 应用 三、list3.1 基础命令3.2 应用 四、hash4.1 基础命令4.2 存储结构4.3 应用 五、set5.1 基础命令5.2 存储结构5.3 应用 六、zset6.1 基础命令6.2 存储结构6.3 应用 一、redis 1.1 re…

【C#】MVC页面常见的重定向方式和场景

本篇文章主要简单讲讲&#xff0c;C# MVC 页面常见跳转或者重定向的方式和场景。 在实际项目开发中&#xff0c;在一些特定场景肯定会用到重定向&#xff0c;比如&#xff1a;不同角色跳转到不同视图地址 目录 一、种常见重定向方式1.1、RedirectToAction1.2、RedirectToRoute1…

Java中的队列

队列的理解 队列&#xff08;Queue&#xff09;是一种特殊的线性表&#xff0c;它只允许在表的前端进行删除操作&#xff0c;而在表的后端进行插入操作。 LinkedList类实现了Queue接口&#xff0c;因此我们可以把LinkedList当成Queue来用。 常用方法 实例 import java.util…

Stable Diffusion服务环境搭建(远程服务版)

Stable Diffusion服务环境搭建&#xff08;远程服务版&#xff09; Stable Diffusion是什么 Stable diffusion是一个基于Latent Diffusion Models&#xff08;潜在扩散模型&#xff0c;LDMs&#xff09;的文图生成&#xff08;text-to-image&#xff09;模型。具体来说&#…

C# IO FileStream流(一)使用整理

一、C# IO 文件流&#xff0c;常用操作整理 来自其他开发者的整理&#xff1a; 文件操作常用相关类 1)Directory //操作目录&#xff08;文件夹&#xff09;&#xff0c;静态类。2)Path//静态类&#xff0c;对文件或目录的路径进行操作&#xff08;很方便&#xff09;【字符…

[深度学习实战]基于PyTorch的深度学习实战(中)[线性回归、numpy矩阵的保存、模型的保存和导入、卷积层、池化层]

目录 一、前言二、线性回归2.1 训练代码2.2 绘图部分代码2.3 numpy 数组的保存和导入代码2.4 完整代码 三、numpy矩阵的保存四、模型的保存和导入4.1 保存模型4.2 导入模型 五、卷积层5.1 Conv2d5.1.1 函数定义5.1.2 参数说明5.1.3 测试代码5.1.4 最终结果 5.2 Conv1d5.2.1 函数…

element ui 上传控件携带参数到后端

1.携带固定参数&#xff1a; 2.携带不固定参数&#xff1a; <el-row> <el-col :span"24"> <el-upload :multiple"false" :show-file-list"false" :on-success"f_h…

ShardingSphere分库分表实战之MySQL主从集群搭建

&#x1f680; ShardingSphere &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&…

Java并发编程学习笔记(一)线程的入门与创建

一、进程与线程 认识 程序由指令和数据组成&#xff0c;简单来说&#xff0c;进程可以视为程序的一个实例 大部分程序可以同时运行多个实例进程&#xff0c;例如记事本、画图、浏览器等少部分程序只能同时运行一个实例进程&#xff0c;例如QQ音乐、网易云音乐等 一个进程可以…