1. 程式人生 > 實用技巧 >python獲得命令列輸入的引數

python獲得命令列輸入的引數

一.藉助陣列進行分頁

原理:進行資料庫查詢操作時,獲取到資料庫中所有滿足條件的記錄,儲存在應用的臨時陣列中,再通過List的subList方法,獲取到滿足條件的所有記錄。

實現:

首先在dao層,建立StudentMapper介面,用於對資料庫的操作。在介面中定義通過陣列分頁的查詢方法,如下所示:

1 List<Student> queryStudentsByArray();

方法很簡單,就是獲取所有的資料,通過list接收後進行分頁操作。

建立StudentMapper.xml檔案,編寫查詢的sql語句:

1 <select id="queryStudentsByArray" resultMap="studentmapper">
2   select * from student
3 </select>

可以看出再編寫sql語句的時候,我們並沒有作任何分頁的相關操作。這裡是查詢到所有的學生資訊。

接下來在service層獲取資料並且進行分頁實現:

定義IStuService介面,並且定義分頁方法:

  List<Student> queryStudentsByArray(int currPage, int pageSize);
通過接收currPage引數表示顯示第幾頁的資料,pageSize表示每頁顯示的資料條數。

建立IStuService介面實現類StuServiceIml對方法進行實現,對獲取到的陣列通過currPage和pageSize進行分頁:

1 @Override
2 public List<Student> queryStudentsByArray(int currPage, int pageSize) {
3     List<Student> students = studentMapper.queryStudentsByArray();
4     // 從第幾條資料開始
5     int firstIndex = (currPage - 1) * pageSize;
6     // 到第幾條資料結束
7     int lastIndex = currPage * pageSize;
8     return students.subList(firstIndex, lastIndex);
9 }

通過subList方法,獲取到兩個索引間的所有資料。

缺點:資料庫查詢並返回所有的資料,而我們需要的只是極少數符合要求的資料。當資料量少時,還可以接受。當資料庫資料量過大時,每次查詢對資料庫和程式的效能都會產生極大的影響。

二.藉助Sql語句進行分頁

  在瞭解到通過陣列分頁的缺陷後,我們發現不能每次都對資料庫中的所有資料都檢索。然後在程式中對獲取到的大量資料進行二次操作,這樣對空間和效能都是極大的損耗。所以我們希望能直接在資料庫語言中只檢索符合條件的記錄,不需要在通過程式對其作處理。這時,Sql語句分頁技術橫空出世。

實現:通過sql語句實現分頁也是非常簡單的,只是需要改變我們查詢的語句就能實現了,即在sql語句後面新增limit分頁語句。

首先還是在StudentMapper介面中新增sql語句查詢的方法,如下:

1 List<Student> queryStudentsBySql(Map<String,Object> data);

然後在StudentMapper.xml檔案中編寫sql語句通過limiy關鍵字進行分頁:

1 <select id="queryStudentsBySql" parameterType="map" resultMap="studentmapper">
2     select * from student limit #{currIndex} , #{pageSize}
3 </select>

接下來還是在IStuService介面中定義方法,並且在StuServiceIml中對sql分頁實現。

sql分頁語句如下:

1 select * from table limit index, pageSize;

所以在service中計算出currIndex:要開始查詢的第一條記錄的索引。

結果:

從輸出結果可以看出和陣列分頁的結果是一致的,因此sql語句的分頁也是沒問題的。

缺點:雖然這裡實現了按需查詢,每次檢索得到的是指定的資料。但是每次在分頁的時候都需要去編寫limit語句,很冗餘。而且不方便統一管理,維護性較差。所以我們希望能夠有一種更方便的分頁實現。

三.攔截器分頁

  上面提到的陣列分頁和sql語句分頁都不是我們今天講解的重點,今天需要實現的是利用攔截器達到分頁的效果。自定義攔截器實現了攔截所有以ByPage結尾的查詢語句,並且利用獲取到的分頁相關引數統一在sql語句後面加上limit分頁的相關語句,一勞永逸。不再需要在每個語句中單獨去配置分頁相關的引數了。

  首先我們看一下攔截器的具體實現,在這裡我們需要攔截所有以ByPage結尾的所有查詢語句,因此要使用該攔截器實現分頁功能,那麼再定義名稱的時候需要滿足它攔截的規則(以ByPage結尾),如下所示:

 1 package com.cbg.interceptor;
 2 import org.apache.ibatis.executor.Executor;
 3 import org.apache.ibatis.executor.parameter.ParameterHandler;
 4 import org.apache.ibatis.executor.resultset.ResultSetHandler;
 5 import org.apache.ibatis.executor.statement.StatementHandler;
 6 import org.apache.ibatis.mapping.MappedStatement;
 7 import org.apache.ibatis.plugin.*;
 8 import org.apache.ibatis.reflection.MetaObject;
 9 import org.apache.ibatis.reflection.SystemMetaObject;
