前言:命令模式內容比較多,這里做了拆分
命令模式基礎篇 :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
