Mybatis Cursor

# 基本概念 流式查询指的是查询成功后不是返回一个集合而是返回一个迭代器,应用每次从迭代器取一条查询结果。流式查询的好处是能够降低内存使用。 如果没有流式查询,我们想要从数据库取 1000 万条记录而又没有足够的内存时,就不得不分页查询,而分页查询效率取决于表设计,如果设计的不好,就无法执行高效的分页查询。因此流式查询是一个数据库访问框架必须具备的功能。 流式查询的过程当中,数据库连接是保持打开状态的,因此要注意的是:执行一个流式查询后,数据库访问框架就不负责关闭数据库连接了,需要应用在取完数据后自己关闭。 # MyBatis 流式查询接口 MyBatis 提供了一个叫 org.apache.ibatis.cursor.Cursor 的接口类用于流式查询,这个接口继承了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知: Cursor 是可关闭的; Cursor 是可遍历的。 除此之外,Cursor 还提供了三个方法: isOpen():用于在取数据之前判断 Cursor 对象是否是打开状态。只有当打开时 Cursor 才能取数据; isConsumed():用于判断查询结果是否全部取完。 getCurrentIndex():返回已经获取了多少条数据 因为 Cursor 实现了迭代器接口,因此在实际使用当中,从 Cursor 取数据非常简单: 但构建 Cursor 的过程不简单 我们举个实际例子。下面是一个 Mapper 类: 方法 scan() 是一个非常简单的查询。通过指定 Mapper 方法的返回值为 Cursor 类型,MyBatis 就知道这个查询方法一个流式查询。 然后我们再写一个 SpringMVC Controller 方法来调用 Mapper(无关的代码已经省略): […]

位运算四则运算

一、位运算简介   我们先来熟悉下位运算的操作,大致要用到的位运算如下: 与(&)操作,该操作先将数值转换为二进制(如:a=3 => a=11),然后再进行操作。会对两个数相同的位置上进行操作,如果两个操作数长度不一致,会对值较短的数进行高位补0。(如:a =3 , b = 4, a+b = 011+100);相同位置为全1才为1,有0必为0,则上述结果:a&b = 000。 或(|)操作,跟与(&)操作不一样的地方在于,相同位置有1则1。a|b = 000。 异或(^)操作,相同则为0,不同则为1。a^b = 111。 我们将从加法开始依次分析。 二进制加法   可以很轻松的利用异或(^)操作与与(&)操作来实现加法的运算。与(&)操作可以用来获取两者相加进位,因为相同的位置同时出现1结果才为1,那么此时对结果集进行左移(<<)操作得到即为进位的值,采用异或(^)操作得到的是我们不带进位的相加结果,再利用不带进位与进位相加,依次迭代,即可以求出我们需要的值。 例如:a=010010,b=100111,计算步骤如下: 二进制减法   二进制的减法跟简单,其实就是在加法的基础上进行改进,众所周知,在计算机中一切都是在做加法,减法的由来就是一个数加上另外一个数的负数。计算机中的负数可以采用补码+1的形式得到 tip: 取反(~)得到补码: a的补码为~a。 二进制乘法   乘法有个特性就是,当你乘一个数的时候,你会左移它所出现的位置步,比如:10110010那么就会左移动1位,10111000左移3位,利用好这个特性我们就可以对一个数进行拆分了,保留每一位上面的1,其余的都变成0。 在这里需要用到几个辅助的位操作:1. -n = ~(n-1) = ~n+12. n&~(n-1),获取n中二进制中的最后一个13. n&(n-1),去掉n中二进制中的最后一个1 二进制除法   二进制的除法可以利用移位跟加减法进行计算。思路如下:先对除数进行移位操作,移位到一个临界值,即比被除数小的最大值,再用除数进行迭代相减,有点类似辗转相除法。   下面贴张图,应该就很好理解了。满足为1,不满足上0 POW的实现 在这里不使用的循环的原因是,那样太需要计算很多次,这里的temp用于保存上次的记录的结果,直接拿出来用,避免的了重复的计算,我们一次分为奇偶来讨论,如 x^4 可以拆分为x^2*x^2 => x^(y/2),而奇数的话,我们可以用上次保存的偶数乘以x得到。代码如下: 总结 位运算应用口诀 清零取反要用与,某位置一可用或 若要取反和交换,轻 轻松松用异或 移位运算 […]

Pageable多字段不同排序规则问题

若前端传排序字段。则为sort=weight,sequence,desc&sort=extra,asc&sort=id,desc 针对Spring Boot 2.1及之前 Sort sort = new Sort(Sort.Direction.DESC, “createdate”) .and(new Sort(Sort.Direction.AES, “id”)); Pageable pageable = new PageRequest(1, 10, sort) 针对Spring Boot 2.2及之后 var sort = Sort.by(Sort.Direction.DESC, “weight”, “sequence”) .and(Sort.by(Sort.Direction.ASC, “extra”)) .and(Sort.by(Sort.Direction.DESC, “id”)); var pageNumber = pageable.getPageNumber(); var pageSize = pageable.getPageSize(); return PageRequest.of(pageNumber, pageSize, sort);

VO、DTO、DO、PO、BO、POJO

概念: Entity: 最常用实体类,基本和数据表一一对应,一个实体一张表。 VO (View Object ):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。 DTO (Data Transfer Object ):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。 DO (Domain Object ):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。 PO (Persistent Object ):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性。 BO (business object) : 代表业务对象的意思,Bo就是把业务逻辑封装为一个对象(注意是逻辑,业务逻辑),这个对象可以包括一个或多个其它的对象。通过调用Dao方法,结合Po或Vo进行业务操作。 形象描述为一个对象的形为和动作,当然也有涉及到基它对象的一些形为和动作。比如处理一个人的业务逻辑,该人会睡觉,吃饭,工作,上班等等行为,还有可能和别人发关系的行为,处理这样的业务逻辑时,我们就可以针对BO去处理。 POJO (plian ordinary java object) : 代表简单无规则java对象 纯的传统意义的java对象,最基本的Java Bean只有属性加上属性的get和set方法 可以额转化为PO、DTO、VO;比如POJO在传输过程中就是DTO Dao (data access object) : 数据访问对象的意思,是sun的一个标准j2ee设计模式的接口之一,负责持久层的操作 。这个基本都了解,Dao和上面几个O区别最大,基本没有互相转化的可能性和必要,主要用来封装对数据的访问,注意,是对数据的访问,不是对数据库的访问。 模型: 下面以一个时序图建立简单模型来描述上述对象在三层架构应用中的位置 用户发出请求(可能是填写表单),表单的数据在展示层被匹配为VO。 展示层把VO转换为服务层对应方法所要求的DTO,传送给服务层。 服务层首先根据DTO的数据构造(或重建)一个DO,调用DO的业务方法完成具体业务。 服务层把DO转换为持久层对应的PO(可以使用ORM工具,也可以不用),调用持久层的持久化方法,把PO传递给它,完成持久化操作。 对于一个逆向操作,如读取数据,也是用类似的方式转换和传递,略。 VO 与 DTO 的区别 大家可能会有个疑问:既然DTO是展示层与服务层之间传递数据的对象,为什么还需要一个VO呢?对!对于绝大部分的应用场景来说,DTO和VO的属性值基本是一致的,而且他们通常都是POJO,因此没必要多此一举,但不要忘记这是实现层面的思维,对于设计层面来说,概念上还是应该存在VO和DTO,因为两者有着本质的区别,DTO代表服务层需要接收的数据和返回的数据,而VO代表展示层需要显示的数据。 […]

lWoHvYe 无悔,专一