10 import java.sql.Connection;
11 import java.util.Map;
12 import java.util.Properties;
13 
14 /**
15 * @Intercepts 說明是一個攔截器
16 * @Signature 攔截器的簽名
17 * type 攔截的型別 四大物件之一( Executor,ResultSetHandler,ParameterHandler,StatementHandler)
18 * method 攔截的方法
19 * args 引數
20 */
21 @Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
22 public class MyPageInterceptor implements Interceptor {
23 
24 //每頁顯示的條目數
25 private int pageSize;
26 //當前現實的頁數
27 private int currPage;
28 
29 private String dbType;
30 
31 @Override
32 public Object intercept(Invocation invocation) throws Throwable {
33     //獲取StatementHandler,預設是RoutingStatementHandler
34     StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
35     //獲取statementHandler包裝類
36     MetaObject MetaObjectHandler = SystemMetaObject.forObject(statementHandler);
37     //分離代理物件鏈
38     while (MetaObjectHandler.hasGetter("h")) {
39         Object obj = MetaObjectHandler.getValue("h");
40         MetaObjectHandler = SystemMetaObject.forObject(obj);
41     }
42     while (MetaObjectHandler.hasGetter("target")) {
43         Object obj = MetaObjectHandler.getValue("target");
44         MetaObjectHandler = SystemMetaObject.forObject(obj);
45     }
46     //獲取連線物件
47     //Connection connection = (Connection) invocation.getArgs()[0];
48     //object.getValue("delegate"); 獲取StatementHandler的實現類
49     //獲取查詢介面對映的相關資訊
50     MappedStatement mappedStatement = (MappedStatement) MetaObjectHandler.getValue("delegate.mappedStatement");
51     String mapId = mappedStatement.getId();
52     //statementHandler.getBoundSql().getParameterObject();
53     //攔截以.ByPage結尾的請求,分頁功能的統一實現
54     if (mapId.matches(".+ByPage$")) {
55         //獲取進行資料庫操作時管理引數的handler
56         ParameterHandler parameterHandler = (ParameterHandler) MetaObjectHandler.getValue("delegate.parameterHandler");
57         //獲取請求時的引數
58         Map<String, Object> paraObject = (Map<String, Object>) parameterHandler.getParameterObject();
59         //也可以這樣獲取
60         //paraObject = (Map<String, Object>) statementHandler.getBoundSql().getParameterObject();
61         //引數名稱和在service中設定到map中的名稱一致
62         currPage = (int) paraObject.get("currPage");
63         pageSize = (int) paraObject.get("pageSize");
64         String sql = (String) MetaObjectHandler.getValue("delegate.boundSql.sql");
65         //也可以通過statementHandler直接獲取
66         //sql = statementHandler.getBoundSql().getSql();
67         //構建分頁功能的sql語句
68         String limitSql;
69         sql = sql.trim();
70         limitSql = sql + " limit " + (currPage - 1) * pageSize + "," + pageSize;
71         //將構建完成的分頁sql語句賦值個體'delegate.boundSql.sql',偷天換日
72         MetaObjectHandler.setValue("delegate.boundSql.sql", limitSql);
73     }
74     //呼叫原物件的方法,進入責任鏈的下一級
75     return invocation.proceed();
76 }
77 
78 //獲取代理物件
79 @Override
80     public Object plugin(Object o) {
81     //生成object物件的動態代理物件
82     return Plugin.wrap(o, this);
83 }
84 
85 //設定代理物件的引數
86 @Override
87     public void setProperties(Properties properties) {
88         //如果專案中分頁的pageSize是統一的,也可以在這裡統一配置和獲取,這樣就不用每次請求都傳遞pageSize引數了。引數是在配置攔截器時配置的。
89         String limit1 = properties.getProperty("limit", "10");
90         this.pageSize = Integer.valueOf(limit1);
91         this.dbType = properties.getProperty("dbType", "mysql");
92     }
93 }

上面即是攔截器功能的實現,在intercept方法中獲取到select標籤和sql語句的相關資訊,攔截所有以ByPage結尾的select查詢,並且統一在查詢語句後面新增limit分頁的相關語句,統一實現分頁功能。

重點詳解:

StatementHandler是一個介面,而我們在程式碼中通過StatementHandler statementHandler = (StatementHandler) invocation.getTarget();獲取到的是StatementHandler預設的實現類RoutingStatementHandler。而RoutingStatementHandler只是一箇中間代理,他不會提供具體的方法。那你可能會納悶了,攔截器中基本上是依賴statementHandler獲取各種物件和屬性的,沒有具體屬性和方法怎麼行??接著看下面程式碼: