mysql同时使用order by排序和limit分页数据重复问题

目录

场景再现:

解决方案:

问题分析:

 mysql官方描述:


场景再现:

最近排查数据时发现使用order by及limit分页时会出现不同页数数据重复问题及有的数据分页不会显示,但是按条件搜索就可以搜索出来。

 解决方案:

排序中使用唯一值(例如主键id),保证每条数据不重复;

问题分析:

 mysql官方描述:

        如果多行在列中具有相同的值ORDER BY,服务器可以自由地以任何顺序返回这些行,并且可能会根据整体执行计划以不同的方式返回。换句话说,这些行的排序顺序相对于未排序的列是不确定的。
        影响执行计划的一个因素是 LIMIT,因此ORDER BY 有和没有的查询LIMIT可能会以不同的顺序返回行。

        也就是说如果我们order by 的字段值是一样的,那么每一次查询的数据返回可能的顺序是不同的。如果同limit一起使用,就可能出现分页数据重复的问题。

 官方文档: MySQL :: MySQL 5.7 Reference Manual :: 8.2.1.17 LIMIT Query Optimization

由此可知,在同时使用order by及limit时尽量确保ORDER BY子句中包含其他列以使顺序具有​​确定性;

若按照时间排序,建议库中时间值精确到毫秒级别;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 MyBatis 框架从不同 MySQL 数据源查询数据并整合同时完成排序分页操作可以分为以下几个步骤: 1. 配置数据源 在 MyBatis 的配置文件中配置多个数据源,分别对应不同的 MySQL 数据库。可以使用 c3p0、DBCP2、HikariCP 等连接池实现数据源的配置。 2. 配置 SQL 语句 在 MyBatis 的映射文件中配置 SQL 语句,分别对应不同的数据源。可以使用 `<select>` 标签实现查询操作,使用 `<if>` 标签实现条件查询,使用 `<where>` 标签实现动态拼接 SQL 语句。可以使用 `<include>` 标签将 SQL 片段抽离出来,方便复用。 同时,在 SQL 语句中可以使用 `ORDER BY` 子句实现排序操作,使用 `LIMIT` 和 `OFFSET` 子句实现分页操作。可以使用 `#{}` 占位符将参数传递给 SQL 语句。 3. 配置 Mapper 接口 在 Mapper 接口中定义查询方法,分别对应不同的 SQL 语句。可以使用 `@Select` 注解指定 SQL 语句,在方法的参数列表中使用 `@Param` 注解指定参数名,方便传递参数。 4. 使用 SqlSessionFactoryBuilder 创建 SqlSessionFactory 使用 SqlSessionFactoryBuilder 类创建 SqlSessionFactory,将 MyBatis 的配置文件和数据源传入。可以使用 SqlSessionFactory 的 openSession 方法创建 SqlSession。 5. 使用 Mapper 接口查询数据 通过 SqlSession 的 getMapper 方法获取 Mapper 接口的实例,然后调用 Mapper 接口的查询方法即可查询数据。可以使用 PageHelper 插件实现分页操作,将查询结果封装到 PageInfo 对象中。 以下是一个示例代码,演示如何从不同 MySQL 数据源查询数据并整合同时完成排序分页操作: 1. 配置数据源 ``` <bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db1" /> <property name="user" value="root" /> <property name="password" value="root" /> </bean> <bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.cj.jdbc.Driver" /> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db2" /> <property name="user" value="root" /> <property name="password" value="root" /> </bean> ``` 2. 配置 SQL 语句 ``` <!-- 在映射文件中配置 SQL 语句 --> <mapper namespace="com.example.mapper.UserMapper1"> <select id="findUsers" resultType="com.example.model.User"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name like #{name} </if> </where> ORDER BY ${sort} ${order} LIMIT #{start}, #{pageSize} </select> </mapper> <mapper namespace="com.example.mapper.UserMapper2"> <select id="findUsers" resultType="com.example.model.User"> SELECT * FROM user <where> <if test="name != null and name != ''"> AND name like #{name} </if> </where> ORDER BY ${sort} ${order} LIMIT #{start}, #{pageSize} </select> </mapper> ``` 3. 配置 Mapper 接口 ``` // 定义 Mapper 接口 public interface UserMapper1 { @Select("com.example.mapper.UserMapper1.findUsers") List<User> findUsers(@Param("name") String name, @Param("sort") String sort, @Param("order") String order, @Param("start") int start, @Param("pageSize") int pageSize); } public interface UserMapper2 { @Select("com.example.mapper.UserMapper2.findUsers") List<User> findUsers(@Param("name") String name, @Param("sort") String sort, @Param("order") String order, @Param("start") int start, @Param("pageSize") int pageSize); } ``` 4. 使用 SqlSessionFactoryBuilder 创建 SqlSessionFactory ``` // 创建 SqlSessionFactory DataSource dataSource1 = (DataSource) context.getBean("dataSource1"); DataSource dataSource2 = (DataSource) context.getBean("dataSource2"); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory sessionFactory1 = builder.build(dataSource1, "mybatis-config.xml"); SqlSessionFactory sessionFactory2 = builder.build(dataSource2, "mybatis-config.xml"); // 创建 SqlSession SqlSession sqlSession1 = sessionFactory1.openSession(); SqlSession sqlSession2 = sessionFactory2.openSession(); // 获取 Mapper 实例 UserMapper1 userMapper1 = sqlSession1.getMapper(UserMapper1.class); UserMapper2 userMapper2 = sqlSession2.getMapper(UserMapper2.class); // 设置分页参数 int pageNum = 1; int pageSize = 10; String sort = "age"; String order = "desc"; int start = (pageNum - 1) * pageSize; // 使用 PageHelper 插件查询数据 PageHelper.startPage(pageNum, pageSize); List<User> users1 = userMapper1.findUsers("Tom", sort, order, start, pageSize); PageInfo<User> pageInfo1 = new PageInfo<>(users1); PageHelper.startPage(pageNum, pageSize); List<User> users2 = userMapper2.findUsers("Tom", sort, order, start, pageSize); PageInfo<User> pageInfo2 = new PageInfo<>(users2); // 整合数据 List<User> allUsers = new ArrayList<>(); allUsers.addAll(users1); allUsers.addAll(users2); ``` 在以上示例代码中,我们先在 MyBatis 的配置文件中配置了两个数据源,分别对应不同的 MySQL 数据库。然后在映射文件中配置了 SQL 语句,分别对应不同的数据源,并使用 `ORDER BY` 子句实现排序操作,使用 `LIMIT` 和 `OFFSET` 子句实现分页操作。 接着定义了两个 Mapper 接口,分别对应不同的 SQL 语句。在接口方法的参数列表中使用 `@Param` 注解指定参数名,方便传递参数。 在使用 SqlSessionFactoryBuilder 创建 SqlSessionFactory 时,将 MyBatis 的配置文件和数据源传入。然后使用 SqlSessionFactory 的 openSession 方法创建 SqlSession,获取 Mapper 接口的实例,即可使用 Mapper 接口查询数据使用 PageHelper 插件实现分页操作,将查询结果封装到 PageInfo 对象中。最后将不同数据源查询的数据整合起来,存储到 allUsers 集合中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值