前言:命令模式内容比较多,这里做了拆分
命令模式基础篇 :https://blog.csdn.net/Json_wangqiang/article/details/85276179
命令模式扩展篇 - 宏命令:https://blog.csdn.net/Json_wangqiang/article/details/85276185
命令模式扩展篇 - 撤销命令:https://blog.csdn.net/Json_wangqiang/article/details/85276177
命令模式扩展篇 - 命令队列:https://blog.csdn.net/Json_wangqiang/article/details/85276186
命令模式扩展篇 - 请求日志:https://blog.csdn.net/Json_wangqiang/article/details/85276183
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:原文地址 https://blog.csdn.net/Json_wangqiang/article/details/85276183