前言:命令模式内容比较多,这里做了拆分
命令模式基础篇 :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