栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringMVC 整合 Mybatis 和 pagehelper分页插件

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringMVC 整合 Mybatis 和 pagehelper分页插件

一、整合

Spring + SpringMVC 是已经配置好了。以下是整合 MyBatis 和 pagehelper分页插件 的部分。

1、导入依赖


    org.mybatis
    mybatis
    3.5.6



    org.mybatis
    mybatis-spring
    2.0.5






    com.github.pagehelper
    pagehelper
    4.1.1



    com.github.jsqlparser
    jsqlparser
    x.x.x

2、进行配置 2.1、配置类配置
@Configuration
@MapperScan(basePackages = {"com.exmple.xxx.mapper"})
public class MyBatisConfig {

    @Value("${xxx.datasource.url}")
    private String url;
    @Value("${xxx.datasource.username}")
    private String username;
    @Value("${xxx.datasource.password}")
    private String password;

    
    private static final String CONFIG_LOCATION = "config/xxx/mybatis-config.xml";
    
    private static final String MAPPER_LOCATION = "classpath:mapper/xxx
    @Bean(name = "mybatis_dataSource")
    public DataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return druidDataSource;
    }

   
    @Bean(name = "mybatis_sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
    	// mybatis
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        // mybatis-plus
        // MyBatisSqlSessionFactoryBean factoryBean = new MyBatisSqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource());
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factoryBean.setConfigLocation(new ClassPathResource(CONFIG_LOCATION));
        factoryBean.setMapperLocations(resolver.getResources(MAPPER_LOCATION));
        // pageHelper 分页插件配置
        // pageHelper 5.0 以后的版本使用 => new PageInterceptor()
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        // 4.0.0 以后版本可以不设置该参数 5.0 以前的版本使用
        properties.setProperty("dialect", "postgresql");
        // 5.0 后的版本使用以下
        // properties.setProperty("helperDialect", "postgresql");
        // reasonable:分页合理化参数,默认值为false。
		// 当该参数设置为 true 时,pageNum<=0 时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。
        // 默认false 时,直接根据参数进行查询。
        properties.setProperty("reasonable", "true");
        pageHelper.setProperties(properties);
        factoryBean.setPlugins(pageHelper);
		// mybatis-plus 自动填充配置
		// MetaObjectHandler 配置
		// GlobalConfig globalConfig = new GlobalConfig();
		// globalConfig.setMetaObjectHandler(new MyBatisPlusTimeMetaObjectHandler());
		// globalConfig.setBanner(false);
		// factoryBean.setGlobalConfig(globalConfig);

        return factoryBean.getObject();
    }

   
    @Bean(name = "mybatis_sqlSessionTemplate")
    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory());
    }

    
    @Bean(name = "mybatis_transactionManager")
    public DataSourceTransactionManager  transactionManager(){
        return new DataSourceTransactionManager(dataSource());
    }
}

2.2、配置拦截器插件另外两种方法

1)pageHelper 分页插件可在 Mybatis 配置文件中配置

mybatis-config.xml





	
        
        
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
            
        
  	

2) 在 Spring 配置文件中配置拦截器插件


	
	
    	
        	
                
                    
                    
                        dialect=postgresql
                        reasonable=true
                    
                
        	
    	
	

3、使用测试



    
        select * from person_info_test
    

4、自动填充类
@Component
public class MyBatisPlusTimeMetaObjectHandler implements MetaObjectHandler {
    private static final Logger LOG = LoggerFactory.getLogger(MyBatisPlusTimeMetaObjectHandler.class);
    
    @Override
    public void insertFill(MetaObject metaObject) {
        LOG.info("start insert fill....");
        Long cur = System.currentTimeMillis();

        this.strictInsertFill(metaObject, "createTime", Long.class, cur);
        this.strictInsertFill(metaObject, "updateTime", Long.class, cur);
    }

    
    @Override
    public void updateFill(MetaObject metaObject) {
        LOG.info("start update fill....");
        Long cur = System.currentTimeMillis();

        this.setFieldValByName("updateTime", cur, metaObject);
    }
}
二、PageHelper 分页插件

推荐查看文档学习:Mybatis-PageHelper-HowToUse

1、注意事项

​ 1)PageHelper.startPage方法重要提示。只有紧跟在PageHelper.startPage方法后的第一个Mybatis的 查询(Select) 方法会被分页。

​ 2)请不要在系统中配置多个分页插件(使用Spring时,mybatis-config.xml和Spring配置方式,请选择其中一种,不要同时配置多个分页插件)!

​ 3)分页插件不支持带有for update语句的分页。 对于带有for update的sql,会抛出运行时异常,对于这样的sql建议手动分页,毕竟这样的sql需要重视。

​ 4)分页插件不支持嵌套结果映射。 由于嵌套结果方式会导致结果集被折叠,因此分页查询的结果在折叠后总数会减少,所以无法保证分页结果数量正确。

2、如何在代码中使用 2.1、RowBounds方式的调用
// 第一种,RowBounds方式的调用
List list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10));

使用这种调用方式时,你可以使用RowBounds参数进行分页,这种方式侵入性最小,我们可以看到,通过RowBounds方式调用只是使用了这个参数,并没有增加其他任何内容。

分页插件检测到使用了RowBounds参数时,就会对该查询进行物理分页。

注: 不只有命名空间方式可以用RowBounds,使用接口的时候也可以增加RowBounds参数,例如:

//这种情况下也会进行物理分页查询
List selectAll(RowBounds rowBounds);

注意: 由于默认情况下的 RowBounds 无法获取查询总数,分页插件提供了一个继承自 RowBounds 的 PageRowBounds,这个对象中增加了 total 属性,执行分页查询后,可以从该属性得到查询总数。

2.2、Mapper接口方式的调用
// 第二种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.startPage(1, 10);
List list = userMapper.selectIf(1);

// 第三种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.offsetPage(1, 10);
List list = userMapper.selectIf(1);

PageHelper.startPage 静态方法调用

除了 PageHelper.startPage 方法外,还提供了类似用法的 PageHelper.offsetPage 方法。

在你需要进行分页的 MyBatis 查询方法前调用 PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个MyBatis 查询方法会被进行分页。

例一:

// 获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
// 紧跟着的第一个select方法会被分页
List list = userMapper.selectIf(1);
assertEquals(2, list.get(0).getId());
assertEquals(10, list.size());
// 分页时,实际返回的结果list类型是Page,如果想取出分页信息,需要强制转换为Page
assertEquals(182, ((Page) list).getTotal());

例二:

// request: url?pageNum=1&pageSize=10
// 支持 ServletRequest,Map,POJO 对象,需要配合 params 参数
PageHelper.startPage(request);
// *紧跟着的第一个select方法会被分页
List list = userMapper.selectIf(1);
// *后面的不会被分页,除非再次调用 PageHelper.startPage
List list2 = userMapper.selectIf(null);
// list1
assertEquals(2, list.get(0).getId());
assertEquals(10, list.size());
// 分页时,实际返回的结果list类型是Page,如果想取出分页信息,需要强制转换为Page,
// 或者使用PageInfo类(下面的例子有介绍)
assertEquals(182, ((Page) list).getTotal());
// list2
assertEquals(1, list2.get(0).getId());
assertEquals(182, list2.size());

例三,使用PageInfo的用法:

// 获取第1页,10条内容,默认查询总数count
PageHelper.startPage(1, 10);
List list = userMapper.selectAll();
// 用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
// 测试PageInfo全部属性
// PageInfo包含了非常全面的分页属性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
assertEquals(true, page.isHasNextPage());
2.3、参数方法调用
// 第四种,参数方法调用
// 存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
public interface CountryMapper {
    List selectByPageNumSize(
            @Param("user") User user,
            @Param("pageNum") int pageNum, 
            @Param("pageSize") int pageSize);
}
// 配置 supportMethodsArguments=true
// 在代码中直接调用:
List list = userMapper.selectByPageNumSize(user, 1, 10);
// 第五种,参数对象
// 如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页
// 有如下 User 对象
public class User {
    // 其他fields
    // 下面两个参数名和 params 配置的名字一致
    private Integer pageNum;
    private Integer pageSize;
}
// 存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
public interface CountryMapper {
    List selectByPageNumSize(User user);
}
// 当 user 中的 pageNum!= null && pageSize!= null 时,会自动分页
List list = userMapper.selectByPageNumSize(user);

想要使用参数方式,需要配置 supportMethodsArguments 参数为 true,同时要配置 params 参数。 例如下面的配置:


    
    
        
        
        
	

在 MyBatis 方法中:

List selectByPageNumSize(
        @Param("user") User user,
        @Param("pageNumKey") int pageNum, 
        @Param("pageSizeKey") int pageSize);

当调用这个方法时,由于同时发现了 pageNumKey 和 pageSizeKey 参数,这个方法就会被分页。params 提供的几个参数都可以这样使用。

使用 POJO 对象时:

注意: pageNum 和 pageSize 两个属性同时存在才会触发分页操作,在这个前提下,其他的分页参数才会生效。

2.4、jdk8 lambda 用法
// 第六种,ISelect 接口方式
// jdk8 lambda用法
Page page = PageHelper.startPage(1, 10).doSelectPage(() -> userMapper.selectGroupBy());

// 也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage
pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> userMapper.selectGroupBy());

// count查询,返回一个查询语句的count数
total = PageHelper.count(() -> userMapper.selectLike(user));
3、PageHelper 安全调用

1)使用 RowBounds 和 PageRowBounds 参数方式是极其安全的

2)使用参数方式是极其安全的

3)使用 ISelect 接口调用是极其安全的

​ ISelect 接口方式除了可以保证安全外,还特别实现了将查询转换为单纯的 count 查询方式,这个方法可以将任意的查询方法,变成一个 select count(*) 的查询方法。

4)什么时候会导致不安全的分页?

PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。

只要你可以保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper 在 finally 代码段中自动清除了 ThreadLocal 存储的对象。

如果代码在进入 Executor 前发生异常,就会导致线程不可用,这属于人为的 Bug(例如接口方法和 XML 中的不匹配,导致找不到 MappedStatement 时), 这种情况由于线程不可用,也不会导致 ThreadLocal 参数被错误的使用。

但是如果你写出下面这样的代码,就是不安全的用法:

PageHelper.startPage(1, 10);
List list;
if(param1 != null){
    list = userMapper.selectIf(param1);
} else {
    list = new ArrayList();
}

这种情况下由于 param1 存在 null 的情况,就会导致 PageHelper 生产了一个分页参数,但是没有被消费,这个参数就会一直保留在这个线程上。当这个线程再次被使用时,就可能导致不该分页的方法去消费这个分页参数,这就产生了莫名其妙的分页。

上面这个代码,应该写成下面这个样子:

List list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    list = userMapper.selectIf(param1);
} else {
    list = new ArrayList();
}

这种写法就能保证安全。

如果你对此不放心,你可以手动清理 ThreadLocal 存储的分页参数,可以像下面这样使用:

List list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    try{
        list = userMapper.selectAll();
    } finally {
        PageHelper.clearPage();
    }
} else {
    list = new ArrayList();
}

这么写很不好看,而且没有必要。

三、MyBatis Mapper

https://mapper.mybatis.io/

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/987805.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号