設計模式解密(11)- 命令模式 - 擴展篇(請求日志)


前言:命令模式內容比較多,這里做了拆分

命令模式基礎篇 :http://www.cnblogs.com/JsonShare/p/7202133.html

命令模式擴展篇 - 宏命令:http://www.cnblogs.com/JsonShare/p/7206395.html

命令模式擴展篇 - 撤銷命令:http://www.cnblogs.com/JsonShare/p/7206513.html

命令模式擴展篇 - 命令隊列:http://www.cnblogs.com/JsonShare/p/7206607.html

命令模式擴展篇 - 請求日志:http://www.cnblogs.com/JsonShare/p/7206665.html

4、請求日志

概念:將所有的動作都記錄在日志中,並能在系統死機后,重新調用這些動作恢復到之前的狀態。當我們執行命令的時候,將歷時記錄存儲在磁盤中。一旦系統死機,我們就可以將命令對象重新加載,並依次調用這些對象的execute()方法。

實現方法:利用對象的序列化把對象保存起來(記錄日志),在需要的時候反序列化(恢復事務)。

請求日志文件可以實現很多功能,常用功能如下

  1、什么事情都存在意外,如一旦系統發生故障,日志文件可以為系統提供一種恢復機制,在請求日志文件中可以記錄用戶對系統的每一步操作,從而讓系統能夠順利恢復到某一個特定的狀態;

  2 、請求日志也可以用於實現批處理,在一個請求日志文件中可以存儲一系列命令對象,例如一個命令隊列;

  3、可以將命令隊列中的所有命令對象都存儲在一個日志文件中,每執行一個命令則從日志文件中刪除一個對應的命令對象,防止因為斷電或者系統重啟等原因造成請求丟失,而且可以避免重新發送全部請求時造成某些命令的重復執行,只需讀取請求日志文件,再繼續執行文件中剩余的命令即可。

 

模擬場景(未必真實,領會實質即可):

假如數據庫被DBA誤操作了,數據全刪除了,因為兩小時備份了一次數據庫,所以現在只能恢復到兩小時前的數據;這豈不是很悲劇;要被開除的節奏;還要賠償公司經濟損失;瞬間感覺要死的節奏;

要是在程序里加上請求日志,這個算個鳥,分分鍾恢復;

我們把程序執行的所有sql記錄下來,這里假設sql都是在這兩小時執行的(比較理想,具體情境具體解決);

代碼來了:

package com.designpattern.Command.extend.RequestLog;

import java.io.Serializable;

/**
 * 抽象命令類,由於需要將命令對象寫入文件,因此它實現了Serializable接口  
 * @author Json
*/
public abstract class Command implements Serializable {
    private static final long serialVersionUID = 1L;
    
    protected String name; //命令名稱 
    protected String args; //命令參數  
    protected Operator operator; //接收者對象
      
    public Command(String name) {  
        this.name = name;
    }  
      
    public String getName() {  
        return this.name;  
    }  
      
    public void setName(String name) {  
        this.name = name;  
    }  
      
    public void setOperator(Operator operator) {  
        this.operator = operator;  
    }  
    
    //聲明兩個抽象的執行方法execute()  
      public abstract void execute(String args);  
      public abstract void execute();
}
package com.designpattern.Command.extend.RequestLog;

import java.io.Serializable;
/**
 * 請求接收者 -- 由於Operator類的對象是Command的成員對象,它也將隨Command對象一起寫入文件,因此Operator也需要實現Serializable接口  
 * @author Json
*/
public class Operator implements Serializable{
    private static final long serialVersionUID = 1L;

    public void insert(String args) {  
        System.out.println("新增數據:" + args);  
    }  
      
    public void update(String args) {  
        System.out.println("修改數據:" + args);  
    }  
      
