• Spring framework day 03:Spring 整合 Mybatis(分页)


    前言

    在当今快速发展的软件开发领域,Java作为一种广泛使用的编程语言,以其强大的生态系统和丰富的框架而备受推崇。而在Java开发中,Spring框架几乎成为了事实上的标准,它为开发者提供了一种优雅且高效的方式来构建企业级应用程序。

    而对于数据持久化方面,MyBatis作为一种流行的ORM(Object-Relational Mapping)框架,也成为了Java开发者的首选之一。它不仅提供了简单易用的SQL映射功能,还具备动态SQL、一级缓存、延迟加载等高级特性。

    然而,在实际项目中,我们通常需要实现分页查询以处理大量数据。而Spring和MyBatis共同配合,可以实现简单而强大的分页功能。本文将介绍如何在Spring框架中整合MyBatis,并使用MyBatis的分页插件来实现分页查询功能。

    在接下来的内容中,我们将逐步讲解如何设置环境、配置数据源和整合MyBatis。然后,我们将介绍如何使用MyBatis分页插件来实现分页查询,并提供实例演示。最后,我们将总结所学内容,并讨论一些可能遇到的常见问题和解决方案。

    通过本文的学习,您将了解到使用Spring整合MyBatis(分页)的基本步骤和技巧,以及如何在实际项目中应用它们。希望本文能够帮助您更好地理解和使用这两个优秀的框架,并加快您的开发效率。

    请继续阅读下文,我们将一步步引导您完成整合过程。

     一、使用 pagehelper 插件

    PageHelper是一个开源的MyBatis分页插件,可以轻松地在MyBatis应用中实现分页查询功能。它提供了丰富的分页参数配置项,支持多种数据库(包括MySQL、Oracle、SqlServer等)和多种分页方式(包括普通分页、滚动分页、局部分页等),同时也提供了与Spring框架和SpringBoot框架的无缝集成。使用PageHelper可以大大简化分页查询的编写,提高代码的可读性和可维护性。

    二、新建项目,结构如下

    1、导入 spring 依赖
    1. <dependencies>
    2. <dependency>
    3. <groupId>com.alibabagroupId>
    4. <artifactId>druidartifactId>
    5. <version>1.2.15version>
    6. dependency>
    7. <dependency>
    8. <groupId>org.springframeworkgroupId>
    9. <artifactId>spring-contextartifactId>
    10. <version>5.3.23version>
    11. dependency>
    12. <dependency>
    13. <groupId>org.springframeworkgroupId>
    14. <artifactId>spring-jdbcartifactId>
    15. <version>5.3.23version>
    16. dependency>
    17. <dependency>
    18. <groupId>ch.qos.logbackgroupId>
    19. <artifactId>logback-classicartifactId>
    20. <version>1.4.5version>
    21. dependency>
    22. <dependency>
    23. <groupId>mysqlgroupId>
    24. <artifactId>mysql-connector-javaartifactId>
    25. <version>8.0.33version>
    26. dependency>
    27. <dependency>
    28. <groupId>org.projectlombokgroupId>
    29. <artifactId>lombokartifactId>
    30. <version>1.18.30version>
    31. dependency>
    32. <dependency>
    33. <groupId>junitgroupId>
    34. <artifactId>junitartifactId>
    35. <version>4.13.2version>
    36. <scope>testscope>
    37. dependency>
    38. <dependency>
    39. <groupId>org.mybatisgroupId>
    40. <artifactId>mybatisartifactId>
    41. <version>3.5.6version>
    42. dependency>
    43. <dependency>
    44. <groupId>org.mybatisgroupId>
    45. <artifactId>mybatis-springartifactId>
    46. <version>2.0.6version>
    47. dependency>
    48. <dependency>
    49. <groupId>com.github.pagehelpergroupId>
    50. <artifactId>pagehelperartifactId>
    51. <version>5.3.2version>
    52. dependency>
    53. dependencies>
     3、在 dao 包下的 CityDao 接口中添加一个方法
    1. public interface CityDao {
    2. /**
    3. * 分页查询
    4. * @param pageNum
    5. * @param pageSize
    6. * @return
    7. */
    8. List page(@Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize);
    9. }
    4、在 service 包下的 CityService 接口中,添加一个方法
    1. public interface CityService {
    2. PageInfo page(Integer pageNum, Integer pageSize);
    3. }
    5、在 CityServiceImpl 实现类中添加一个方法
    1. @Service
    2. @Slf4j
    3. @RequiredArgsConstructor
    4. public class CityServiceImpl implements CityService {
    5. /**
    6. * 这里注入的是代理对象
    7. */
    8. private final CityDao cityDao;
    9. @Override
    10. public PageInfo page(Integer pageNum, Integer pageSize) {
    11. List list = cityDao.page(pageNum, pageSize);
    12. return new PageInfo<>(list);
    13. }
    14. }

     在该示例中,CityServiceImpl类的主要逻辑如下:

    1. 使用@Service注解将CityServiceImpl类标识为一个Spring的服务组件。

    2. 使用@Slf4j注解引入lombok库提供的日志功能,可以通过log对象输出日志信息。

    3. 使用@RequiredArgsConstructor注解,通过Lombok生成带有final字段的构造函数。这里用于注入CityDao的代理对象。

    4. 实现page方法,该方法接收两个参数:pageNumpageSize,用于指定当前页码和每页的数据量。

    5. page方法中调用cityDao对象的page方法进行分页查询,传入pageNumpageSize作为参数。

    6. 将查询结果列表封装为PageInfo对象,并返回。

    需要注意的是,CityDao的注入是通过构造函数注入的,而且注入的是代理对象,这是使用Spring整合MyBatis后的一种常见配置方案。

    三、xml 配置

    1、在 resources 包下新建一个 beans.xml 文件
    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mybatis="http://mybatis.org/schema/mybatis-spring"
    4. xmlns:context="http://www.springframework.org/schema/context"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    6. <context:component-scan base-package="edu.nf.ch02"/>
    7. <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    8. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    9. <property name="url" value="jdbc:mysql://localhost:3306/psm"/>
    10. <property name="username" value="root"/>
    11. <property name="password" value="123456"/>
    12. <property name="maxActive" value="200"/>
    13. <property name="initialSize" value="5"/>
    14. <property name="minIdle" value="5"/>
    15. <property name="maxWait" value="2000"/>
    16. <property name="minEvictableIdleTimeMillis" value="300000"/>
    17. <property name="timeBetweenEvictionRunsMillis" value="60000"/>
    18. <property name="testWhileIdle" value="true"/>
    19. <property name="testOnReturn" value="false"/>
    20. <property name="validationQuery" value="select 1"/>
    21. <property name="poolPreparedStatements" value="false"/>
    22. bean>
    23. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    24. <property name="dataSource" ref="dataSource"/>
    25. <property name="typeAliasesPackage" value="edu.nf.ch02"/>
    26. <property name="mapperLocations" value="classpath:mappers/*.xml"/>
    27. <property name="plugins">
    28. <bean class="com.github.pagehelper.PageInterceptor">
    29. <property name="properties">
    30. <props>
    31. <prop key="helperDialect">mysqlprop>
    32. <prop key="supportMethodsArguments">trueprop>
    33. <prop key="reasonable">trueprop>
    34. props>
    35. property>
    36. bean>
    37. property>
    38. bean>
    39. <mybatis:scan base-package="edu.nf.ch02.dao"/>
    40. beans>

    这是完整的 xml 配置,数据源、分页都在这里面交给容器管理。

    以上是一个整合MyBatis和Spring的配置示例。主要包括以下几个关键点:

    1. 配置SqlSessionFactoryBean:通过该配置将MyBatis和Spring进行整合。需要注入DataSource,并设置其他属性值,比如实体类的包、mapper映射文件的路径等。

    2. 设置分页插件:在SqlSessionFactoryBean中配置分页插件。使用PageInterceptor作为分页拦截器,并注入相关属性值。可以设置数据库方言(如mysql)、启用分页参数注解支持和分页合理化等。

    3. 配置扫描dao接口包:通过mybatis:scan配置,指定扫描dao接口所在的包路径。这样会利用动态代理在运行时创建所有dao接口的实现类,并自动注册到Spring容器中。

    通过以上配置,就可以完成MyBatis和Spring的整合,并且使用PageHelper插件实现方便的分页查询功能。

    我们再来详细的分析每一个属性是干嘛的吧!

    1. dataSource:指定SqlSessionFactory所需的数据源。

    2. typeAliasesPackage:指定实体类(对应数据库表的映射类)的包路径,用于创建别名。

    3. mapperLocations:指定mapper XML文件所在的路径(可以是文件系统路径或者classpath路径)。

    4. plugins:设置MyBatis插件。可以配置多个插件,例如分页插件等。在该示例中,使用的是PageHelper分页插件。

    5. PageInterceptor:PageHelper分页插件提供了一个名为PageInterceptor的分页拦截器。该拦截器会在执行SQL语句前,自动将分页参数封装为Page对象,并且在SQL语句后自动进行分页处理。

    6. helperDialect:指定数据库方言(如mysql、oracle等),PageHelper根据不同的数据库方言自动选择相应的分页方法。

    7. supportMethodsArguments:启用分页参数注解支持。在service层的方法(dao接口对应的方法)上添加@Param注解,并使用PageHelper.startPage(pageNum, pageSize)方法即可完成分页功能。

    8. reasonable:分页合理化。如果该属性设置为true,则会在查询总记录数时,先判断当前查询是否是一个简单的查询(没有含有排序、聚合、子查询等特殊操作),如果是,则不进行count查询总记录数,直接返回limit查询结果。这样可以避免多余的count查询操作,提升性能。

    9. base-package:指定dao接口所在的包路径,用于自动扫描并注册dao接口。

     完整的 xml 配置已经完成了,现在我们来测试一下吧!

    2、测试
    1. @Slf4j
    2. public class Main {
    3. public static void main(String[] args) {
    4. ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    5. // 从容器中获取动态创建的 CityDao 的代理对象
    6. CityService cityDao = context.getBean(CityService.class);
    7. PageInfo list = cityDao.page(1,10);
    8. list.getList().forEach(page -> log.info(page.getCityName()));
    9. }
    10. }

    page(1,10):大家是不是很疑惑,我们调用的这个方法并不是 CityService 的方法,而是 CityDao 接口的实现类的方法,那这个实现类是怎么来的呢?我们并没有实现呀,这个实现类是动态代理帮我们动态生成的,不用我们自己实现,这就是使用框架的好处,帮我们节省了很多的重复操作。

    运行结果

    四、使用 Java 配置类配置(推荐)

    1、在 resources 包下新建一个 db.properties 文件
    1. driver = com.mysql.cj.jdbc.Driver
    2. url = jdbc:mysql://localhost:3306/psm
    3. username= root
    4. password = 123456
    5. maxActive = 200
    6. initialSize = 5
    7. minIdle = 5
    8. maxWait = 2000
    9. minEvictableIdleTimeMillis = 300000
    10. timeBetweenEvictionRunsMillis = 60000
    11. testWhileIdle = true
    12. testOnReturn = false
    13. validationQuery = select 1
    14. poolPreparedStatements = false
    2、在 config 包下新建一个 AppConfig 类
    1. @Configuration
    2. // 扫描 dao 接口的包,动态生成 dao 接口的代理实现
    3. // 等效于 xml 中的
    4. @MapperScan(basePackages = "edu.nf.ch02.dao")
    5. @ComponentScan(basePackages = "edu.nf.ch02")
    6. public class AppConfig {
    7. /**
    8. * 装配 dataSource 数据源
    9. *
    10. * @return
    11. * @throws Exception
    12. */
    13. @Bean(initMethod = "init", destroyMethod = "close")
    14. public DruidDataSource dateSource() throws Exception {
    15. // 创建 Properties 对象
    16. Properties prop = new Properties();
    17. // 获取一个输入流来读取 properties 文件
    18. InputStream input = AppConfig.class.getClassLoader().getResourceAsStream("db.properties");
    19. // 将输入流加载到 properties 对象中
    20. prop.load(input);
    21. // 通过 DruidDataSourceFactory 来创建 DruidDataSource 实例
    22. DruidDataSource ds = (DruidDataSource) DruidDataSourceFactory.createDataSource(prop);
    23. return ds;
    24. }
    25. /**
    26. * 整合 mybatis ,装配 SqlSessionFactory
    27. *
    28. * @return
    29. */
    30. @Bean
    31. public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) throws Exception {
    32. // 创建 SqlSessionFactoryBean
    33. SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
    34. // 注入数据源
    35. sqlSessionFactoryBean.setDataSource(dataSource);
    36. // 注入 mybatis 其他属性
    37. // 设置包的别名
    38. sqlSessionFactoryBean.setTypeAliasesPackage("edu.nf.ch02.entity");
    39. // mapper 映射配置文件的路径
    40. // 先创建一个资源路径解析器来查找源文件
    41. PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    42. Resource[] resources = resolver.getResources("classpath:mappers/*.xml");
    43. sqlSessionFactoryBean.setMapperLocations(resources);
    44. // 设置分页插件
    45. PageInterceptor interceptor = new PageInterceptor();
    46. // 设置属性
    47. Properties properties = new Properties();
    48. properties.setProperty("helperDialect","mysql");
    49. properties.setProperty("supportMethodsArguments","true");
    50. properties.setProperty("reasonable","true");
    51. // 将分页属性设置到分页拦截器中
    52. interceptor.setProperties(properties);
    53. // 最后将分页拦截器设置到 SqlSessionFactoryBean 插件中
    54. sqlSessionFactoryBean.setPlugins(interceptor);
    55. // 返回 SqlSessionFactoryBean 给容器
    56. return sqlSessionFactoryBean;
    57. }
    58. }

     我们来注重讲解一些分页的属性:

    在这段代码中,首先创建了一个PageInterceptor对象,作为PageHelper分页插件的拦截器。然后,通过Properties对象设置了一些属性:

    1. helperDialect:指定数据库方言,这里设置为mysql

    2. supportMethodsArguments:启用分页参数注解支持,设置为true

    3. reasonable:分页合理化,设置为true

    接下来,将这些分页属性设置到PageInterceptor对象中,使用interceptor.setProperties(properties)语句。

    最后,通过sqlSessionFactoryBean.setPlugins(interceptor)将分页拦截器设置到SqlSessionFactoryBean中,以便在MyBatis的执行过程中应用分页插件。

    通过这样的配置,就可以实现在MyBatis中使用PageHelper进行分页查询了。

     3、测试
    1. @Slf4j
    2. public class Main {
    3. public static void main(String[] args) {
    4. ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    5. // 从容器中获取动态创建的 CityDao 的代理对象
    6. CityService cityDao = context.getBean(CityService.class);
    7. PageInfo list = cityDao.page(1,10);
    8. list.getList().forEach(page -> log.info(page.getCityName()));
    9. }
    10. }

    运行结果

    五、xml 配置和 Java配置类,配置分页属性的区别 

    在配置分页属性时,可以使用两种方式:XML配置和Java配置类。下面是它们之间的区别:

    1. XML配置:

      • 在XML配置文件中,可以通过元素来配置分页插件以及其属性。
      • 使用XML配置时,需要手动编写XML配置文件,并指定插件的相关属性。
      • 配置文件中的内容相对独立,可单独管理和维护。
    2. Java配置类:

      • 在Java配置类中,可以通过实例化分页插件对象并设置属性来配置分页插件。
      • 使用Java配置类时,可以直接在代码中进行配置和设置,无需单独的配置文件。
      • 配置类可以与其他配置类一起进行管理,方便集中管理和维护。

    总体来说,XML配置适合于对配置文件进行统一管理的项目,而Java配置类适合于将配置与代码结合在一起的项目。选择使用哪种方式主要取决于项目的需求和个人偏好。无论选择哪种方式,配置的具体内容都是相同的,只是配置方式不同。

    大家在开发中,根据自己的需求选择即可。

    六、gitee 案例

    完整代码地址:ch02 · qiuqiu/conformity-study - 码云 - 开源中国 (gitee.com)

  • 相关阅读:
    Quill编辑器实现原理初探
    Android 音频可视化
    vector容器模拟实现及使用——c++
    java基于springboot+vue的校园闲置二手物品交易系统 跳蚤市场 element
    Spring Cloud Gateway 实现原理
    分布式.BASE理论
    现状分析:“一云多芯”如何推动信创项目快速部署
    SpringBoot终极讲义第一章笔记
    【考研复习】union有关的输出问题
    deb包格式实例详解
  • 原文地址:https://blog.csdn.net/zhiqiuqiu2/article/details/133947936