• 质量属性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)进程监视器

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

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

  • 相关阅读:
    Selenium2(webdriver)入门之TestNG的使用
    selenium2.0(WebDriver) API
    xss漏洞校验
    文件上传攻击
    代码注入
    一个安全测试的CheckList
    MTK Android 设置-选择日期格式 [管理和组织首选项,ListPreference,CheckBoxPreference,EditTextPreference,RingtonePreference]
    MTK Android ListPreference的用法
    MTK Android 回调机制[CallBack]
    MTK Android 耳机线控的实现方法
  • 原文地址:https://www.cnblogs.com/mitang0-0/p/12410750.html
Copyright © 2020-2023  润新知