    public void delete(String args) {  
        System.out.println("刪除數據:" + args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;
/**
 * 具體命令角色類 -- 插入命令
 * @author Json
*/
public class InsertCommand extends Command{
    public InsertCommand(String name) {
        super(name);
    }

    public void execute(String args) {  
        this.args = args;  
        operator.insert(args);  
    }  
      
    public void execute() {  
        operator.insert(this.args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;
/**
 * 具體命令角色類 -- 修改命令
 * @author Json
*/
public class UpdateCommand extends Command{
    public UpdateCommand(String name) {
        super(name);
    }

    public void execute(String args) {  
        this.args = args;  
        operator.update(args);  
    }  
      
    public void execute() {  
        operator.update(this.args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;
/**
 * 具體命令角色類 -- 刪除命令
 * @author Json
*/
public class DeleteCommand extends Command{
    public DeleteCommand(String name) {
        super(name);
    }

    public void execute(String args) {  
        this.args = args;  
        operator.delete(args);  
    }  
      
    public void execute() {  
        operator.delete(this.args);  
    }  
}
package com.designpattern.Command.extend.RequestLog;

import java.util.ArrayList;

import com.designpattern.utils.FileUtil;
/**
 * 請求發送者
 * @author Json
*/
public class SqlExecuteTool {
     //定義一個集合來存儲每一次操作時的命令對象  
    private ArrayList<Command> commands = new ArrayList<Command>();  
    private Command command;
  
    //注入具體命令對象  
    public void setCommand(Command command) {  
        this.command = command;  
    }  
      
    //執行配置文件修改命令,同時將命令對象添加到命令集合中  
    public void call(String args) {  
        command.execute(args);  
        commands.add(command);  
    }  
      
    //記錄請求日志,生成日志文件,將命令集合寫入日志文件  
    public void save() {  
        FileUtil.writeCommands(commands);  
    }
      
    //從日志文件中提取命令集合,並循環調用每一個命令對象的execute()方法來實現配置文件的重新設置  
    public void recover() {  
        ArrayList list = FileUtil.readCommands();  
        for (Object obj : list) {  
            ((Command)obj).execute();  
        }  
    }  
}

測試:

package com.designpattern.Command.extend.RequestLog;
/**
 * 測試
 * @author Json
*/
public class Client {
    public static void main(String[] args) {
        SqlExecuteTool tool = new SqlExecuteTool(); //定義請求發送者  
        Operator operator = new Operator(); //定義請求接收者  
          
        Command command;
        
        //執行了很多次SQL
        command = new InsertCommand("增加");  
        command.setOperator(operator);   
        tool.setCommand(command);  
        tool.call("insert xxx");  
          
        command = new InsertCommand("增加");  
        command.setOperator(operator);  
        tool.setCommand(command);  
        tool.call("insert xxx");  
          
        command = new UpdateCommand("修改"); 
        command.setOperator(operator); 
        tool.setCommand(command);  
        tool.call("update xxx");  
          
        command = new DeleteCommand("刪除");
        command.setOperator(operator);  
        tool.setCommand(command);          
        tool.call("delete xxx");  
          
        System.out.println("-------------------------------------");
        System.out.println("保存執行的sql");  
        tool.save();
        System.out.println("-------------------------------------");
        System.out.println("恢復執行的sql");  
        System.out.println("-------------------------------------");
        tool.recover(); 
    }
}

結果:

新增數據:insert xxx
新增數據:insert xxx
修改數據:update xxx
刪除數據:delete xxx
-------------------------------------
保存執行的sql
-------------------------------------
恢復執行的sql
-------------------------------------
新增數據:insert xxx
新增數據:insert xxx
修改數據:update xxx
刪除數據:delete xxx

這里把這兩小時的sql又執行了一遍,是不是相當於數據全部恢復了?

我只能腦補情景,具體在實際編程中,還未遇到,我還年輕,不比老司機... O(∩_∩)O哈哈~

     

PS:源碼地址   https://github.com/JsonShare/DesignPattern/tree/master 

  

PS:原文地址 http://www.cnblogs.com/JsonShare/p/7206665.html 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM