防御性编程(Defensive Programming)
什么是Defensive Programming[1]?
原文:Defensive programming is a form of defensive design intended to ensure the continuing function of a piece of software under unforeseen circumstances.
_
翻译:防御性编程是防御性设计的一种形式,它能够保证软件产品在不可预测的环境中持续运行。
我们可以看到,防御性编程只是防御性设计的分支,对于防御性设计,可以布满我们生活的任何角落,尤其是设计行业和制造业,因此,理解和应用防御性编程,让我们更好地懂得“防御”,也能将其应用于自己的生活。
防御性编程的重要思想[2]
所有的外部因素(输入参数、环境变量、上下文)都是“邪恶”的,都存在着企图摧毁程序的罪恶本源,为了抵制它,我们要在程序中处处检验,满地设卡,不满足条件就不再执行后续程序,以保护主程序的正确性
简单来说就是,不管别人如何使用程序,它都能做出相应的处理,因此我们需要预测可能出现的错误并阻止它。
注意,不要滥用Defensive Programming,这可能让你的程序消耗过多资源,牺牲本不必牺牲的性能(可以在文章最底部的参考资料中进一步学习)。
JDBC代码示例
防御性编程在Java异常中的应用情况
- 当程序产生异常,对后面的影响不大(视情况,看模块独立性),则只需抛出异常并继续执行
- 若程序产生异常,导致后面都不能执行,那就只能回滚重新执行,或者退出程序了
例如使用JDBC连接云端Mysql的时候,可能会断网导致无法连接,这个时候,连登录账户都不行,就需要用户
- 要么尝试重新连接
- 要么退出程序
给出示例代码,注释已经足够清楚,不再过多解释(代码是基于简单的控制台程序)
package FinancialSystem.UsualFunction;import com.mysql.cj.jdbc.exceptions.CommunicationsException;import javax.xml.crypto.Data;
import java.net.UnknownHostException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Time;
import java.util.Scanner;/*** 执行连接数据库操作的类** <p>* 创建日期:2020-08-04 20:44** @author 作者* @version 1.0.0* @since 1.0.0*/public class DatabaseOperating {/*** 供其他程序连接数据库使用** <p>* 方法保证了返回值一定是非空的 Connection对象* </p>** @return Connection Object* @throws InterruptedException*/public static Connection createDatabaseLink() throws InterruptedException {Connection connection;int i = 0;for (; i < 5; i++) {connection = DatabaseOperating.createDatabase();if (connection != null) {if(i != 0){System.out.println("恭喜您,网络连接成功!");}return connection;}System.out.println("是否尝试重新连接?");System.out.println("1. 是 2. 否");Scanner scanner = new Scanner(System.in);System.out.print("请输入序号:");int choose = scanner.nextInt();if(choose != 1){break;}}if (i == 5) {System.err.println("超过重连次数,请联系相关运营商检查您的网络!");}for (int j = 5; j > 0; j--) {System.err.print("\r" + j + "秒后将自动退出程序");Thread.sleep(1000);}System.err.print("\r程序退出!");System.exit(0);return null;}/*** 连接本地(或云端)的Mysql数据库** @return Connection实例*/private static Connection createDatabase() throws InterruptedException {try {String url = "jdbc:mysql://主机:端口/数据库";String user = "用户名";String password = "密码";return DriverManager.getConnection(url, user, password);} catch (CommunicationsException communicationsException) {System.err.println("网络连接错误!");return null;} catch (SQLException throwable) {// throwable.printStackTrace();System.err.println("远程服务器连接失败");for (int i = 5; i > 0; i--) {System.err.print("\r" + i + "秒后将自动退出程序");Thread.sleep(1000);}System.err.print("\r程序退出!");System.exit(0);}return null;}
}
方法的调用,能够保证,connection一定不是null,也就能够保证后面的一些步骤避免一些问题,例如NullPointerException
。
举例如下(部分代码):
String sql = "sql语句";try (Connection connection = DatabaseOperating.createDatabaseLink();PreparedStatement preparedStatement = connection.prepareStatement(sql)
) {// <代码部分>
} catch (SQLException | InterruptedException throwable) {throwable.printStackTrace();
}
思考点
以下是我的思考,对于初学者,我想暂时我暂时没有必要花精力于此处,目前这些也没有搜集专业资料,仅供思考,这一小节可以忽略掉。
- JDBC不应该使用一个具备大量的MySQL账户,这是危险的,我们应该分配多个具备专门权限的账户,去处理不同的信息。
- 不应该使用明码表示MySQL账户,如果那样的话,使用逆向工程,很容易被找到和破解,这样不太安全,例如,可以将账户存在隐秘的地方以密码传输,在程序中解码;又或者使用低等权限账户登录数据库,从数据库获取具备操作权限的账户信息,再用该账户登录数据库。
参考资料
[1] Wikipedia: Defensive Programming
[2] 防御性编程的核心思想