魯春利的工做筆記,好記性不如爛筆頭java
數據庫的分頁主要有物理分頁和邏輯分頁。
物理分頁:數據庫自己提供的分頁方式,如MySQL的limit、Oracle的rownum、SqlServer的top,好處是效率高,很差的地方就是不一樣數據庫有不一樣的查詢方式。
邏輯分頁:從數據庫將全部記錄查詢出來,存儲到內存中,而後數據再直接從內存中獲取並篩選分頁,好處是可以統一查詢方式,很差的地方是效率低,由於每次都要把所有數據查詢出來再處理。sql
經常使用orm框架採用的分頁技術:
①:hibernate採用的是物理分頁;
②:MyBatis使用RowBounds實現的分頁是邏輯分頁,也就是先把數據記錄所有查詢出來,然在再根據offset和limit截斷記錄。數據庫
MetaObjectapache
org.apache.ibatis.reflection.MetaObject是Mybatis提供的一個的工具類,Mybatis在sql參數設置和結果集映射裏常用到這個對象。app
屬性:
框架
// 原始對象 private Object originalObject; // 對原始對象的一個封裝 private ObjectWrapper objectWrapper; // org.apache.ibatis.reflection.factory.DefaultObjectFactory的父類 private ObjectFactory objectFactory; // org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory的父類 private ObjectWrapperFactory objectWrapperFactory;
方法:
ide
// 用於包裝對象 MetaObject forObject(Object object,ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) // 用於獲取屬性的值(支持OGNL的方法) Object getValue(String name) // 用於設置屬性的值(支持OGNL的方法) void setValue(String name, Object value)
構造方法工具
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { this.originalObject = object; this.objectFactory = objectFactory; this.objectWrapperFactory = objectWrapperFactory; if (object instanceof ObjectWrapper) { this.objectWrapper = (ObjectWrapper) object; } else if (objectWrapperFactory.hasWrapperFor(object)) { this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object); } else if (object instanceof Map) { this.objectWrapper = new MapWrapper(this, (Map) object); } else if (object instanceof Collection) { this.objectWrapper = new CollectionWrapper(this, (Collection) object); } else { this.objectWrapper = new BeanWrapper(this, object); } }
forObject方法this
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) { if (object == null) { return SystemMetaObject.NULL_META_OBJECT; } else { return new MetaObject(object, objectFactory, objectWrapperFactory); } }
getValue
spa
public Object getValue(String name) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { return null; } else { // 這裏至關於遞歸調用,直到最後一層。例如user.cust.custId // 第一次遞歸cust.custId // 第二次遞歸custId,這個就是真正訪問要返回的 return metaValue.getValue(prop.getChildren()); } } else { return objectWrapper.get(prop); } }
setValue
public void setValue(String name, Object value) { PropertyTokenizer prop = new PropertyTokenizer(name); if (prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if (metaValue == SystemMetaObject.NULL_META_OBJECT) { if (value == null && prop.getChildren() != null) { return; // don't instantiate child path if value is null } else { metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } } metaValue.setValue(prop.getChildren(), value); } else { objectWrapper.set(prop, value); } }
攔截器簽名
@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class}) }) public class PreparePaginationInterceptor extends BaseInterceptor {
從簽名裏能夠看出,要攔截的目標類型是StatementHandler(注意:type只能配置成接口類型),攔截的方法是名稱爲prepare參數爲Connection類型的方法。
說明:關於爲何要把攔截器加到StatementHandler請參閱MyBatis之SqlSession介紹