前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >mybatis深入学习

mybatis深入学习

作者头像
爱撒谎的男孩
发布2019-12-31 16:33:42
1.1K0
发布2019-12-31 16:33:42
举报
文章被收录于专栏:码猿技术专栏

文章目录

1. 环境搭建

2. typeAliases(别名)

2.1. 内建的别名【推荐使用】

3. 参数处理

3.1. 单个参数

4. 多个参数

4.1. 参数是Map类型

4.2. POJO【推荐使用】

5. 返回结果封装

5.1. 返回POJO

5.2. 返回List

5.3. 返回Map

5.4. ResultMap

6. 分步查询

6.1. 延迟加载

7. 内置参数

8. 批量处理

8.1. Mybaits-Spring执行批量处理

9. 类型处理器(TypeHandler)

9.1. 实例

9.2. 枚举类型处理器

10. 插件

10.1. 实现一个简单的插件

10.2. 重要的方法

10.3. 多个插件的执行顺序

11. Spring整合Mybatis

11.1. 注意

11.2. 源码

12. 分页插件

12.1. 自己整合工具类

环境搭建

  • 按照官方文档搭建即可

typeAliases(别名)

  • 在使用mybatis标签的时候,需要指定类的全类名,比如resultType=xx.xxx.xx,但是我们可以为类指定别名,那么就可以直接使用别名,避免全类名冗余【不推荐使用】
  • 别名的配置有两种方式,这里我们讲解简单的配置方式,步骤如下:
    • 在mybatis的全局配置文件下指定别名的包扫描如下:
代码语言:javascript
复制
<typeAliases>
       <package name="cn.tedu.domain"/>
   </typeAliases>
代码语言:javascript
复制
 @Alias("author") public class Author {     ... } 

内建的别名【推荐使用】

  • mybatis对java中基本类型和基本的引用类型内嵌了别名,我们可以直接使用别名进行指定,这样利于开发,内建的别名如下:

别名

映射的类型

_byte

byte

_long

long

_short

short

_int

int

_integer

int

_double

double

_float

float

_boolean

boolean

string

String

byte

Byte

long

Long

short

Short

int

Integer

integer

Integer

double

Double

float

Float

boolean

Boolean

date

Date

decimal

BigDecimal

bigdecimal

BigDecimal

object

Object

map

Map

hashmap

HashMap

list

List

arraylist

ArrayList

collection

Collection

iterator

Iterator

参数处理

  • mybatis内部会将我们传入的参数封装成一个Map,key就是以param1、param2....

单个参数

  • 单个参数在sql语句中可以任意指定,比如#{a}…,或者可以使用#{param1}

多个参数

  • 使用@Param指定key,那么就可以在sql语句中直接使用这个key即可,如下:
代码语言:javascript
复制
@Select("select * from patient_info where ipt_num=#{iptNum} and status=#{status}")
   Patient selectByIptNumAndInhos(@Param("iptNum") String iptNum, @Param("status") String status);
  • 也可以直接使用mybatis中默认的key,即是param1…..
代码语言:javascript
复制
@Select("select * from patient_info where ipt_num=#{param1} and status=#{param2}")
  Patient selectByIptNumAndInhos(String iptNum,String status);

参数是Map类型

  • mybatis默认的会将参数转换为map,那么我们直接传入一个map那是再好不过了,此时的key就可以直接使用,如下:
代码语言:javascript
复制
@Select("select * from patient_info where ipt_num=#{iptNum} and status=#{status}")
 Patient selectByIptAndInhosNumMap(Map ipts);

@Test
    public void test3() throws IOException {
        SqlSessionFactory sqlSessionFactory = XmlConfigInit.getSqlSessionFactory();
        PatientMapper mapper = sqlSessionFactory.openSession().getMapper(PatientMapper.class);
        Map<String,String> map=new HashMap<>();
        map.put("iptNum","15627656");
        map.put("status","1");
        Patient patient = mapper.selectByIptAndInhosNumMap(map);
        System.out.println(patient);
    }

POJO【推荐使用】

  • 对于POJO可以直接使用成员属性的名称就可以取值,这个经常使用,不再演示

返回结果封装

  • mybatis对于返回结果如何封装有多种实现方式,可以返回List,POJO,Map等类型的数据

返回POJO

  • 对于从数据库中查询单条数据库的时候,返回一个POJO只需要sql查询的字段和POJO类中的属性相同即可自动映射,当然我们也可以开启驼峰配置
  • resultType指定返回的POJO的全类名即可,或者指定别名
  • 此处不演示

返回List

  • 同POJO,此时的resultType指定的仍然是List泛型的全类名或者别名

返回Map

  • mybatis还可以返回Map类型的数据,比如我们查询患者的信息,使用Map接收数据,key是患者的id,value就是POJO,如下:
代码语言:javascript
复制
/**
    * 使用@MapKey注解指定返回Map中的key,这里设定的是Patient中的id属性作为key
    * @return
    */
   @MapKey("id")
   @Select("select * from patient_info")
   Map<Integer,Patient> selectAllReturnMap();
  • 在返回的Map的时候需要指定POJO类的哪个字段作为Map的key,使用@MapKey这个注解指定

ResultMap

  • mybatis还支持使用ResultMap自定义结果映射,此时的select语句中需要指定resultMap为当前的定义的id
  • 经常使用,不再演示

分步查询

  • 在mybatis中collectionassociation中都是可以使用分步查询
  • 我们需要查询一个科室下的所有患者,那么实体类定义如下:
代码语言:javascript
复制
@Data
@ToString
public class Dept {
    private Integer id;
    private String name;
    private List<Patient> patients;
}

@Data
@ToString
public class Patient {
    private String userId;
    private Integer id;
    private String status;
}
  • 不采用分布查询,此时我们的resultMap应该如下:
代码语言:javascript
复制
<resultMap id="baseResultMap" type="cn.tedu.domain.Dept">
        <id column="id" property="id" />
        <result column="name" property="name"/>
        <collection property="patients" ofType="cn.tedu.domain.Patient">
            <id column="pid" property="id"/>
            <result column="userId" property="userId"/>
            <result column="pstatus" property="status"/>
        </collection>
    </resultMap>

//sql

 SELECT
        d.id AS id,
        d.NAME AS NAME,
        p.id AS pid,
        p.user_id AS userId,
        p.STATUS AS pstatus
    FROM
        dept_info d
        LEFT JOIN patient_info p ON p.dept_id = d.id
    WHERE
        d.id =#{id,jdbcType=INTEGER}
  • 但是我们也可以采用分布查询的方式,先查询出科室的信息,再根据科室的id查询出对应患者的信息,实现步骤如下:
    • 定义一个方法查找科室,此时的resultMap指定的是分步查询的id
代码语言:javascript
复制
<select id="selectById" resultMap="ByStepResultMap">
           SELECT
       *
   FROM
       dept_info
   WHERE
       id =#{id,jdbcType=INTEGER}
   </select>
  • 定义一个方法根据科室id查询患者信息
代码语言:javascript
复制
@Select("SELECT * from patient_info where dept_id=#{deptId}")
    List<Patient> selectByDeptId(Integer deptId);
  • 在resultMap中指定分步查询
代码语言:javascript
复制
<!--分步查询科室信息和患者信息-->
   <resultMap id="ByStepResultMap" type="cn.tedu.domain.Dept">
       <id column="id" property="id" />
       <result column="name" property="name"/>
  
       <!--ofType:指定级联属性的类型-->
       <!--select:指定分步查询患者信息的方法,全类名+方法名-->
       <!--column:指定查询科室获取的结果的哪一个字段作为查询患者方法的参数,可以指定多个
                   如果指定多个,那么需要将参数封装成map,比如column="{key1=column1,key2=column2}"
       -->
        <!--fetchType:在开启全局延迟加载的时候设置是否延迟加载,默认是延迟加载,可以设置为eager表示不延迟加载-->
       <collection property="patients" ofType="cn.tedu.domain.Patient"
                   select="cn.tedu.mapper.PatientMapper.selectByDeptId"
                   column="id">
       </collection>
   </resultMap>

延迟加载

  • mybatis默认是不使用延迟加载的,因此当使用分步查询的时候即使没有用到分步查询的结果仍然会发出sql语句
  • 我们可以在全局配置文件中设置开启延迟加载,如下:
代码语言:javascript
复制
<settings>
        <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。-->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!--当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载(参考 lazyLoadTriggerMethods)。-->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

内置参数

  • mybatis中内置了两个参数,在写sql的时候可以直接拿来使用,如下:
    • _parameter:代表整个参数,如果是一个参数就表示这个参数,如果是多个参数,此时的参数会被封装成一个Map,那么_parameter此时就代表整个Map
    • _databaseId:如果配置了databaseIdProvider标签,就代表当前数据库的别名
  • 实例:
代码语言:javascript
复制
@Select("SELECT * from patient_info where dept_id=#{_parameter}")
   List<Patient> selectByDeptId(Integer deptId);
  • 如果是一个参数,并且是POJO对象,我们还可以使用_parameter判断是否为空,如下:
代码语言:javascript
复制
<if test="_parameter!=null">
	.....
</if>
  • 如果是多个参数,那么就表示一个Map,此时可以直接使用_parameter.key1....直接获取值即可,当然如果没有指定@Param注解,此时还可以使用_parameter.param1,_parameter.param2...直接获取对应的值

批量处理

  • Mybatis针对批量操作有两种常用的方法,第一种就死通过动态sql在sql语句中使用for-each拼写,第二种就是使用Mybaits自带的批量执行器(BatchExecutor),这里主要介绍第二种的方式
  • 如何配置?有如下两种方式
    • 在全局配置文件的settings中配置一个属性defaultExecutorType =BATCH即可,不过这种方式将会导致所有的sql操作都会使用批量操作。
    • 我们可以在获取SqlSession的时候指定执行类型,如下:
      • SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);,此时当前的SqlSession执行的就是批量操作。

Mybaits-Spring执行批量处理

  • Spring执行批量处理很简单,只需要在ioc容器中注入一个SqlSessionTemplate,并且设置批量处理的属性即可,如下:
    • 这种改变是全局的,慎用
代码语言:javascript
复制
/**
     * 注入SqlSessionTemplate,替代SqlSessionFactory直接创建SqlSession,并且能够使用Spring的事务管理
     * 如果需要使用批量处理,在构造方法中指定ExecutorType.BATCH即可,那么全部的操作的都会使用
     * 【可以不配置,需要的时候使用】
     */
    @Bean
    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory().getObject(),ExecutorType.BATCH);
        return sqlSessionTemplate;
    }

类型处理器(TypeHandler)

  • 用于处理Java类型和JDBC类型之前的映射关系,mybaits中内置了许多的类型处理器,一般我们在使用#{}中的jdbcType属性的时候,mybaits框架会为我们设置相应的处理器,比如jdbcType=DATE,那么mybatis默认对应的处理器就是DateOnlyTypeHandler(只有年月日),如果我们设置了jdbcType=TIMESTAMP,那么mybatis对Date类型的类型处理器就是DateTypeHandler,关于类型处理器和jdbcType的对应关系,看官方文档中typeHandler这一节
  • 内置处理器执行的时间:
    • 在StatementHandler创建Statement之后,会调用ParameterHandler设置参数,其中执行了类型处理器的setParametes的方法,设置对应的参数
    • 在DefaultResultsetHandler处理执行结果的时候,会调用的TypeHandler中的getResult方法获取结果集
  • TypeHandler中的方法如下:
代码语言:javascript
复制
public interface TypeHandler<T> {

  /**
   * 为预编译语句设置参数的时候执行,实际就是调用setxxx方法设置参数
   * @param ps PreparedStatement 对象
   * @param i
   * @param parameter 参数
   * @param jdbcType #{}中自定义的jdbcType
   * @throws SQLException
   */
  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  /**
   * 根据列名获取指定的值
   * @param rs ResultSet结果集
   * @param columnName 列名
   * @return
   * @throws SQLException
   */
  T getResult(ResultSet rs, String columnName) throws SQLException;

  /**
   * 根据下标获取指定列的值
   * @param rs ResultSet结果集
   * @param columnIndex  下标
   * @return
   * @throws SQLException
   */
  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  /**
   * 调用存储过程的获取返回值的时候
   * @param cs
   * @param columnIndex
   * @return
   * @throws SQLException
   */
  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}
  • 虽然mybatis中内置了许多的类型处理器,但是我们也可以自定义类型处理器,并且作用到指定需要处理的类型中,自定义的方式有两种,如下:
    • 实现TypeHandler接口
    • 继承BaseTypeHandler【推荐】

实例

  • 实例:我们需要将一个List<Auth>对象存入数据库的时候是以json字符串的形式,获取的是以List集合的形式,此时我们可以自定义一个TypeHandler,如下:
代码语言:javascript
复制
/**
 * 自定义类型转换器,将List<Auth>数据存入数据库的时候是以json字符串存入的,获取返回的结果的时候是List集合
 * @MappedJdbcTypes(value = {JdbcType.VARCHAR}):指定了映射的jdbcType的类型是VARCHAR
 * @MappedTypes(value = {Auth.class}):指定了映射的java类型是Auth
 */
@MappedJdbcTypes(value = {JdbcType.VARCHAR})
@MappedTypes(value = {Auth.class})
public class AuthTypeHandler extends BaseTypeHandler {
    /**
     * 将参数转换为json数据存入数据库
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Object parameter, JdbcType jdbcType) throws SQLException {
        String json = new Gson().toJson(parameter);
        ps.setString(i,json);
    }

    @Override
    public Object getNullableResult(ResultSet rs, String columnName) throws SQLException {
        String string = rs.getString(columnName);
        return new Gson().fromJson(string,new TypeToken<List<Auth>>(){}.getType());
    }

    @Override
    public Object getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        String string = rs.getString(columnIndex);
        return new Gson().fromJson(string,new TypeToken<List<Auth>>(){}.getType());
    }

    @Override
    public Object getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return null;
    }
}
  • 需要在全局配置文件中设置TypeHandler的包扫描,如下:
代码语言:javascript
复制
<!--设置自动扫描包下的typeHandler-->
    <typeHandlers>
        <package name="cn.tedu.typehandler"/>
    </typeHandlers>
  • 此时的类型处理器还是不起作用的,需要在insert、update的#{}中设置一下typehandler属性,如下:
    • #{}中有一个typeHandler属性,指定自定义的TypeHandler即可
代码语言:javascript
复制
<insert id="insertAdmin" parameterType="cn.tedu.domain.Admin">
        insert into t_admin(name,birthday,account,password,point,status,auths)
         values (#{name,jdbcType=VARCHAR},#{birthday,jdbcType=DATE},
         #{account,jdbcType=VARCHAR},#{password,jdbcType=VARCHAR},
         #{point,jdbcType=DOUBLE},#{status,jdbcType=VARCHAR},#{auths,jdbcType=VARCHAR,typeHandler=cn.tedu.typehandler.AuthTypeHandler})
    </insert>
  • 对select语句设置类型处理器,只能在resultMap中设置,如下:
    • 在result中需要设置javaType,jdbcType,typeHandler三个属性,这里的auths就是需要映射的List<AUth>
代码语言:javascript
复制
<resultMap id="BaseResultMap" type="cn.tedu.domain.Admin">
       <id column="id" property="id"/>
       <result column="name" property="name" />
       <result column="auths" property="auths" javaType="cn.tedu.domain.Auth" jdbcType="VARCHAR" typeHandler="cn.tedu.typehandler.AuthTypeHandler"></result>

   </resultMap>

枚举类型处理器

  • 枚举的类型处理器默认是EnumTypeHandler,存入和取出都是存储的枚举的名称,也有一个EnumOrdinalTypeHandler是按照枚举的索引存储和查询的。
  • 我们也可以自定义类型处理器来处理枚举类型。

插件

  • 插件的设计其实就是一个拦截器,在目标方法执行之前进行拦截,当然这里只是针对Mybatis中的四大对象进行拦截,四大对象如下:
    • Executor
    • StatementHandler
    • ParameterHandler
    • ResultSetHandler
  • Interceptor能够做到对四大对象中的每一个方法进行拦截
  • 实现一个插件很简单,只需要实现org.apache.ibatis.plugin.Interceptor接口即可
  • 对应Interceptor这个接口的方法解释如下:
代码语言:javascript
复制
public interface Interceptor {

  /**
   * 拦截器真正执行的方法,其中的invocation.proceed()是用来执行目标方法的,只有执行了这个proceed方法,目标方法才会执行,否则不执行
   * @param invocation
   * @return 返回目标方法执行的结果,return invocation.proceed();
   * @throws Throwable
   */
  Object intercept(Invocation invocation) throws Throwable;

  /**
   * 四大对象生成代理对象的方法,在四大对象创建的时候,都会调用一个pluginAll方法返回一个代理对象
   * 这个方法不需要做修改,默认就行了
   * @param target 目标对象
   * @return 返回的代理对象(层层包装,表示只有一层)
   */
  default Object plugin(Object target) {
    return Plugin.wrap(target, this);
  }

  /**
   * 在全局配置文件中<plugin>标签中设置properties属性,会封装在此方法的properties中
   * @param properties
   */
  default void setProperties(Properties properties) {
    // NOP
  }

}

实现一个简单的插件

  • 自定义一个插件,修改指定查询语句的入参。如下:
    • 实现原理其实很简单,因为mybaits的增删改查标签所有的信息都封装在MappedStatement中,我们只需要获取这个对象,然后通过属性判断即可。
代码语言:javascript
复制
/**
 * @Intercepts注解标记这是一个拦截器,其中可以指定多个@Signature
 * @Signature:指定该拦截器拦截的是四大对象中的哪个方法
 *      type:拦截器的四大对象的类型
 *      method:拦截器的方法,方法名
 *      args:入参的类型
 */
@Intercepts(
        {
                @Signature(type = ParameterHandler.class,method ="setParameters",args = {PreparedStatement.class})
        }
)
public class FirstPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("拦截器执行:"+invocation.getTarget());
        //目标对象
        Object target = invocation.getTarget();
        //获取目标对象中所有属性的值,因为ParameterHandler使用的是DefaultParameterHandler,因此里面的所有的属性都封装在其中
        MetaObject metaObject = SystemMetaObject.forObject(target);
        //使用xxx.xxx.xx的方式可以层层获取属性值,这里获取的是mappedStatement中的id值
        String value = (String) metaObject.getValue("mappedStatement.id");
        //如果是指定的查询方法
        if ("cn.tedu.mapper.AdminMapper.selectById".equals(value)){
            //设置参数的值是2,即是设置id=2,因为这里只有一个参数,可以这么设置,如果有多个需要需要循环
            metaObject.setValue("parameterObject", 2);
        }
        //执行目标方法
        return invocation.proceed();
    }

    //可以省略
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
    
    //可以省略
    @Override
    public void setProperties(Properties properties) {
        System.out.println(properties);
    }
}
  • 全局文件中配置:
代码语言:javascript
复制
<!--配置插件,其中的property可以设置自己的属性,可以封装到setProperties中的properties中-->
   <plugins>
       <plugin interceptor="cn.tedu.plugin.FirstPlugin">
           <property name="id" value="11"></property>
       </plugin>
   </plugins>

重要的方法

  • SystemMetaObject.forObject(target):可以获取目标类中所有的属性的值
  • metaObject.getValue("mappedStatement.id"):可以使用xxx.xxx层层的获取属性的值
  • metaObject.setValue(name, value):设置属性的值

多个插件的执行顺序

  • 全局配置文件中配置插件的顺序,决定插件的执行顺序,是相反的顺序。
  • 如果有多个插件作用在同一个对象的同一个方法上,那么插件的执行顺序是怎样的?我们知道四大对象在创建的时候会调用拦截器中的plugin方法创建代理对象,这种代理实层层包装的,那么在后面的插件创建的代理是包裹在最外层的,因此肯定是先执行最外层的拦截器方法。

