质量属性2——质量六大属性之可用性在代码端的实现

三大点:

一、错误检测

(1)命令/响应

         个人理解响应就像是一个暗号,我发过去上半部分,然后你能返回对应的下半部分,那么这个过程就没毛病

         例1:

1 import requests
2 r=requests.get("http://www.baidu.com")
3 r.status_code
status_code

         其中 r.status_code 就是获取向网页请求返回的结果

         如果结果是200则成功,如果是其他的则失败,这一例是对 是否成功获取网页的一个响应

         例2:

1 #include<stdio.h>
2 int main()
3 { 
4     char ch; 
5     int i = system("ping 192.168.1.1"); 
6     printf("%d
",i); 
7     system("pause"); 
8     return 0;
9 }
system("ping ")

         这里的 system("ping ")即为测试ping是否通,

         若返回的 i=1,则表示“未ping通”;若 i=0,则表示 “ping通”

(2)心跳(dead man 计时器)

 1 Page({
 2   /**
 3    * 页面的初始数据
 4    */
 5   data: {
 6     timer: '',//定时器名字
 7     countDownNum: '60'//倒计时初始值
 8   },
 9  
10   onShow: function(){
11     //什么时候触发倒计时,就在什么地方调用这个函数
12     this.countDown();
13   },
14  
15   countDown: function () {
16     let that = this;
17     let countDownNum = that.data.countDownNum;//获取倒计时初始值
18     //如果将定时器设置在外面,那么用户就看不到countDownNum的数值动态变化,所以要把定时器存进data里面
19     that.setData({
20       timer: setInterval(function () {//这里把setInterval赋值给变量名为timer的变量
21         //每隔一秒countDownNum就减一,实现同步
22         countDownNum--;
23         //然后把countDownNum存进data,好让用户知道时间在倒计着
24         that.setData({
25           countDownNum: countDownNum
26         })
27         //在倒计时还未到0时,这中间可以做其他的事情,按项目需求来
28         if (countDownNum == 0) {
29           //这里特别要注意,计时器是始终一直在走的,如果你的时间为0,那么就要关掉定时器!不然相当耗性能
30           //因为timer是存在data里面的,所以在关掉时,也要在data里取出后再关闭
31           clearInterval(that.data.timer);
32           //关闭定时器之后,可作其他处理codes go here
33         }
34       }, 1000)
35     })
36   }
37 })
time.js
1 <view class='countDown'>倒计时:<text style='color:red'>{{countDownNum}}</text>s</view>
time.wxml

         这个是微信小程序上实现的一个简单计时器的代码,目的就是计时用,而将其用到实例中可以控制页面的跳转、提示信息等

         如下,这是一个答题的js,里面的内容是300s内答完页面的题目,如果未在300内答完则后退到上一页,若答完,则评判分数,答题入库。

  1 // pages/exam/exam.js
  2 import '../../utils/util.js';    //导入日期格式化模块
  3 //获取应用实例
  4 const app = getApp()
  5 
  6 Page({
  7 
  8   /**
  9    * 页面的初始数据
 10    */
 11   data: {
 12     questions: [{}],
 13     presentQ: 0,
 14     uAnswer: [],
 15     content: "",
 16     tag: false,
 17     color: "#ff6f10",
 18     time: 300,
 19     time_control: 1,
 20   },
 21 
 22   /**
 23    * 生命周期函数--监听页面加载
 24    */
 25   onLoad: function (options) {
 26   
 27     let that = this
 28     let chapter = options.chapter
 29     let course = options.course
 30     // let chapter = '第一章'
 31     // let course = 'C语言'
 32     wx.request({
 33       url: app.globalData.host + '/exam/wx_question.php?chapter=' + chapter + '&course=' + course,
 34       dataType: 'json',
 35       success(res) {
 36         console.log(res.data)
 37         that.setData({ questions: res.data })  //加载下一题
 38       }
 39     })
 40   },
 41 
 42   /**
 43    * 生命周期函数--监听页面初次渲染完成
 44    */
 45   onReady: function () {
 46 
 47   },
 48 
 49   /**
 50    * 生命周期函数--监听页面显示
 51    */
 52   onShow: function () {
 53 
 54   },
 55 
 56   /**
 57    * 生命周期函数--监听页面隐藏
 58    */
 59   onHide: function () {
 60 
 61   },
 62 
 63   /**
 64    * 生命周期函数--监听页面卸载
 65    */
 66   onUnload: function () {
 67     let that = this;
 68     that.setData({
 69       time: that.data.time = 1,
 70       time_control: that.data.time_control = 0
 71     })
 72   },
 73 
 74   /**
 75    * 页面相关事件处理函数--监听用户下拉动作
 76    */
 77   onPullDownRefresh: function () {
 78 
 79   },
 80 
 81   /**
 82    * 页面上拉触底事件的处理函数
 83    */
 84   onReachBottom: function () {
 85 
 86   },
 87 
 88   /**
 89    * 用户点击右上角分享
 90    */
 91   onShareAppMessage: function () {
 92 
 93   },
 94   selectAnswer: function (e) {
 95     //将uAnswer(用户答案)添加进question
 96     var p = 'questions[' + this.data.presentQ + '].uAnswer'
 97     this.setData({ [p]: e.detail.value })
 98   },
 99   //填空
100   fillblank: function (res) {
101     var p = 'questions[' + this.data.presentQ + '].uAnswer'
102     this.setData({ [p]: res.detail.value })
103   },
104 
105 
106   //下一题
107   next: function () {
108     //清空输入框
109     this.setData({ content: "" })
110     let that = this
111     //下一题
112     
113       var p = this.data.presentQ
114       if (this.data.questions[p].uAnswer) {
115         this.setData({ presentQ: p + 1 })    //presentQ++
116         this.setData({ tag: false })
117         that.setData({})
118       }
119       console.log(this.data.presentQ)
120     
121     //如果是最后一题
122     
123       if (this.data.presentQ >= this.data.questions.length) {
124         //显示答题结果 
125         var score = 0
126         for (var i = 0; i < this.data.questions.length; i++) {
127           if (this.data.questions[i].ANSWER == this.data.questions[i].uAnswer) score += parseInt(this.data.questions[i].SCORE)
128           
129         }
130         this.setData({ score: score })
131       }
132     
133 
134   },
135 
136 
137 
138   setTime() {
139     let that = this
140     let myTime = setInterval(function () {
141       that.setData({
142         time: that.data.time - 1
143       })
144       console.log(that.data.time)
145       if (that.data.time == 0 && that.data.time_control != 0) {
146         clearInterval(myTime)
147         wx.navigateBack({})
148       }
149       else if (that.data.time_control == 0) {
150         clearInterval(myTime)
151       }
152     }, 1000)
153   },
154 
155 
156   insertScore: function (question) {
157     let correct = 0
158     if (question.ANSWER == question.uAnswer) {
159       correct = 1
160     } else {
161       correct = 0
162     }
163     wx.request({
164       url: app.globalData.host + '/exam/wx_insertScore.php?sid=' + app.globalData.userInfo.ID + '&UID=' + question.UID + '&Chapter=' + question.CHAPTER + '&Course=' + question.COURSE + '&Correct=' + correct,
165       success(res) {
166       },
167 
168     })
169   },
170 
171   redo: function () {
172     //this.setData({presentQ:0})
173     wx.navigateBack({})
174   }
175 })
exam_js

(3)异常

         我所理解的异常就是 检测程序运行中各种的异常,例如数据异常,返回异常等。

         下面是一个简单的方法体用“throw”抛出异常

1 public void dev(){
2     int a = 5 ;
3     int b = 1 ;
4     if(b==0){
5         throw new ArithmeticException() ;
6     }else{
7         System.out.println(a/b);
8             }
9 }
throw

         这里可以很简单的看出若b=0则抛出异常,反之输出a/b,即为5

二、错误恢复

(1)表决

         个人理解是:程序运行有很多算法,里面有一类称作表决算法,实行的是裁决功能,他可以监视其他的算法/处理器是否运行错误,若错,则纠正

         虽然我没用过这么高级的东西,但是我通过百度查到了一个叫“Simplex”单纯形法算法,它是一个表决算法,解决的是线性规划问题

         简介:一般线性规划问题中当线性方程组的变量数大于方程个数,这时会有不定数量的解,而单纯形法是求解线性规划问题的通用方法。具体步骤是,从线性方程组找出一个个的单纯形,每一个单纯形可以求得一组解,然后再判断该解使目标函数值是增大还是变小了,决定下一步选择的单纯形。通过优化迭代,直到目标函数实现最大或最小值

而至于具体怎么用,移步

https://baike.baidu.com/item/%E5%8D%95%E7%BA%AF%E5%BD%A2%E6%B3%95/8580570?fr=aladdin 百度百科

这是我看到的一个关于代码层次的Simplex算法分析很好的博客,也对我学习Simplex算法代码实现有很大帮助

https://www.cnblogs.com/Kenneth-Wong/p/8451343.html Kenneth-Wong 的博客园

(2)主动冗余(热重启)

         冗余的含义:提前对关键的地方做备份,做应急处理,例如网络冗余、服务器冗余、磁盘冗余、数据冗余等

         主动和被动的区别就是:

         主动:所有的冗余组件(无论主,还是备份)同时在运行,同步更新,一旦主发生故障,备份立即顶替

         被动:一个组件(主)在运行,备份进行定时的更新,一旦主发生故障,备份顶替,但不是故障前主最新的状态

         主动的例子:

         地铁控制系统中,两个与硬件直接通讯的主备RTU(REMOTE TERMINAL UNIT)之间就采用自控方式。当两个RTU之间不能通讯时,或者当前系统中仅有一个RTU时,它们会将自己设定为主节点,提供所有服务。

(3)被动冗余(暖重启/双冗余/三冗余)

         检查点/回滚:

         这个就像电脑系统的备份精灵,在某一个节点备份当前的状态,若主发生错误,则回到之前备份节点的状态

一种是IDEA的回滚例如:来源:https://www.cnblogs.com/smile-fanyin/p/11007696.html

在 IDEA 编辑器里面,右键操作代码所在文件夹,选择 git ,点击 show  history 。如下图:

历史记录里面,根据自己提交的时间,和右侧显示的 commit 的文件,判断要回滚到哪个版本。

 第二种代码回滚的话,百度了下,有:git代码回滚

其一是本地文件回滚,其二是远程文件回滚

本地很简单,三步骤(PS:素材来自https://blog.csdn.net/leo_csdn_/article/details/84838514):

1、查看log

输入git log 查看commit记录

[xxxxxxx]$ git log

2、寻找到想要回滚的commit 

 3、确定需要回滚到的commitId,输入 git reset --hard{commitId},实现本地文件回滚

[xxxxxxx]$ git push -f

远程回滚,抱歉我有点看不懂,但是不妨碍看是不:

请移步 https://www.cnblogs.com/lwh-note/p/9639835.html

这个写的不错

三、错误预防

(1)从服务中删除

          我的理解就是在使用完某个连接后及时的关闭连接(也可理解为删除这个连接),不耽误下一次的使用

          目前咱应用很多的就是DBUtil,mysql数据库的连接

 1 package com.util;
 2 
 3 import java.sql.*;
 4  
 5 public class DBUtil {
 6     private static String driver;    
 7     private static String url;    
 8     private static String username;    
 9     private static String password;
10     
11     static {        
12         driver = "com.mysql.jdbc.Driver";        
13         url = "jdbc:mysql://127.0.0.1:3306/wang?useSSL=false&characterEncoding=utf8";        
14         username = "root";        
15         password = "123456";        
16         try {            
17             Class.forName(driver);        
18         } catch (ClassNotFoundException e) {            
19             e.printStackTrace();        
20         }     
21     }     
22     
23     public static Connection getConn() throws SQLException {        
24         return DriverManager.getConnection(url, username, password);    
25         }     
26     
27     public static void close(Connection conn, Statement st, ResultSet rs) {        
28         try {            
29             if (conn != null) {                
30                 conn.close();            
31                 }            
32             if (st != null) {                
33                 st.close();           
34                 }            
35             if (rs != null) {               
36                 rs.close();            
37                 }        
38             } catch (SQLException e) {   
39                 e.printStackTrace();       
40             }   
41     }
42 }
DBUtil

这个里面有正常运行的开启连接,也有close关闭连接的方法,

在其他的java文件中,每一次开启mysql的连接,在使用完之后都会有个close的使用,目的就是错误预防

(2)事务

         这个我的理解是对 “并发进程” 排队,按照规则有序得进行

         想到的例子就是数据库课程里讲的事务锁(X锁,S锁,IS锁,IX锁等)

         共享锁(S锁、多锁):事务获得元组的共享锁后,其它事务也只能获得该元组的共享锁,而不能获得排它锁;获得共享锁的事务可以对元组进行读操作。并发性:良好

         排它锁(X锁、写锁):事务获得元组的排它锁后,其它事务既不能获得该元组的共享锁,也不能获得排它锁;获得排它锁的事务可以对元组进行写操作。并发性:差

         意向共享锁(IS锁):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。

         意向排它锁(IX锁):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。

         S、X、IS、IX锁的兼容性如下图(PS:源自https://www.cnblogs.com/maying3010/p/8804941.html):

         何为死锁?

         死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待.

         等待图(wait-for-graph)可以用来检测死锁,通过深度优先算法实现,只要图中存在循环的回路.那么存在死锁.

         解决死锁时会回滚当中undo日志最小的一个事务,回滚又出现了,没错,这里当然要回滚了,因为错误了

(3)进程监视器

         一旦检测到进程中存在错误,监视进程就可以删除非执行进程,并为该进程创建一个新的实例,就像在备件战术中一样,初始化为某个适当的状态。

         这个感觉和被动冗余,回滚一样,回到之前的某个状态

原文地址:https://www.cnblogs.com/mitang0-0/p/12410750.html