精华内容
下载资源
问答
  • 章.软件测试过程.课后作业0 目录5 软件测试过程5.7 课后作业5.7.1 课堂重点5.7.2 测试与作业6 下一章 0 目录 5 软件测试过程 5.7 课后作业 5.7.1 课堂重点 5.7.2 测试与作业 习题5 1(1分)软件测试是软件质量...

    慕课金陵科技学院.软件质量保证与测试.第五章.软件测试过程.课后作业

    0 目录

    5 软件测试过程

    5.7 课后作业

    5.7.1 课堂重点

    5.7.2 测试与作业

    习题5

    1(1分)软件测试是软件质量保证的重要手段,下述哪种测试是软件测试的最基础环节?( )
    A.集成测试 B.单元测试  C.系统测试 D.验收测试
    参考答案:B

    2(1分)增量式集成测试有3种方式:自顶向下增量测试方法,( )和混合增量测试方式。
    A.自下向顶增量测试方法
    B.自底向上增量测试方法
    C.自顶向上增量测试方法
    D.自下向顶增量测试方法
    参考答案:B

    3(1分)在软件测试步骤按次序可以划分为以下几步:( )。
    A、单元测试、集成测试、系统测试、验收测试
    B、验收测试、单元测试、系统测试、集成测试
    C、单元测试、集成测试、验收测试、系统测试
    D、系统测试、单元测试、集成测试、验收测试
    参考答案:A

    4(1分)软件验收测试合格通过的标准不包括( )
    A.软件需求分析说明书中定义的所有功能已全部实现,性能指标全部达到要求。
    B.至少有一项软件功能超出软件需求分析说明书中的定义,属于软件特色功能。
    C.立项审批表、需求分析文档、设计文档和编码实现一致。
    D.所有在软件测试中被发现的严重软件缺陷均已被修复。
    参考答案:B

    5(1分)下列关于alpha测试的描述中正确的是:( )
    A.alpha测试一定要真实的最终软件用户参加
    B.alpha测试是集成测试的一种
    C.alpha测试是系统测试的一种
    D.alpha测试是验收测试的一种
    参考答案:D

    6(1分)编码阶段产生的错误主要由( )检查出来的。
    A、单元测试 B、集成测试 C、系统测试 D、有效性测试
    参考答案:A

    7(1分)单元测试一般以( )为主。
    A、白盒测试 B、黑盒测试 C、系统测试 D、分析测试
    参考答案:A

    8(1分)单元测试的测试用例主要根据( )的结果来设计。
    A、需求分析 B、源程序 C、概要设计 D、详细设计
    参考答案:D

    9(1分)集成测试的测试用例是根据( )的结果来设计。
    A、需求分析 B、源程序 C、概要设计 D、详细设计
    参考答案:C

    10(1分)集成测试对系统内部的交互以及集成后系统功能检验了何种质量特性( )
    A、正确性 B、可靠性 C、安全性 D、可维护性
    参考答案:A

    11(1分)( )的目的是对即将交付使用的软件系统进行全面的测试,确保最终软件产品满足用户需求。
    A、系统测试   B、集成测试   C、单元测试   D、验收测试
    参考答案:A

    12(1分)单元测试中用来模拟被测模块调用者的模块是 ( )
    A、父模块 B、子模块 C、驱动模块 D、桩模块
    参考答案:C

    13(1分)在自底向上测试中,要编写( )。
    A、测试存根 B、驱动模块 C、桩模块 D、 底层模块。
    参考答案:B

    14(1分)以下哪种软件测试属于软件性能测试的范畴( )。
    A、接口测试 B、压力测试 C、单元测试 D、正确性测试
    参考答案:B

    15(1分)下列关于α测试的描述中,正确的是( )
    A.α测试采用白盒测试技术;
    B.α测试不需要从用户角度考虑问题;
    C.α测试是系统测试的一种;
    D.α测试是验收测试的一种;
    参考答案:D

    16(1分)下列软件属性中,软件产品首要满足的应该是( )
    A、功能需求 B、性能需求 C、可扩展性和灵活性 D、容错纠错能力
    参考答案:A

    17(1分)按照测试组织划分,软件测试可分为:开发方测试,第三方测试,( )。
    A.集成测试 B.单元测试 C.用户测试 D.灰盒测试
    参考答案:C

    18(1分)软件可靠性是指在指定的条件下使用时,软件产品维持规定的性能级别的能力,其子特性( )是指在软件发生故障或者违反指定接口的情况下,软件产品维持规定的性能级别的能力。
    A、成熟性 B、易恢复性 C、容错性 D、稳定性
    参考答案:C

    19(1分)下面哪项对验收测试的描述不正确?( )
    A、与系统测试不同的是以客户业务需求为标准来进行测试
    B、测试人员多由客户方担任,也可以客户委托第三方来进行验收测试
    C、由资深的开发和测试人员来进行测试
    D、不仅仅要验收程序,还要验收相关的文档
    参考答案:C

    20(1分)对于软件的β测试,下列哪些描述是正确的? ( )
    A. β测试就是在软件公司内部展开的测试,由公司专业的测试人员执行的测试。
    B. β测试就是在软件公司内部展开的测试,由公司的非专业测试人员执行的测试。
    C. β测试就是在软件公司外部展开的测试,由非专业的测试人员执行的测试。
    D. β测试就是在软件公司外部展开的测试,由专业的测试人员执行的测试。
    参考答案:C

    21(1分)在程序测试中,用于检查程序模块或子程序之间的调用是否正确的静态分析方法是 ( )
    A、操作性分析 B、可靠性分析 C、引用分析 D、接口分析
    参考答案:C

    22(1分)用于考察当前软硬件环境下软件系统所能承受的最大负荷并帮助找出系统瓶颈所在的是( )。
    A、压力测试 B、容量测试 C、负载测试 D、疲劳测试
    参考答案:A

    23(2分)集成测试以_______________说明书为指导,验收测试以_______________说明书为指导。
    参考答案:概要设计 软件规格

    24(2分)软件验收测试可分为 2 类:__________________、__________________。
    参考答案:α+β测试 正式验收测试

    25(1分)____________指软件系统被修改或扩充后重新进行的测试。
    参考答案:回归测试

    26(1分)____________是在软件开发公司内模拟软件系统的运行环境下的一种验收测试。
    参考答案:α测试

    27(1分)____________的依据是软件规格说明书。
    参考答案:验收测试

    28(1分)(判断)单元测试通常由开发人员进行。 ( )
    参考答案:对

    29(1分)(判断)测试应从"大规模"开始,逐步转向"小规模"。 ( )
    参考答案:错

    30(1分)(判断)负载测试是验证要检验的系统的能力最高能达到什么程度。 ( )
    参考答案:错

    31(1分)(判断)为了快速完成集成测试,采用一次性集成方式是适宜的。 ( )
    参考答案:错

    32(1分)(判断)验收测试是站在用户角度的测试。 ( )
    参考答案:对

    33(1分)(判断)自底向上集成需要测试员编写桩模块。 ( )
    参考答案:错

    34(1分)(判断)β测试是集成测试的一种。 ( )
    参考答案:错

    35(1分)(判断)如何看待软件产品内部的缺陷,开发者和用户的立场是一致的。 ( )
    参考答案:错

    36(13分)试针对如下程序代码设计测试脚本。

    public class GCD {   
    	public int getGCD(int x,int y) {
    		if(x<1||x>100) {   
    			System.out.println("数据超出范围!");        
    			return -1;    
    		}      
    		if(y<1||y>100) {   
    			System.out.println("数据超出范围!");      
    			return -1;        
    		}      
    		int max,min,result = 1;      
    		if(x>=y) {  
    			max = x;         
    			min = y;     
    		}      
    		else {  
    			max = y;         
    			min = x;     
    		}      
    		for(int n=1;n<=min;n++) {   
    			if(min%n==0&&max%n==0) {       
    				if(n>result)              
    					result = n;
    			}     
    		}      
    		System.out.println("因数:"+result);      
    		return result;
    	}
    }
    

    参考答案:

    (1)设计测试脚本,对GCD类的getGCD方法实现语句覆盖测试。

    public class GCD {   
    	public void testDemo_yuju(){
      		int test1=getGCD(-1,100);
      		int test2=getGCD(2,1);
      		System.println.out(test1+ test2);
     	}
    	public int getGCD(int x,int y) {
      		if(x<1||x>100) {   
       			System.out.println("数据超出范围!");        
       			return -1;    
      		}      
      		if(y<1||y>100) {   
       			System.out.println("数据超出范围!");      
       			return -1;        
      		}      
      		int max,min,result = 1;      
      		if(x>=y) {  
       			max = x;         
       			min = y;     
      		}      
      		else {  
       			max = y;         
       			min = x;     
      		}      
      		for(int n=1;n<=min;n++) {   
       			if(min%n==0&&max%n==0) {       
        				if(n>result)              
         				result = n;
       			}     
      		}      
      		System.out.println("因数:"+result);      
      		return result;
     	}
    }
    

    (2)设计测试脚本,对GCD类的getGCD方法实现条件覆盖测试。

    public class GCD {  
    	public void testDemo_tiaojian(){
    		int test1=getGCD(-1,-1);
    		int test2=getGCD(100,100);
    		int test3=getGCD(2,1);
    		int test4=getGCD(1,2);
    		System.println.out(test1+ test2+ test3+ test4);
    	}
     	public int getGCD(int x,int y) {
       		 if(x<1||x>100) {   
    		        System.out.println("数据超出范围!");        
    		        return -1;    
        		}      
        		if(y<1||y>100) {   
          			System.out.println("数据超出范围!");      
          			return -1;        
        		}      
        		int max,min,result = 1;      
        		if(x>=y) {  
          			max = x;         
          			min = y;     
        		}      
        		else {  
          			max = y;         
          			min = x;     
        		}      
        		for(int n=1;n<=min;n++) {   
          			if(min%n==0&&max%n==0) {       
            			if(n>result)              
             			result = n;
          			}     
        		}      
        		System.out.println("因数:"+result);      
        		return result;
      	}
    }
    

    37(8分)设有程序段ModuleA和 ModuleB如下,

    public class ModuleA {       
    	public static double operate(double x) {              
    		// 模块A内部进行处理              
    		// ...              
    		double r = x/2;              
    		// 调用模块B              
    		double y = ModuleB.operate(r);              
    		// 继续处理              
    		// ...              
    		return y;       
    	}
    } 
    public class ModuleB {       
    	public static double operate(double r) {              
    		// 模块B内部进行处理              
    		// ...              
    		double temp = Pi*r * r * r *4/3;              
    		// 继续处理              
    		// ...              
    		double y = temp;              
    		return y;       
    	}
    }
    

    参考答案:

    (1)阅读程序,请说明这两段程序合起来的功能是什么?

    输入直径,求圆球的体积
    

    (2)已知变量x一开始就有一定的误差△x,请分析 ModuleA.operate(x)执行完毕后,返回结果y的相对误差有多大?
    在这里插入图片描述

    38(6分) 设有两段代码ModuleA和 ModuleB如下,它们由不同的程序员开发。

    public class ModuleA {       
    	/*** 实现把 str1 中包含的 str2 去掉后的内容返回的功能        
    	* @param str1 字符串1
    	* @param str2 字符串2        
    	* @param 返回处理的结果        
    	*/       
    	public String operate(String str1, String str2) {              
    		return str1.replace(str2, "");       
    	}
    }
    
    public class ModuleB {       
    	private ModuleA moduleA;              
    	public void setModuleA(ModuleA moduleA) {              
    		this.moduleA = moduleA;       
    	}       
    	/**        
    	* 模块B的具体处理操作中,调用了模块A的接口        
    	*/       
    	public String operate(String str1, String str2) {              
    		// str1 待替换的目标串       
    		// str2 原串              
    		return moduleA.operate(str1, str2);       
    	}
    }  
    

    参考答案:
    (1)试分析对这两段代码进行集成测试时会出现什么问题?

    ModuleB的目标是将str2中包含str1的字符串替换(去除),而ModuleA提供的接口是将str1中包含str2的字符串替换或删除
    两者接口颠倒,将会出现字符串替换错乱的问题
    

    (2)试设计两个测试数据,一个能发现这一问题,另一个则不能发现这一问题。
    在这里插入图片描述

    39(7分)某连锁机构网站有注册账号5万个,平均1天大约有12000个用户要访问该系统,用户一般在7点——22点使用该系统,在一天的时间内,用户使用系统的平均时长约为0.5小时。假设用户登录访问该系统符合泊松分布,为进行并发测试,请估算系统的平均并发用户数C_avg和并发用户峰值数C_max。

    参考答案:

    系统的平均并发用户数C_avg=nL/T=12000*0.5/(22-7)=400
    并发用户峰值数C_max~=400+3*400^1/2=460
    

    6 下一章

    博客地址:

    展开全文
  • 当我们的系统中引入了MQ之后,不得不考虑的一个问题是如何保证消息的顺序性,这是一个至关重要的事情,如果顺序错乱了,就会导致数据的不一致。 比如:业务场景是这样的:我们需要根据mysql的binlog日志同步一个...

           当我们的系统中引入了MQ之后,不得不考虑的一个问题是如何保证消息的顺序性,这是一个至关重要的事情,如果顺序错乱了,就会导致数据的不一致。

           比如:业务场景是这样的:我们需要根据mysql的binlog日志同步一个数据库的数据到另一个库中,加如在binlog中对同一条数据做了insert,update,delete操作,我们往MQ顺序写入了insert,update,delete操作的三条消息,那么根据分析,最终同步到另一个库中,这条数据是被删除了的。但是,如果这三条消息不是按照insert,update,delete顺序被消费,而是按照delete,insert,update的顺序被消费,那么最终这条数据是会保存到新库中的。这就导致了数据错乱了。下面分别讲解下RabbitMQ和Kafka是如何保证消息的顺序性。

    1、RabbitMQ如何保证消息顺序性

    1.1 RabbitMQ的消息不被顺序消费的情况

    注意:queue(队列)中的消息只能被一个消费者所消费,然后消费者在消费消息的过程中是无序的。如上图所示,如果按照BAC的消费顺序,那么最终数据库中是被保存这条数据的。这和我们预期的结果不符,如果这样的情况很多,那么就造成了数据库中的数据完成不对,同步工作也是白费了。

    1.2 RabbitMQ保证消息顺序性的措施

    如图所示,RabbitMQ保证消息的顺序性,就是拆分多个 queue,每个 queue 对应一个 consumer(消费者),就是多一些 queue 而已,确实是麻烦点;或者就一个 queue 但是对应一个 consumer,然后这个 consumer 内部用内存队列做排队,然后分发给底层不同的 worker 来处理。

     

    2、Kafka如何保证消息的顺序性

    2.1 Kafka出现消息顺序性错乱的情况

           首先要说明一些Kafka的特性:比如一个topic,有三个partition,生产者在写的时候可以指定一个key,假设以订单id作为key,那么这个订单key相关的数据,一定会被分发到同一个partition中去,并且是有序的。同时消费者从 partition 中取出来数据的时候,也一定是有顺序的。

           还以上面的RabbitMQ一样的业务场景来说明Kafka出现消息没有顺序性的情况:假设订单id作为key的三条消息分别是执行:insert,update,delete操作。如果是按这个顺序执行的话,最终同步到其他库之后,这条数据是不存存在的。从Kafka的特性可以知道,这三条消息会分到一个partition中,一个消费者去消费这个partition中的数据,这个时候都能说是有序的。但是,单线程的情况下,吞吐量很低,一秒钟可能只能处理十多条消息,所以一般会采用多线程去提高吞吐量。线程之间的执行顺序和速度就不能保证有序了,如果thread1是拿到的delete,然后执行了,thread2拿到的消息是insert,然后执行,thread3拿到的消息是update,然后执行,所以最终这个订单的数据是会存到新库中的。这和原有的业务需求是不符合的。如图所示:

    2.2 Kafka如何保证消息有序性

    每个线程都只从一个内存队列中取数据,都相关的数据都存到同一个内存队列中,就保证了数据的有序性。

    展开全文
  • 代码之谜()- 浮点数(谁偷了你的精度?)

    万次阅读 多人点赞 2012-11-13 12:27:14
    什么是 2 和 5 呢?因为他们是 10 的因子 10 = 2 x 5。 二进制和十六进制呢?他们的因子只有 2,所以十六进制只是二进制的一种简写形式,它的精度和二进制一样。 如果一个十进制数可以用二进制精确表示...
    ****光棍节加长版**** 
    

    如果我告诉你,中关村配置最高的电子计算机的计算精度还不如一个便利店卖的手持计算器,你一定会反驳我:「今天写博客之前又忘记吃药了吧」。

    你可以用最主流的编程语言计算 0.2 + 0.4,如果你使用的是 Chrome、FireFox、IE 8+,可以按 F12 键,然后找到 「控制台」,输入上面的 表达式 0.2 + 0.4,回车。

    然后再用最简陋的计算器(如果你没有手持计算器没关系,手机、电脑都自带一个计算器,打开“运行”,输入calc,回车) 再计算一下刚才的 算式 0.2 + 0.4。

    怎么样?同意我的观点了吧! 再简陋的计算器也比超级计算器的精度高,关键不在于它的频率和内存,而在于它是如何设计、如何表示、如何计算的

    不能表示 VS 不能精确表示

    在上一章『浮点数(从惊讶到思考)』中我们讲到用浮点数表示  时出现的问题——很多数都 不能表示。(注意 浮点数表示的是数,而不仅仅是小数。)

    如果你数学比较好,或者你确信你身体健康,没有心脏病、高血压,没有受过重大精神创伤,那我告诉你, 在浮点数的表示范围内,有多于 99.999…% 的数在计算机中是 不能表示 的。 真的是太令人吃惊,也太令人遗憾了。 真相总是很残忍。

    请注意我使用的措辞,区别开 不能表示 和 不能精确表示

    下面我从数量级分析一下,32bit 浮点数的表示范围是 10 的 38 次方,而表示个数呢,是 10 的 10 次方。 能够被表示的数只有 1/100000000…. (大概有30个零),这个数多大呢?还记得那个国际象棋和麦子的故事吗?

    为了让你了解 指数的威力,我再举个例子:

    有一张很大很大的纸,对折 38 次,会有多高呢? 一米?一百米?比珠峰还高?再次考验你心脏承受能力的时刻到了:它不仅仅比珠峰高,其实它已经快到达月球了。

    回到原来的话题,还有更残忍的真相。 在剩下的可以表示的不到 0.000…1% 的数中,又有多少不能精确表示呢?这就是我写这篇博客的目的。

    上一章中我还给出了一种用定点数精确表示小数的方法。 事实上,手持计算器、java 中的 BigDecimal、C# 中的货币类型、MySQL 中的 NUMERIC 类型就是这么干的。 你还记得在数据库中添加字段时的 SQL 语句是如何写的吗?现在明白为什么我说 再简陋的计算器也比超级计算器的精度高 了吧。

    这篇博客我将为大家讲解为什么很多数 不能精确表示,本篇可能比较烧脑子,我会尽量用最通俗的语言,最贴近现实的例子来讲解,不在乎篇幅有多长,关键是要给大家讲明白。下一篇,你将了解到浮点数如何工作,以及为什么很多数 不能表示

    热身 —— 问:要把小数装入计算机,总共分几步?你猜对了,3 步。

    • 第一步:转换成二进制
    • 第二步:用二进制科学计算法表示
    • 第三步:表示成 IEEE 754 形式

    在上面的第一步和第三步都有可能 丢失精度

    十进制 VS 二进制

    下面我们讨论如何把十进制小数转换成二进制小数(什么?你不会?请自觉去面壁)。

    考虑我们将 1/7(七分之一) 写成小数的时候是如何做的?

    用 1 除以 7,得到的商就是小数部分,剩下的余数我们继续除以 7,一直除到什么时候结束呢? 有两种情况:

    1. 如果余数为 0。yeah!终于结束了,洗洗睡吧

    2. 当除到某一步时,余数等于 1… 停!stop!等一下,我发现有什么地方怪怪的。余数为 1,余数如果为 1 的话,再继续除下去,不就又是 1/7 了吗?绕了一个大弯,又回来了?对,你猜的很对,它永远不会结束,它循环了。

    注意我上面说的 情况2,我们判断他循环,并 不是从直观看感觉它重复了,而是因为在计算过程中,它又回到了开头。为什么这么说呢?当你计算一个分数时,它总是连续出现 5,出现了好多次,例如 0.5555555… 你也无法断定它是无限循环的,比如 一亿分之五。

    记得高中时,从一本数学课外书学到了手动开平方的方法,于是很兴奋的去计算 2 的平方根,发现它的前几位是 1.414,哇,原来「2的平方根」等于 1.414141…。很多天以后,当我再次看到我的笔记时,只能苦笑了,「2的平方根」不可能循环啊,它可是一个无理数啊。

    你可能不耐烦了,叽哩哇啦说这么多,有用吗?当然有用了,以后如果 MM 问你:你会爱我到什么时候?你可以回答她:我会爱你到 1/7 的尽头。难道我会把我的表白方式告诉你们吗? 我对你的爱就像圆周率,无限——却永不重复。

    扯远了,现在会到主题。 你也许会说:我明白了,循环小数不能精确表示,放到计算机中会丢失精度; 那么有限小数可以精确表示吧,比如 0.1。

    对于无限小数,不只是计算机不能精确表示,即使你用别的办法(省略号除外),比如纸、黑板、写字板…都无法精确表示。什么?手机?也不能,当然不能了。不,不,iPad也不行,1万买的也不行,真的,再贵的本子也写不下。

    哪些数能精确表示?

    那么 0.1 在计算机中可以精确表示吗?

    答案是出人意料的, 不能

    在此之前,先思考个问题: 在 0.1 到 0.9 的 9 个小数中,有多少可以用二进制精确表示呢?

    我们按照乘以 2 取整数位的方法,把 0.1 表示为二进制(我假设那些不会进制转换的同学已经补习完了):

    (1) 0.1 x 2 = 0.2  取整数位 0 得 0.0
    (2) 0.2 x 2 = 0.4  取整数位 0 得 0.00
    (3) 0.4 x 2 = 0.8  取整数位 0 得 0.000
    (4) 0.8 x 2 = 1.6  取整数位 1 得 0.0001
    (5) 0.6 x 2 = 0.2  取整数位 1 得 0.00011
    (6) 0.2 x 2 = 0.4  取整数位 0 得 0.000110
    (7) 0.4 x 2 = 0.8  取整数位 0 得 0.0001100
    (8) 0.8 x 2 = 1.6  取整数位 1 得 0.00011001
    (9) 0.6 x 2 = 1.2  取整数位 1 得 0.000110011
    (n) ...

    我们得到一个无限循环的二进制小数 0.000110011…

    我为什么要把这个计算过程这么详细的写出来呢?就是为了让你看,多看几遍,再多看几遍,继续看… 还没看出来,好吧,把眼睛揉一下,我提示你,把第一行去掉,从 (2) 开始看,看到 (6),对比一下 (2) 和 (6)。 然后把前两行去掉,从 (3) 开始看…

    明白了吧,0.2、0.4、0.6、0.8 都不能精确的表示为二进制小数。 难以置信,这可是所有的偶数啊!那奇数呢? 答案就是:

    0.1 到 0.9 的 9 个小数中,只有 0.5 可以用二进制精确的表示。

    如果把 0.0 再算上,那么就有两个数可以精确表示,一个奇数 0.5,一个偶数 0.0。 为什么是两个呢?因为计算机二呗,其实计算机还真够二的。

    世界上有 10 种人,一种是懂二进制的,一种是不懂二进制的。

    其实答案很显然,我再领大家换个角度思考,0.5 就是一半的意思。 在十进制中,进制的基数是 10,而 5 正好是 10 的一半。 2 的一半是多少?当然是 1 了。 所以,十进制的 0.5 就是二进制的 0.1。如果我用八进制呢? 不用计算你就应该立刻回答:0.4;转换成十六进制呢,当然就是 0.8 了。

    (0.5)10 = (0.1)2 = (0.4)8 = (0.8)16

    如果你还想继续思考,就又会发现一个有趣的事实,我们称之为 定理A。 我们上面的数,都是小数点后面一位小数,因此,在十进制中,这样的小数有 10 个(就是 0 到 9); 同理,在二进制中,如果我们让小数点后面有一位小数,应该有多少个呢?当然是 2 个了(0 和 1)。

    哇,好像发现了新大陆一样,很兴奋是吧。那我再给你一棒,其实定理A是错的。再重申一遍 尽信书,则不如无书。我写博客的目的 不是把我的思想灌输到你的脑子里,你应该有自己的思想,自己的思考方式,当我得出这个结论时,你应该立刻反驳我:“按照你的思路,如果是 16 进制的话,应该可以精确表示所有的 0.1 到 0.9 的数甚至还可以精确表示其它的 6 个数。而事实呢,16 进制可以精确表示的数 和 2 进制可以精确表示的数是一样的,只能精确表示 0.5。”

    那么到底怎么确定一个数能否精确表示呢?还是回到我们熟悉的十进制分数。

    1/2、5/9、34/25 哪些可以写成有限小数?把一个分数化到最简(分子分母无公约数),如果分母的因式分解只有 2 和 5,那么就可以写成有限小数,否则就是无限循环小数。为什么是 2 和 5 呢?因为他们是 10 的因子 10 = 2 x 5。

    二进制和十六进制呢?他们的因子只有 2,所以十六进制只是二进制的一种简写形式,它的精度和二进制一样。

    如果一个十进制数可以用二进制精确表示,那么它的最后一位肯定是 5。

    备注:这是个必要条件,而不是充分条件。一位热心网友设计出了下面的解决精度的方案。我就不解释了,同学们自己思考一下吧。

    我有一个观点,针对小数精度不够的问题(例如 0.1),软件可以人为的在数据最后一位补 5, 也就是 0.15,这样牺牲一位,但是可以保证数据精度,还原再把那个尾巴 5 去掉。

    请同学们思考一下。

    精度在哪儿丢失?

    一位热心网友 独孤小败 在 OSC 上回复了我上一篇文章,提出了一个疑问:

    在 java 中计算 0.2 + 0.4 得到的结果是

    // 代码(a)
    double d = 0.2 + 0.4;  // 结果是 0.6000000000000001

    但是当直接输出 0.6 的时候,确实是 0.6

    // 代码(b)
    double d = 0.6;  // 结果是 0.6

    好像很矛盾。很显然,通过代码(b)可以知道,在 java 中,可以精确 显示 0.6,哪怕 0.6 不能被精确表示,但至少能精确把 0.6 显示出来,这不是和代码(a)矛盾了吗?

    这又是一个 想当然的错误,在直观上认为 0.2 + 0.4 = 0.6 是必然成立的(在数学上确实如此),既然(a)的结果是 0.6,而且 java 可以精确输出 0.6,那么代码(a)的结果应该输出 0.6。

    其实在计算机上 0.2 + 0.4 根本就不等于 0.6 (为什么?可以查看本系列『运算符』),因为 0.2 和 0.4 都不能被精确表示。 浮点数的精度丢失在每一个表达式,而不仅仅是表达式的求值结果。

    我们用数学中的概念类比一下,比如四舍五入,我们计算 1.6 + 2.8 保留整数。

    1.6 + 2.8 = 4.4 

    四舍五入得到 4。我们用另一种方法

    先把 1.6 四舍五入为 2
    再把 2.8 四舍五入为 3
    最后求和 2 + 3 = 5

    通过两种运算,我们得到了两个结果 4 和 5。同理,在我们的浮点数运算中,参与运算的两个数 0.2 和 0.4 精度已经丢失了,所以他们求和的结果已经不是 0.6 了。

    后记

    上面一直在讨论小数,整数呢?在博客园,一位童鞋为下面的代码抓狂了:

    JSON.parse('{"status":1,"id":9986705337161735,"name":"test"}').id; 

    把这段代码复制到 Chrome 的 Console 中,按回车, 诡异的问题出现了 9986705337161735 居然变成了 9986705337161736!原始数据加了 1。

    9986705337161735
    9986705337161736

    一开始以为是溢出,换了个更大的数:9986705337161738 发现不会出现这个问题。

    但是 9986705337161739 输出又变成了 9986705337161740!

    9986705337161739
    9986705337161740

    测试几次之后发现浏览器输出数字的一个规律(justjavac注:其实这个规律是错误的):

    1. 十位数为偶数,个位数为奇数时会减 1,个位数为奇数时会加1
    2. 十位数为奇数,个位数为奇数时会加 1,个位数为奇数时会减1

    又多测了几次,发现根本没有规律,很混乱!!有时候是加,有时候是减!!

    解析

    这显然不仅仅是丢失精度的问题,欲知后事如何…咳咳…静待下一篇吧。

    展开全文
  • 1、为什么mybatis-spring框架中不直接使用线程安全的SqlSessionManager(SqlSessionFactory它是线程安全的)而是使用DefaultSqlSession这个线程不安全的类,并通过动态代理的方式来保证DefaultSqlSession操作的线程...

    一、DefaultSqlSession的线程不安全性

    在MyBatis架构中SqlSession是提供给外层调用的顶层接口,实现类有:DefaultSqlSession、SqlSessionManager以及mybatis-spring提供的实现SqlSessionTemplate。默认的实现类为DefaultSqlSession如。类图结构如下所示:
    这里写图片描述
    对于MyBatis提供的原生实现类来说,用的最多的就是DefaultSqlSession,但我们知道DefaultSqlSession这个类不是线程安全的!如下:
    这里写图片描述

    二、SqlSessionTemplate是如何使用DefaultSqlSession的

    而在我们开发的时候肯定会用到Spring,也会用到mybatis-spring框架,在使用MyBatis与Spring集成的时候我们会用到了SqlSessionTemplate这个类,例如下边的配置,注入一个单例的SqlSessionTemplate对象:

    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    	<constructor-arg ref="sqlSessionFactory" />
    </bean>
    

    SqlSessionTemplate的源代码注释如下:
    这里写图片描述
    这里写图片描述
    通过源码我们何以看到 SqlSessionTemplate实现了SqlSession接口,也就是说我们可以使用SqlSessionTemplate来代理以往的DefaultSqlSession完成对数据库的操作,但是DefaultSqlSession这个类不是线程安全的,所以DefaultSqlSession这个类不可以被设置成单例模式的。

    如果是常规开发模式的话,我们每次在使用DefaultSqlSession的时候都从SqlSessionFactory当中获取一个就可以了。但是与Spring集成以后,Spring提供了一个全局唯一的SqlSessionTemplate对象来完成DefaultSqlSession的功能,问题就是:无论是多个Dao使用一个SqlSessionTemplate,还是一个Dao使用一个SqlSessionTemplate,SqlSessionTemplate都是对应一个sqlSession对象,当多个web线程调用同一个Dao时,它们使用的是同一个SqlSessionTemplate,也就是同一个SqlSession,那么它是如何确保线程安全的呢?让我们一起来分析一下:

    三、SqlSessionTemplate是如何保证DefaultSqlSession线程安全的

    (1)首先,通过如下代码创建代理类,表示创建SqlSessionFactory的代理类的实例,该代理类实现SqlSession接口,定义了方法拦截器,如果调用代理类实例中实现SqlSession接口定义的方法,该调用则被导向SqlSessionInterceptor的invoke方法(代理对象的InvocationHandler就是SqlSessionInterceptor,如果把它命名为SqlSessionInvocationHandler则更好理解!)
    这里写图片描述
    核心代码就在 SqlSessionInterceptor的invoke方法当中。

    private class SqlSessionInterceptor implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) 
                throws Throwable {
            //获取SqlSession(这个SqlSession才是真正使用的,它不是线程安全的)
            //这个方法可以根据Spring的事物上下文来获取事物范围内的sqlSession
            SqlSession sqlSession = getSqlSession(
                    SqlSessionTemplate.this.sqlSessionFactory,
                    SqlSessionTemplate.this.executorType,
                    SqlSessionTemplate.this.exceptionTranslator);
            try {
                //调用从Spring的事物上下文获取事物范围内的sqlSession对象
                Object result = method.invoke(sqlSession, args);
                //然后判断一下当前的sqlSession是否被Spring托管 如果未被Spring托管则自动commit
                if (!isSqlSessionTransactional(sqlSession, 
                        SqlSessionTemplate.this.sqlSessionFactory)) {
                    // force commit even on non-dirty sessions because some databases require
                    // a commit/rollback before calling close()
                    sqlSession.commit(true);
                }
                return result;
            } catch (Throwable t) {
                //如果出现异常则根据情况转换后抛出
                Throwable unwrapped = unwrapThrowable(t);
                if (SqlSessionTemplate.this.exceptionTranslator != null && 
                        unwrapped instanceof PersistenceException) {
                    // release the connection to avoid a deadlock if the 
                    // translator is no loaded. See issue #22
                    closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                    sqlSession = null;
                    Throwable translated = SqlSessionTemplate.this.exceptionTranslator.
                            translateExceptionIfPossible((PersistenceException) unwrapped);
                    if (translated != null) {
                        unwrapped = translated;
                    }
                }
                throw unwrapped;
            } finally {
                if (sqlSession != null) {
                    //关闭sqlSession,它会根据当前的sqlSession是否在Spring的事物上下文当中来执行具体的关闭动作
                    //如果sqlSession被Spring管理 则调用holder.released();
                    //使计数器-1,否则才真正的关闭sqlSession
                    closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
                }
            }
        }
    }
    

    在上面的invoke方法当中使用了两个工具方法分别是:

    (1)SqlSessionUtils.getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator)
    (2)SqlSessionUtils.closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory)
    

    那么这两个方法又是如何与Spring的事物进行关联的呢?

    1、getSqlSession方法如下:

    public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, 
            ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
    
        notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
        notNull(executorType, NO_EXECUTOR_TYPE_SPECIFIED);
    
        //根据sqlSessionFactory从当前线程对应的资源map中获取SqlSessionHolder,
        // 当sqlSessionFactory创建了sqlSession,
        //就会在事务管理器中添加一对映射:key为sqlSessionFactory,value为SqlSessionHolder,
        // 该类保存sqlSession及执行方式
        SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.
                getResource(sessionFactory);
    
        //从SqlSessionHolder中提取SqlSession对象
        SqlSession session = sessionHolder(executorType, holder);
        if (session != null) {
            return session;
        }
    
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Creating a new SqlSession");
        }
        //如果当前事物管理器中获取不到SqlSessionHolder对象就重新创建一个
        session = sessionFactory.openSession(executorType);
    
        //将新创建的SqlSessionHolder对象注册到TransactionSynchronizationManager中
        registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
    
        return session;
    }
    

    2、closeSqlSession方法如下:

    //删除了部分日志代码
    public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
            //其实下面就是判断session是否被Spring事务管理,如果管理就会得到holder
            SqlSessionHolder holder = (SqlSessionHolder) 
            TransactionSynchronizationManager.getResource(sessionFactory);
            if ((holder != null) && (holder.getSqlSession() == session)) {
                //这里释放的作用,不是关闭,只是减少一下引用数,因为后面可能会被复用 
                holder.released();
            } else {
                //如果不是被spring管理,那么就不会被Spring去关闭回收,就需要自己close 
                session.close();
            }
        }
    

    大致的分析到此为止,可能有些许不够顺畅,不过:纸上得来终觉浅,绝知此事要躬行!还希望小伙伴打开自己的编译器,找到此处的代码,认真走一遍流程!

    其实通过上面的代码我们可以看出Mybatis在很多地方都用到了代理模式,代理模式可以说是一种经典模式,其实不紧紧在这个地方用到了代理模式,Spring的事物、AOP、Mybatis数据库连接池技术、MyBatis的核心原理(如何在只有接口没有实现类的情况下完成数据库的操作!)等技术都使用了代理技术。

    四、SqlSessionManager又是什么鬼?

    上述说了SqlSession的实现还有一个SqlSessionManager,那么SqlSessionManager到底是什么个东西哪?且看定义如下:
    这里写图片描述
    你可能会发现SqlSessionManager的构造方法竟然是private的,那我们怎么创建这个对象哪?其实SqlSessionManager创建对象是通过newInstance的方法创建对象的,但需要注意的是他虽然有私有的构造方法,并且提供给我们了一个公有的newInstance方法,但它并不是一个单例模式!

    newInstance有很多重载的方法,如下所示:
    这里写图片描述
    SqlSessionManager的openSession方法及其重载的方法是直接通过调用其中底层封装的SqlSessionFactory对象的openSession方法来创建SqlSession对象的,重载方法如下:
    这里写图片描述
    SqlSessionManager中实现了SqlSession接口中的方法,例如:select、update等,都是直接调用sqlSessionProxy代理对象中相应的方法。在创建该代理对像的时候使用的InvocationHandler对象是SqlSessionInterceptor,他是定义在SqlSessionManager的一个内部类,其定义如下:
    这里写图片描述

    五、总结

    综上所述,我们应该大致了解了DefaultSqlSession和SqlSessionManager之间的区别:

    1、DefaultSqlSession的内部没有提供像SqlSessionManager一样通过ThreadLocal的方式来保证线程的安全性;

    2、SqlSessionManager是通过localSqlSession这个ThreadLocal变量,记录与当前线程绑定的SqlSession对象,供当前线程循环使用,从而避免在同一个线程多次创建SqlSession对象造成的性能损耗;

    3、DefaultSqlSession不是线程安全的,我们在进行原生开发的时候,需要每次为一个操作都创建一个SqlSession对象,其性能可想而知;

    六、扩展面试题

    那么问题来了:

    1、为什么mybatis-spring框架中不直接使用线程安全的SqlSessionManager(SqlSessionFactory它是线程安全的)而是使用DefaultSqlSession这个线程不安全的类,并通过动态代理的方式来保证DefaultSqlSession操作的线程安全性哪?

    2、DefaultSqlSession中是如何通过Executor来表现策略模式的或者DefaultSqlSession如何使用策略模式模式的?

    在这里插入图片描述

    【视频福利】2T免费学习视频,搜索或扫描上述二维码关注微信公众号:Java后端技术(ID: JavaITWork)回复:1024,即可免费获取!内含SSM、Spring全家桶、微服务、MySQL、MyCat、集群、分布式、中间件、Linux、网络、多线程,Jenkins、Nexus、Docker、ELK等等免费学习视频,持续更新!

    展开全文
  • 层网络协议,各层功能,各层协议

    万次阅读 多人点赞 2018-05-11 11:21:01
    一、OSI七层模型OSI七层协议模型主要是:应用层(Application)、表示层...三、层体系结构层体系结构包括:应用层、运输层、网络层、数据链路层和物理层。 层协议只是OSI和TCP/IP的综合,实际应用还是TCP/I...
  • TCP/IP层模型

    千次阅读 2018-08-06 12:11:58
    它是把OSI七层模型简化成了层模型。每一层都呼叫它的下一层所提供的网络来完成自己的需求。 应用层:负责应用程序间的沟通。如:简单电子邮件传输(SMTP),文件传输控制协议(FTP),网络远程访问协议(Telnet)...
  • 什么volatile也无法保证线程安全

    万次阅读 2017-12-05 18:11:07
    volatile修饰的关键字在操作的时候必须是在指定位置的,即如果这个变量的操作在第行那会保证前四行都执行完才会执行第行。 ------------------------------------------------------------------...
  • 学习英语的好处不言而喻,打破这层壁垒就会让你感受到真正的世界的样子,去那些纯英文的编程网站,BBS,讨论组,个人博客,增长见识的同时是你在逐步的认清这个世界,知道外面的人在做什么在想什么,现如今的潮流是...
  • vuex的个属性,分别是什么,区别和用途说一下 这个地方回答的不是很好,思路有点混乱 所以就打算整理一下 查了一下官网,关于vuex的个属性还是有很多知识点的 官网:https://vuex.vuejs.org/zh/guide/ 01 前言...
  • 如何保证库存在高并发的场景下是安全的? (1)不多发 (2)不少发 二、 下单的步骤 (1)下单 (2)下单同时预占库存 (3)支付 (4)支付成功真正减扣库存 (5)取消订单 (6)回退预占库存 三、 ...
  • 软件质量保证

    千次阅读 2013-05-17 12:43:13
    软件质量保证(SQA)是建立一套有计划,有系统的方法,来向管理层保证拟定出的标准、步骤、实践和方法能够正确地被所有项目所采用。软件质量保证的目的是使软件过程对于管理人员来说是可见的。它通过对软件产品和...
  • 网络层模型

    千次阅读 2018-09-01 21:52:57
    TCP/IP层模型 应用层: HTTP,HTTPS协议,其中HTTP没有对数据进行加密操作,但是HTTPS对数据进行了加密操作 其中HTTP端口号一般是80/8080等等,HTTPS端口号是443,SSH端口号一般是22,ftp是21 HTTP协议报头: 首行:...
  • 鱼水八情深,四六相约二定来是什么意思指什么含义怎么理解答!! 防火墙: 保证数据的安全性是继数据可用性之后的最为重要的一项工作 防火墙作为公网和内网之间的保护屏障 防火墙种类: 硬件防火墙:网关...
  • 为了防止不符合规范的数据进入数据库,在用户对数据进行插入、修改...#种完整性约束: #NOT NULL :非空约束,指定某列不能为空; #UNIQUE : 唯一约束,指定某列或者几列组合不能重复 #PRIMARY KEY :主键,指定该
  • 如何保证测试质量

    千次阅读 2019-06-11 15:33:43
    当进入测试执行阶段之后,作为测试项目的管理人员,即使知道怎么很好的管理执行进度,但也还是有一个头痛的问题无法回避,那就是怎么保证执行的质量呢? 项目管理的大过程组中,有个贯穿全流程的过程组,也是整个...
  • 程序员的奋斗史()——谦逊才是王道

    千次阅读 热门讨论 2012-05-14 00:39:41
    不管你有多厉害,都要保证谦逊和低调。因为在你的上面比你厉害的人多得是。你算不上什么。要做永远的现实小弟,理想老大。在现实生活中,把自己当做一个弱者,但是在心里要有一颗梦想,你就是最厉害的。
  • 过程质量保证的范围是什么? 过程质量保证是指不同于测试的、主要针对过程和中间工作产物的质量保证,一般而言,早年间的过程质量保证根据最早的CMM,也称为软件质量保证,缩写为SQA。现在最新的CMMI将其对应的...
  • TCP/IP层协议体系结构的各层功能

    万次阅读 2018-03-15 19:51:28
    层协议体系结构的各层功能1 第层——应用层(application layer)应用层(application layer):是体系结构中的最高。直接为用户的应用进程提供服务。在因特网中的应用层协议很多,如支持万维网应用的HTTP协议,支持...
  • 系统运维大要素

    千次阅读 2016-11-17 13:56:25
    争中获胜,必须保证这些系统能够全天候24小时处于开启状态并且拥有很快的速度。所以,在系统 运维方面有个非常重要的要素:可靠性、性能、可扩展性、安全性以及成本节约。 许多公司只关注某一
  • 【死磕JVM】年 整整年了 该知道JVM加载机制了!

    千次阅读 多人点赞 2021-02-27 10:04:36
    ,在Java虚拟机规范中没有进行强制约束,而是交给虚拟机的具体实现来进行把握,但是对于初始化阶段,虚拟机规范严格规定了 “有且只有” 种情况必须立即对类进行初始化(而加载、验证、准备自然需要在此之前开始)...
  • 计算机网络层模型详解

    千次阅读 2020-06-02 17:25:25
    目录 网络概述: 1.网络通信的层次 2.OSI七层网络模型 3.TCP层模型: 一、物理层 1.物理层作用 2.物理层概述 3.信号调制 4.信道复用技术 二、数据链路层 1.数据链路层作用 ...、...
  • 发送消息阶段涉及到Producer到broker的网络通信,因此丢失消息的几率一定会有,那RocketMQ在此阶段用了哪些手段保证消息不丢失了(或者说降低丢失的可能性)。 手段一:提供SYNC的发送消息方式,等待broker处理结果...
  • 计算机网络 第章答案 复习(运输层)

    万次阅读 多人点赞 2018-12-28 22:26:06
    1.试说明运输层在协议栈中的地位和作用,运输层的通信和网络层的通信有什么重要区别?为什么运输层是必不可少的?  答: 运输层处于面向通信部分的最高层,同时也是用户功能中的最低层,向它上面的应用层提供...
  • 手头有万左右,想做小生意,有什么值得推荐的? 创业首先要定位自己和市场,根据个人擅长去选择致富之路。万块钱可以投资的生意不少,要根据自身能力结合当地市场去选择。 如校园小店、街边休闲水吧、一元店、...
  • IM消息送达保证机制实现(二):保证离线消息的可靠投递
  • 章 1.请画出例5.6中给出的3个程序段的流程图 流程图1: 流程图2: 流程图3: 2.请补充例5. 7程序,分别统计当“fabs(t)>= le- 6”和“fabs(t)> = le- 8”时执行循环体的次数。 fabs(t)>= le- 6 ,...
  • LinkedHashMap如何保证顺序性

    千次阅读 2019-07-13 15:46:44
    LinkedHashMap使用的也较为频繁,它基于HashMap,用于HashMap的特点,又增加了双链表的结构,从而保证了顺序性,本文主要从源码的角度分析其如何保证顺序性,accessOrder的解释,以及常用方法的阐释
  • ConcurrentHashMap 能否保证绝对的线程安全?

    千次阅读 多人点赞 2020-02-29 20:04:11
    步,最后操作完整之后,释放对象锁; 我们再来看看,上面提到的 scanAndLockForPut 这个方法,源码如下: scanAndLockForPut 这个方法,操作也是分以下几步: 当前线程尝试去获得锁,查找 key 是否已经存在,...
  • 层协议体系结构的各层功能

    万次阅读 多人点赞 2016-01-26 22:37:44
    层协议体系结构的各层功能 1 第层——应用层(application layer) 应用层(application layer):是体系结构中的最高。直接为用户的应用进程提供服务。 在因特网中的应用层协议很多,如支持万维网应用的HTTP协议...
  • 小程序突破层限制的方法

    千次阅读 2017-06-20 17:50:32
    小程序突破层限制 客户列表-->添加一次操作没有问题,如果多次添加会累加界面 如果关闭的方式,返回按钮又会直接返回到上上层。 1、解决方案,添加完,用 wx.navigateBack 方法返回 2、(脑洞有点打开可以...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 704,686
精华内容 281,874
关键字:

五保证是什么