Spring整合Mybatis

代码语言:javascript
复制
<dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.2</version>
 </dependency>
  • 配置数据源、事务管理器、SqlSessionFactoryBean
    • 这里使用了@MapperScan注解自动扫描Mapper接口
    • SqlSessionFactoryBean中的配置中设置xml文件的位置和全局配置文件中的位置
    • SqlSessionTemplate的注入能够让我们很方便的获取一个SqlSession和Mapper,一旦注入之后,所有的获取Mapper的代理对象都会执行其中的getMapper方法获取,因此如果这里设置了批量处理,那么改变是全局的。
代码语言:javascript
复制
/**
 * 配置类
 * @MapperScan:扫描所有的Mapper接口
 */
@Configuration
@ComponentScan(basePackages = {"cn.tedu.ssm"})
@MapperScan(basePackages = {"cn.tedu.ssm.mapper"})
@EnableAspectJAutoProxy
@EnableAsync
@EnableTransactionManagement
public class MainConfig {
    /**
     * 注册数据源
     */
    @Bean
    public DruidDataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(DataConfig.URL);
        dataSource.setUsername(DataConfig.USER);
        dataSource.setPassword(DataConfig.PWD);
        dataSource.setDriverClassName(DataConfig.DRIVER_NAME);
        return dataSource;
    }


    /**
     * 配置SqlSessionFactoryBean,实际就是SqlSessionFactory
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory() throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        //设置数据源
        sqlSessionFactoryBean.setDataSource(dataSource());
        //配置扫描mapepr.xml文件
        PathMatchingResourcePatternResolver classPathResource = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(classPathResource.getResources("classpath:mappers/*.xml"));
        //设置全局配置文件的位置
        sqlSessionFactoryBean.setConfigLocation(classPathResource.getResource("classpath:mybatis-config.xml"));
        return sqlSessionFactoryBean;
    }


    /**
     * 注入SqlSessionTemplate,替代SqlSessionFactory直接创建SqlSession,并且能够使用Spring的事务管理
     * 如果需要使用批量处理,在构造方法中指定ExecutorType.BATCH即可,那么全部的操作的都会使用
     * 【可以不配置,需要的时候使用】
     */
    @Bean
    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
        SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory().getObject());
        return sqlSessionTemplate;
    }

    /**
     * 创建事务管理器
     * @return
     */
    @Bean
    public PlatformTransactionManager transactionManager(){
        return new DataSourceTransactionManager(dataSource());
    }
}

注意

  • 在和Spring整合的时候,原先全局配置中配置的数据源,事务管理器等都会被忽略,默认会加载Spring配置的事务管理器和数据源。
  • 如果想要配置TypeHandler、Plugin、TypeAlias等设置,在SqlSessionFactoryBean中都是可以直接配置的,因此在和Spring整合之后,Mybaits的全局配置文件中需要配置的东西很少,几乎可以不用。

源码

分页插件

代码语言:javascript
复制
<dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.6</version>
 </dependency>
  • 配置拦截器,在和Spring整合下就只需要在SqlSessionFactoryBean中配置拦截器即可,如下:
代码语言:javascript
复制
/**
     * 配置SqlSessionFactoryBean,实际就是SqlSessionFactory
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory() throws IOException {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        //设置数据源
        sqlSessionFactoryBean.setDataSource(dataSource());
        //配置扫描mapepr.xml文件
        PathMatchingResourcePatternResolver classPathResource = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(classPathResource.getResources("classpath:mappers/*.xml"));
        //设置全局配置文件的位置
        sqlSessionFactoryBean.setConfigLocation(classPathResource.getResource("classpath:mybatis-config.xml"));
        //配置插件
        PageInterceptor pageInterceptor = new PageInterceptor();
        //可以配置PageHelper中的参数映射关系,这里使用默认的,不需配置
//        pageInterceptor.setProperties();
        sqlSessionFactoryBean.setPlugins(pageInterceptor);
        return sqlSessionFactoryBean;
    }
  • 官方文档中有多种使用方式,我们使用面向接口的方式,如下:
    • 只需要在doSelect中调用查询全部的sql即可
代码语言:javascript
复制
@Test
   public void test3(){
       SqlSessionTemplate sqlSessionTemplate = applicationContext.getBean(SqlSessionTemplate.class);
       final PatientMapper mapper = sqlSessionTemplate.getMapper(PatientMapper.class);
       PageInfo<Object> pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() {
           @Override
           public void doSelect() {
               mapper.selectAllPatient();
           }
       });
   }

自己整合工具类

  • 在实际使用过程中上述的方式有点繁琐,本人自己整合一个工具类,能够很轻松的完成分页。
  • 定义一个ParamReq类,如果有需要的分页的请求都继承这个类,如下:
代码语言:javascript
复制
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;

/**
 * 所有需要分页的请求要继承的类,其中提供了分页需要的参数
 * 默认的映射关系是:pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
 * 也可在设置拦截器的时候指定映射关系,具体看官方文档
 * https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md
 */
@Data
public class PageParam {
    /**
     * 当前第几页
     */
    private Integer pageNum=1;

    /**
     * 每页查询的数量
     */
    private Integer pageSize=10;

    /**
     * 是否进行count查询,默认是true,查询
     * 如果设置为false,那么总数total将会为-1,不进行count查询
     */
    @JsonIgnore
    private Boolean countSql=true;

    /**
     * 分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。
     */
    @JsonIgnore
    private Boolean reasonable;

    /**
     * 默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。
     */
    @JsonIgnore
    private Boolean pageSizeZero=true;
}
  • 自定义执行接口,其实就是覆盖上面的doSelect方法,实现自己的执行查询的方法,如下:
代码语言:javascript
复制
/**
 * 分页需要实现的接口,在doExecute中只需调用查询全部数据的mapper即可
 */
@FunctionalInterface
public interface ExecutePageHelper extends ISelect {

    /**
     * 实现类应该覆盖的方法
     */
    void doExecute();

    @Override
    default void doSelect() {
        doExecute();
    }
}
  • 分页工具类,如下:
代码语言:javascript
复制
/**
 * 执行分页插件的工具类
 */
public class PageHelperUtils {

    /**
     * 执行PageHelper分页的方法
     * @param req 请求对象,继承PageParam类
     * @param executePageHelper ExecutePageHelper的接口实现类
     * @param <T> 泛型,需要返回结果的类型
     * @return
     */
    public static <T>  PageInfo<T> execute(PageParam req,ExecutePageHelper executePageHelper){
        //这里直接传入req,其实其中的值是有映射关系的,在PageParam中有讲到
        return PageHelper.startPage(req).doSelectPageInfo(executePageHelper);
    }
}
  • 测试:
    • 使用lambda表示可以方便的执行分页查询
代码语言:javascript
复制
@Test
   public void test4(){
       SqlSessionTemplate sqlSessionTemplate = applicationContext.getBean(SqlSessionTemplate.class);
       PatientMapper mapper = sqlSessionTemplate.getMapper(PatientMapper.class);
       //分页的请求类,继承ParamReq
       UserReq req=new UserReq();
       PageInfo<Patient> pageInfo = PageHelperUtils.execute(req, mapper::selectAllPatient);
       System.out.println(pageInfo.getList());
   }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-08-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境搭建
  • typeAliases(别名)
    • 内建的别名【推荐使用】
    • 参数处理
      • 单个参数
      • 多个参数
        • 参数是Map类型
          • POJO【推荐使用】
          • 返回结果封装
            • 返回POJO
              • 返回List
                • 返回Map
                  • ResultMap
                  • 分步查询
                    • 延迟加载
                    • 内置参数
                    • 批量处理
                      • Mybaits-Spring执行批量处理
                      • 类型处理器(TypeHandler)
                        • 实例
                          • 枚举类型处理器
                          • 插件
                            • 实现一个简单的插件
                              • 重要的方法
                                • 多个插件的执行顺序
                                • Spring整合Mybatis
                                  • 注意
                                    • 源码
                                    • 分页插件
                                      • 自己整合工具类
                                      相关产品与服务
                                      容器服务
                                      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                      领券
                                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档