利用MRT进行多年LAI数据(MOD15A2)拼接和投影转换

最近需要处理连续10年的MODIS LAI产品数据(MOD15A2)。根据自己的需求,写了一个MS-DOS批处理小程序,主要解决的问题是:YEAR和DOY两重循环,并将YEAR和DOY连接成YEAR+DOY的形式(如2001001)用以搜索符合条件的待拼接文件。 需要注意的地方(代码中红色标注处): 1、用set设置数据文件夹环境变量时,等号的前后都不能出现空格。如果等号前面有空格,则环境变量名称变为“MRTDATADIR ”,如果等号后有空格,则数据文件夹路径前面多出空格会导致MRT工具找不到相关数据文件。 2、DOY的设置采用了“曲线救国”方案,即先设置为10001的形式,然后截取最后三个字符作为标准DOY。 3、DOS下的字符截取操作:%DOY:~-3%表示截取DOY变量的最后三个字符,等效于%DOY:~4,3%,表示从DOY变量的第5个字符开始截取3个字符。 4、进行YEAR的循环时需要对DOY进行初始化。 代码如下: @echo off rem **This is a MS-DOS batch file to do multi-yearly mosaicing and resampling preprocessing by using MRT rem **author: pengbin, institute of remote sensing and digital earth, CAS rem **Memo: developed at May 7th, 2013 rem **Set the MRTDATADIR environmental var to the MRT data directory. set MRTDATADIR=D:\MOD15A2_h24-26_v4-5 rem **set batch data start time set /a YEAR = 2001

OSS介绍

1 基本概念介绍 1.1 存储空间(Bucket) 存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。您可以设置和修改存储空间属性用来控制地域、访问权限、生命周期等,这些属性设置直接作用于该存储空间内所有对象,因此您可以通过灵活创建不同的存储空间来完成不同的管理功能。 同一个存储空间的内部是扁平的,没有文件系统的目录等概念,所有的对象都直接隶属于其对应的存储空间。每个用户可以拥有多个存储空间。存储空间的名称在 OSS 范围内必须是全局唯一的,一旦创建之后无法修改名称。存储空间内部的对象数目没有限制。 存储空间的命名规范如下: 只能包括小写字母,数字和短横线(-)。必须以小写字母或者数字开头。长度必须在3-63字节之间。 1.2 对象/文件(Object) 对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。对象由元信息(Object Meta),用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的 Key 来标识。对象元信息是一个键值对,表示了对象的一些属性,比如最后修改时间、大小等信息,同时用户也可以在元信息中存储一些自定义的信息。 根据不同的上传方式,对象的大小限制是不一样的。分片上传 最大支持 48.8TB 的对象大小,其他的上传方式最大支持 5GB。 对象的生命周期是从上传成功到被删除为止。在整个生命周期内,对象信息不可变更。重复上传同名的对象会覆盖之前的对象,因此,OSS 不支持修改文件的部分内容等操作。 OSS 提供了 追加上传 功能,用户可以使用该功能不断地在Object尾部追加写入数据。 对象的命名规范如下: 使用UTF-8编码。长度必须在1-1023字节之间。不能以“/”或者“\”字符开头。对象名称需要区分大小写。如无特殊说明,本文档中的对象、文件称谓等同于 Object。 1.3 Region(区域) Region 表示 OSS 的数据中心所在的区域,物理位置。用户可以根据费用、请求来源等综合选择数据存储的 Region。一般来说,距离用户更近的 Region 访问速度更快。详细请查看 OSS 已经开通的 Region。 Region是在创建 Bucket 的时候指定的,一旦指定之后就不允许更改,该 Bucket 下所有的 Object 都存储在对应的数据中心,目前不支持 Object 级别的 Region 设置。 1.4 Endpoint(访问域名) Endpoint 表示 OSS 对外服务的访问域名。OSS 以 HTTP RESTful API 的形式对外提供服务,当访问不同的 Region 的时候,需要不同的域名。通过内网和外网访问同一个 Region 所需要的 Endpoint 也是不同的。例如杭州 Region 的外网 Endpoint 是 oss-cn-hangzhou.

Java中使用Jedis操作Redis—Redis快速入门

这里先说Java中使用Jedis操作Redis,稍后会整理Redis快速入门来详细介绍Redis(跟着项目走会更容易理解)。 Java连接Redis: 在Java程序中使用Redis之前,我们需要先确保在机器上安装了Redis服务及Java Redis驱动程序,并且你的机器上能够正常使用Java环境。 1、Java的安装配置参考-Java开发环境配置-(略) 2、安装Redis服务 1)、下载Redis: Redis 官网 :http://redis.io/ 下载页面:http://redis.io/download 官方文档:http://redis.io/documentation Windows_64位 版本下载:https://github.com/ServiceStack/redis-windows/tree/master/downloads点击打开链接 2)、配置Redis: 下载完成后,在C盘【Program Files】目录下新建文件夹【Redis】,右键解压redis ZIP包,把所有文件解压到Redis文件夹中。 文件介绍: redis-benchmark.exe #基准测试 redis-check-aof.exe # aof redischeck-dump.exe # dump redis-cli.exe # 客户端 redis-server.exe # 服务器 redis.windows.conf # 配置文件 3)、启动Redis: 进入cmd操作系统窗口 使用【redis-server.exe redis.windows.conf】启动redis服务。 服务启动成功状态 启动redis服务的doc窗口,不用关闭,因为服务需要一直执行,关闭服务,直接关闭窗口就行。 4)、测试Redis: 新打开一个doc窗口,用自带的客户端工具进行测试命令【redis-cli.exe】,启动redis客户端,如下 3、下载Java redis驱动包(jedis.jar),确保下载最新驱动包,项目中引入jar包 1)、首先在项目下创建一个文件夹,保存我们的jar包 在项目名上右击,依次点击【new】-->【folder】,打开新建文件夹窗口。 2)、输入文件夹名称【lib】,点击【ok】,我们通常在lib文件夹中存放从外部引入的jar包。 3)、找到我们要引入的jar包,拖进lib文件夹中或者复制,打开选择框,我们选择默认的【copy fiels】,点击【OK】关闭。 4)、此时,项目中看到的jar包只是复制到项目下,还不能使用 再在项目名称上右击,依次选择【Build Path】-->【Configure Build Path...】。 5)、在打开的窗口中,先选择【Libraries】页,再从右边的按钮中点击【Add JARs...】 6)、在打开的窗口中,我们依次展开本项目的lib文件夹,然后选择我们刚才复制到项目中的jar包,然后点击【OK】关闭窗口。 7)、此时,我们在刚才打开的【Libraries】页可以看到我们引入的jar包的名称,点击【OK】确认关闭窗口。 8)、现在,我们就可以在项目中使用这个jar包了。 Java连接到Redis服务器: 参考以下示例代码: package redis; import redis.clients.jedis.Jedis; public class RedisTest {

Android 底部导航栏中间凸起、动态配置替换底部导航栏Tab图标(按钮、标签)的实现方案

标签:底部导航栏中间凸起、动态配置底部导航、底部导航中间大圆圈 类似 京东 淘宝 等app,在一些节假日的时候,首页UI 一般都是配置的节日气息很浓重,这类的实现一般是不需要发版,思路是 由后台直接配置,第一次开启App后台下载,在下次打开时 直接展示下载的图标。 思路分析 一般默认 一套普通图标平日展示使用, 后台下载一套新的图标,固定时间段展示使用。 比如 淘宝 假设下面这个是节日展示的底部导航 实现原理: 1.开启应用 ,后台下载活动图标。 2.下次打开应用,检测是否要展示。 3.底部导航实现,这里以RadioButton 为例, RadioButton 自带选中和默认 两种状态,所以只要我们将下载下来的图标做成selector选择器设置给RadioButton , 我们就可以实现替换图标的需求。 实现分析细节补充: 1. 启动页 请求后台图标接口,判断后台下载图标。 2.启动时, 检测下载图标是否完整,一定要下载完全,如果不完整,则展示出现问题,需要重新下载。 3.如果已经下载到本地,并且校验符合条件,则 加载本地图标生成Drawable,然后设置给Selector,然后将Selector 添加到 相应的RadioButton 上面。 圖片的下載比較容易,不做介紹,只介紹生成select部分: //代碼生成Selector StateListDrawable drawable = new StateListDrawable(); drawableDefault = new BitmapDrawable(bitmap); drawableChecked);= new BitmapDrawable(bitmap); drawable.addState(new int[]{android.R.attr.state_checked}, drawableChecked); drawable.addState(new int[]{ - android.R.attr.state_checked}, drawableDefault); // 將生成的Selector 添加到RadioButton 上面 drawable.setBounds(0,0,DimenUtil.dipToPx(context,30),DimenUtil.dipToPx(context,30)); radioButton.setCompoundDrawables(null,drawable,null,null); 下面是效果展示: https://github.com/CodingForAndroid/AutoBottomBar 谢谢认真观读本文的每一位小伙伴,衷心欢迎小伙伴给我指出文中的错误,也欢迎小伙伴与我交流学习。 [点击链接加入群聊【编程之美】: https://jq.

Java的反射机制

反射机制: Java反射机制:是在运行状态中,对于任意一个类,都能够知道该类的所有属性和方法;对于任意一个对象,都能够调用它的任意属性和方法;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。 Java反射(放射)机制:”程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言 "。从这个观点看,Java并不是动态语言,但是Java有一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整结构(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。因此,Java反射是Java被视为动态语言的一个关键性质。 反射机制的必要性: 1、在涉及某些应用程序时,往往需要动态升级以增加修改工程,而在静态编译体系中一切升级操作都需要对源码进行修改,这就意味着每一次升级就要对整个源代码编译一次。而如果是些大程序编译一次要几小时甚至几天才能完成,如此,显然纯静态的编程方式不太适合。而java是一门静态语言,为了弥补这个缺点,就有了反射机制。 2、Java更多的情况是应用于服务端程序,而服务器上的程序是不能关掉的,即使关掉也要提前给用户通知,但是,如果此时又要对系统进行升级,既要保证体系内其他功能正常运行,还要保证系统升级措施,就可以用发射机制来实现。 3、程序更加清晰,将主程序和功能程序分离,便于后期维护管理。 反射机制的应用: 1、杀毒软件病毒库的在线升级。 2、JDBC数据桥的构建(Class.forName(“数据库驱动包类名称”))。 3、应用程序功能的增加。 4、分析泛型的实质。 5、分析程序,找bug。 反射机制三种实现方式: 1、得到类类型,同时加载类Class class = Class.forName("SomethingName")。 2、已知类对象,由对象得到其所属类Class class = new Demo().getClass(). 3、直接由类得到其类对象Class class = Demo.Class。 反射相关类: 1、Class类,用来处理类级别的反射。 2、Field类,用来处理成员变量级的反射。 3、Method类,用来处理方法级的反射。 4、Constructor类,用来处理构造器的反射。 Java反射机制提供了什么功能: 1、获取类的Class对象 2、获取类的Fields 3、获取类的Method 4、获取类的Constructor 5、新建类的实例 注:在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。 获取类的Class对象: 1)、调用getClass Boolean var1 = true; Class<?> classType1 = var1.getClass(); System.out.println(classType1); //输出:class java.lang.Boolean 2)、运用.class语法 Class<?> classType2 = Boolean.class; System.out.println(classType2); //输出:class java.lang.Boolean 3)、运用static method Class.forName() Class<?> classType3 = Class.forName("java.lang.Boolean"); System.out.println(classType3);

Java的内存分配机制(初步整理)

Java程序是运行在Java虚拟机(Java Virtual Machine,JVM)上的,可以把JVM理解为Java程序和操作系统之间的桥梁,JVM实现了Java的跨平台,Java内存分配原理一切都是在JVM中进行的,JVM是内存分配原理的基础与前提。 一个完整的Java程序运行过程会涉及以下内存区域: 寄存器:JVM内部虚拟寄存器,存取速度非常快,程序不可控制。 栈内存:保存局部变量的值。在函数中定义的一些基本数据类型的变量和对象的引用变量都是在函数的栈内存中分配,当一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如:在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销毁,分配给它的内存会被收回),Java会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。 堆内存:用来存放Java世界中几乎所有的对象实例(如new创建的对象和数组,注意:创建出来的对象只包含属于各自的成员变量,不包括成员方法,因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是它们共享该类的方法,并不是每创建一个对象就把成员方法复制一次),在堆中分配内存,由Java虚拟机的自动垃圾回收器(GC)来管理。在堆中产生了一个对象或数组后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或是对象在堆内存中的首地址,栈中的这个变量就成了对象或数组的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的对象或数组,引用变量就相当于为对象或数组取的一个名称。引用变量是普通变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而对象或数组本身在堆中分配,即使程序运行到使用new产生对象或数组的语句所在的代码块之外,对象或数组本身所占据的内存不会被释放,对象和数组在没有引用变量指向它的时候才变为垃圾,不能再被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器(GC)收走。这也是Java比较占内存的原因,实际上,栈中的变量指向堆内存中变量就是Java中的指针。 常量池:JVM为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用(*)。池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。常量池存在于堆中。 代码段:用来存放从硬盘上读取的源程序代码。 数据段:用来存放static定义的静态成员,一直占用内存。 内存表示图: 预备知识: 1、一个Java文件,只要有main入口方法,我们就认为这是一个Java程序,可以单独编译运行。 2、无论是普通类型的变量还是引用类型的变量(俗称实例),都可以作为局部变量,他们都可以出现在栈中。只不过普通类型的变量在栈中直接保存它所对应的值,而引用类型的变量保存的是一个指向堆区的指针,通过这个指针,就可以找到这个实例在堆区对应的对象。因此普通类型变量只在栈区占用一块内存,而引用类型变量要在栈区和堆区各占一块内存。 示例: 1)、JVM自动寻找main方法,执行第一句代码,创建一个Test类的实例,在栈中分配一块内存,存放一个指向堆区对象的指针110925。 2)、创建一个int型的变量date,由于是基本类型,直接在栈中存放date对应的值9。 3)、创建两个BirthDate类的实例d1和d2,在栈中分别存放了对应的指针指向各自的对象,他们在实例化时调用了有参数的构造方法,因此对象中有自定义初始值。 调用test对象的change1方法,并且以date为参数。JVM读到这段代码时,检测到 i 是局部变量,因此会把 i 放到栈中,并且把date的值赋给 i 。 把1234赋给 i 。很简单的一步。 change1方法执行完毕,立即释放局部变量 i 所占用的栈空间。 调用test对象的change2方法,以实例d1为参数,JVM检测到change2方法中的b参数为局部变量,立即加入到栈中,由于是引用类型的变量,所以b中保存的是d1中的指针,此时b和d1指向同一个堆中的对象。在b和d1之间传递是指针。 change2方法中又实例化了一个BirthDate对象,并且赋给b。在内部的执行过程是:在堆区new了一个对象,并且把该对象的指针保存在栈中的b对应空间,此时实例b不再指向实例d1所指向的对象,但是实例d1所指向的对象并无变化,这样无法对d1造成任何影响。 change2方法执行完毕,立即释放局部引用变量b所占的栈空间,注意只是释放了栈空间,堆空间要等到自动回收。 调用test实例的change3方法,以实例d2为参数,同理,JVM会在栈中为局部引用变量b分配空间,并且把d2中的指针存放在b中,此时d2和b指向同一个对象。再调用实例b的setDay方法,其实就是调用d2指向的对象的setDay方法。 调用实例b的setDay方法会影响d2,因为二者指向的是同一个对象。 change3方法执行完毕,立即释放局部引用变量b。 以上就是Java程序运行时内存分配的大致情况,就是两种类型的变量:基本类型和引用类型。二者作为局部变量,都放在栈中,基本类型直接在栈中保存值,引用类型只保存一个指向堆区的指针,真正的对象在堆里。作为参数时基本类型就直接传值,引用类型传指针。 小结: 1、分清楚什么是实例什么是对象。 Class a = new Class();此时a叫实例,而不能说是对象。实例在栈中,对象在堆中,操作实例实际上是通过实例的指针间接操作对象。多个实例可以指向同一个对象。 2、栈中的数据和堆中的数据销毁并不是同步的。方法一旦结束,栈中的局部变量立即销毁,但是堆中的对象不一定销毁。因为可能有其他变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才可以被销毁。 3、每一个应用程序都对应唯一的一个JVM实例,每一个JVM实例都有自己的内存区域,互不影响。并且这些内存区域是所有线程共享的。这里提到的栈和堆都是整体上的概念,这些堆栈还可以细分。以上的堆、栈、代码段、数据段等都是相对于应用程序而言的。 4、类的成员变量在位于数据段中一直占用内存。而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。 常量池的补充: 预备知识:基本类型和基本类型的包装类。基本类型有:byte、short、char、int、long、boolean。基本类型的包装类:Byte、Short、Character、Integer、Long、Boolean。注意区分大小写。二者的区别是:基本类型体现在程序中是普通变量,基本类型的包装类是类,体现在程序中是引用变量。因此二者在内存中的存储位置不同:基本类型存储在栈中,而基本类型的包装类存储在堆中。上面的这些包装类都实现了常量池的技术,另外两种浮点数类型的包装类则没有实现。另外,String类型也实现了常量池技术。 常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了类、方法、接口等中的常量,也包括字符串常量,如String s="java"这种申明方式,当然也可以扩充,执行器产生的常量也会放入常量池,因此认为常量池是JVM的一块特殊的内存空间。 常量池中除了包含代码中所定义的各种基本类型(如int、long等)和对象型(如String及数组)的常量值外,还包含一些以文本形式出现的符号引用(*),比如类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。 所以,与Java语言中的所谓的“常量”不同,class文件中的“常量”内容很丰富,这些常量集中在class中的一个区域存放,一个紧接一个,称为“常量池”。 示例: 结果: 结果分析: 1、i和i0均是普通类型(int)的变量,所以数据直接存储在栈中,而栈有一个很重要的特性:栈中的数据可以分享。当我们定义了int i = 40;,再定义int i0 = 40;,这时候会自动检查栈中是否有40这个数据,如果有,i0会直接指向i的40,不会再添加一个新的40。 2、i1和i2均是引用类型,在栈中存储指针,因为Integer是包装类。由于Integer包装类实现了常量池技术,因此i1、i2的40均是从常量池中获取的,均指向同一个地址,因此i1=i2。 3、很明显这是一个加法运算,Java的数学运算都是在栈中进行的,Java会自动对i1、i2进行拆箱操作转化成整形,因此i1在数值上等于i2+i3。 4、i4和i5均是引用类型,在栈中存储指针,因为Integer是包装类。但是由于他们各自都是new出来的,因此不再从常量池寻找数据,而是从堆中各自new一个对象,然后各自保存指向对象的指针,所以i4和i5不相等,因为他们所存指针不同,所指向对象不同。 5、这是一个加法运算,和3同理。 6、d1和d2均是引用类型,在栈中存储指针,因为Double是包装类。但Double包装类没有实现常量池技术,因此Double d1 = 1.

数据库操作之同时一条sql删除两个表格中的数据

先骂一顿csdn吧,虽然最开始是在csdn上写的博客,而且从csdn上查到了很多资料,但是csdn使用实在是差劲。账号管理莫名其妙,有的时候把我的id和qq号搞混了;有时候经常发不了博文,无法点击。算了,不说了。 不记得之前是解决什么问题了,用到了很复杂的一条语句,在这大概描述下。 问题:一条sql语句同时删除两个表中相同记录 1.精简版的 delete a,b from table_a a,table_b b where a.id=b.id; 2.复杂版的 delete a,b from table_a a,table_b b where a.id in(select c.id from (select * from table_a a where a.id in (select b.id from table_b b group by b.id having count(*) > 0)) c); 上述两种结果是一样的。 第二种虽然复杂,但是有些场合是可以使用的。 此外还有触发器版的, create trigger tr_name on table1 for delete as delete from table2 where id in (select id from deleted) 然后删除 delete table1 where id条件。挺精巧的,可以仔细理解下。

我所理解的Java到底是解释型语言还是编译型语言

关于Java到底是解释型语言还是编译型语言还是二者的集合?首先理解一下何为解释型语言和编译型语言 计算机高级语言类型主要有编译型和解释型两种: 编译型语言:在程序运行之前,有一个单独的编译过程,将程序翻译成机器语言,以后执行这个程序时,就不用再进行翻译了。 解释型语言:是在运行的时候将程序翻译成机器语言,所以运行速度相对于编译型语言要慢。 SO,二者之间最大的区别就在于是否存下目标机器码:编译会把输入的源程序以某种单位(例如基本块/函数/方法/trace等)翻译生成目标机器码,并存下来(无论是在磁盘上或是内存中)后续执行可以复用;解释则是把源程序中的指令逐条解释执行,边解释边执行,不存下目标代码,后续执行没有可以复用的信息。 了解Java的运行过程:Java源文件(*.java),通过java编译器(javac)编译生成一个ByteCode字节码文件(*.class),字节码由java自己设计的一个计算机(即java虚拟机,JVM)解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的目标机器码,然后在特定的机器上运行。 所以说Java的解释器的优点是比较容易让用户实现自己跨平台的代码,同一套代码可以在几乎所有的操作系统上执行。 (这里提一下java的跨平台Write Once,Run Anywhere:java的跨平台是基于JVM的。JVM是在一台计算机上由软件或是硬件模拟的计算机,java程序所有的*.class文件都是在JVM上运行的,也就是说*.class文件只需认JVM,由JVM去适应各个操作系统,所以不同的操作系统只要安装符合其类型的JVM,那么程序无论到哪个OS上都是可以正确执行的JVM for Unix / JVM for Windows / JVM for Other……,因此没有JVM也就不能跨平台) 虽然Java的第一道工序是javac编译,其目标文件是ByteCode,而并非机器语言,但后续可能有三种处理方式: 1、运行时,ByteCode由JVM逐条送给解释器,解释器将翻译成机器码运行。 2、运行时,部分ByteCode可能由实时编译器(Just In Time Compiler,JIT)编译为目标机器码再执行(以method为翻译单位,还会保存起来,第二次执行就不用再翻译为机器码了),因为考虑到有些JVM是采用纯JIT编译方式实现的,其内部没有解释器,例如:JRockit、Maxine VM。 3、RTSJ,继javac之后执行AOT二次编译,生成静态的目标平台码。 有的时候,可能是以上三种方式同时在使用,至少,1和2是同时使用的,3则需要程序员手工指定。 SO,我认为java是编译与解释两者之间的混合式语言。 And,一个知乎的大牛说的特别有道理: 很多资料说,C/C++等是编译型语言,而Java、C#、Python、JavaScript都是解释型语言,是通过解释器来实现的,其实这么说很容易引起误解:语言一般只会定义其抽象语义,而不会强制性要求采用某种实现方式,例如说C一般被认为是编译型语言,但C的解释器也是存在的,例如Ch……所以一般被称为“解释型语言”的是主流实现方式为解释器的语言,但并不是说它就无法编译。

JAVA对MYSQL数据库进行批量操作,addBatch(),executeBatch()方法

最近要做一个批处理插入数据的,但是试了批处理的代码发现没有效果,很纳闷啊。但是之前在学习JDBC操作Mysql批处理的时候,记得要在数据库url中的参数加配置的,但是忘了。网速搜居然不容易搜出来,我也是醉了,难道这么重要的参数都不重视?于是就看到这一篇,感谢博主。至于这个参数就是“rewriteBatchedStatements=true”这个对批处理很大影响,没有它就相当于没有批处理。 有人说MySQL的JDBC驱动,不是真正支持批量操作的,就算你在代码中调用了批量操作的方法,MySql的JDBC驱动也是按照一般操作来处理的。 但其实并非如此,Mysql 是有特殊的方式优化整个batch insert 结果的。 可不可以先假设 batch 的方式与非batch一样,每一条insrt语句事实上均是单独发往服务器的呢? 浏览下源代码吧。 好多兄弟都描述了源代码,直接从那几个类入手吧,事实上关键的类是这个 com.mysql.jdbc.PreparedStatement 先看了其中的 addBatch 方法,没有任何问题,只是将语句添加进入一个 List 中保存。 那么 executeBatch 呢? 再贴一下吧, 关键看其中的这部分,顺带说一下, 这个mysql-jdbcdriver的源代码是 5.1.13的 [java] view plain copy try { clearWarnings(); if (!this.batchHasPlainStatements && this.connection.getRewriteBatchedStatements()) { if (canRewriteAsMultiValueInsertAtSqlLevel()) { return executeBatchedInserts(batchTimeout); //执行路径之一 } if (this.connection.versionMeetsMinimum(4, 1, 0) && !this.batchHasPlainStatements && this.batchedArgs != null && this.batchedArgs.size() > 3 /* cost of option setting rt-wise */) { return executePreparedBatchAsMultiStatement(batchTimeout); //执行路径之二 } } return executeBatchSerially(batchTimeout); //执行路径之三 } finally { clearBatch(); } 其实最终,executeBatch 的执行路径有三种可能。代码中我已标出来 代码不算太复杂,但是有一个参数能帮助我们更快的确定mysql的batch工作机制,那就是 mysql jdbc driver 的connection url, 其中有一个参数是: rewriteBatchedStatements 完整的参数参考看这里:http://ftp.

RabbitMQ之消息确认机制(事务+Confirm)

概述 在使用RabbitMQ的时候,我们可以通过消息持久化操作来解决因为服务器的异常奔溃导致的消息丢失,除此之外我们还会遇到一个问题,当消息的发布者在将消息发送出去之后,消息到底有没有正确到达broker代理服务器呢?如果不进行特殊配置的话,默认情况下发布操作是不会返回任何信息给生产者的,也就是默认情况下我们的生产者是不知道消息有没有正确到达broker的,如果在消息到达broker之前已经丢失的话,持久化操作也解决不了这个问题,因为消息根本就没到达代理服务器,你怎么进行持久化,那么这个问题该怎么解决呢? RabbitMQ为我们提供了两种方式: 通过AMQP事务机制实现,这也是AMQP协议层面提供的解决方案;通过将channel设置成confirm模式来实现; 事务机制 这里首先探讨下RabbitMQ事务机制。 RabbitMQ中与事务机制有关的方法有三个:txSelect(), txCommit()以及txRollback(), txSelect用于将当前channel设置成transaction模式,txCommit用于提交事务,txRollback用于回滚事务,在通过txSelect开启事务之后,我们便可以发布消息给broker代理服务器了,如果txCommit提交成功了,则消息一定到达了broker了,如果在txCommit执行之前broker异常崩溃或者由于其他原因抛出异常,这个时候我们便可以捕获异常通过txRollback回滚事务了。 关键代码: channel.txSelect(); channel.basicPublish(ConfirmConfig.exchangeName, ConfirmConfig.routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, ConfirmConfig.msg_10B.getBytes()); channel.txCommit(); 通过wirkshark抓包(ip.addr==xxx.xxx.xxx.xxx && amqp),可以看到: (注意这里的Tx.Commit与Tx.Commit-Ok之间的时间间隔294ms,由此可见事务还是很耗时的。) 我们先来看看没有事务的通信过程是什么样的: 可以看到带事务的多了四个步骤: client发送Tx.Selectbroker发送Tx.Select-Ok(之后publish)client发送Tx.Commitbroker发送Tx.Commit-Ok 下面我们来看下事务回滚是什么样子的。关键代码如下: try { channel.txSelect(); channel.basicPublish(exchange, routingKey, MessageProperties.PERSISTENT_TEXT_PLAIN, msg.getBytes()); int result = 1 / 0; channel.txCommit(); } catch (Exception e) { e.printStackTrace(); channel.txRollback(); } 同样通过wireshark抓包可以看到: 代码中先是发送了消息至broker中但是这时候发生了异常,之后在捕获异常的过程中进行事务回滚。 事务确实能够解决producer与broker之间消息确认的问题,只有消息成功被broker接受,事务提交才能成功,否则我们便可以在捕获异常进行事务回滚操作同时进行消息重发,但是使用事务机制的话会降低RabbitMQ的性能,那么有没有更好的方法既能保障producer知道消息已经正确送到,又能基本上不带来性能上的损失呢?从AMQP协议的层面看是没有更好的方法,但是RabbitMQ提供了一个更好的方案,即将channel信道设置成confirm模式。 Confirm模式 概述 上面我们介绍了RabbitMQ可能会遇到的一个问题,即生成者不知道消息是否真正到达broker,随后通过AMQP协议层面为我们提供了事务机制解决了这个问题,但是采用事务机制实现会降低RabbitMQ的消息吞吐量,那么有没有更加高效的解决方式呢?答案是采用Confirm模式。 producer端confirm模式的实现原理 生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,broker就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了,如果消息和队列是可持久化的,那么确认消息会将消息写入磁盘之后发出,broker回传给生产者的确认消息中deliver-tag域包含了确认消息的序列号,此外broker也可以设置basic.ack的multiple域,表示到这个序列号之前的所有消息都已经得到了处理。 confirm模式最大的好处在于他是异步的,一旦发布一条消息,生产者应用程序就可以在等信道返回确认的同时继续发送下一条消息,当消息最终得到确认之后,生产者应用便可以通过回调方法来处理该确认消息,如果RabbitMQ因为自身内部错误导致消息丢失,就会发送一条nack消息,生产者应用程序同样可以在回调方法中处理该nack消息。 在channel 被设置成 confirm 模式之后,所有被 publish 的后续消息都将被 confirm(即 ack) 或者被nack一次。但是没有对消息被 confirm 的快慢做任何保证,并且同一条消息不会既被 confirm又被nack 。 开启confirm模式的方法 生产者通过调用channel的confirmSelect方法将channel设置为confirm模式,如果没有设置no-wait标志的话,broker会返回confirm.

maven资源过滤导致打包后文件变大

今天遇到一个问题,我们有个ip.dat二进制文件,通过里面内容可以解析ip所在的地域信息,本地单元测试都是OK的,部署到测试环境后,发现解析ip的时候报错。拿测试环境打印出的IP地址,在本地单元测试也么有问题。最后发现:代码库的ip.dat文件大小只有3.5M左右,而测试环境的ip.dat文件大小在5M左右。 问题在于:为什么ip.dat通过maven打包后文件变大了?由于maven打包的时候,会将这个文件从src/main/resources/下面拷贝的conf目录下。我直接将ip.dat放在conf目录下,而不是resources目录下,发现打包后大小正常。 也就是说maven打包的过程中,只是将src/main/resources/目录下的文件变大了。因为我们在pom中开启了资源过滤。 <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> </resource> </resources> 解决方案就很简单了:直接将ip.dat放到conf目录下不参与资源过滤就可以了。如果一定要将ip.dat放在resources目录下,那么可以通过下面配置解决。 <resources> <!--排除ip.dat,不打包到classpath下,自然就不会过滤--> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <excludes> <exclude>ip.dat</exclude> </excludes> </resource> <!--将ip.dat打包到classpath下,但是不进行资源过滤--> <resource> <directory>src/main/resources</directory> <filtering>false</filtering> <includes> <include>ip.dat</include> </includes> </resource> </resources> 使用maven进行资源过滤的时候,只要过滤需要过滤的文件,一些二进制文件,比如https证书等,就不要参与资源过滤,否则打包后会破坏文件内容。

MYSQL部分知识点

mysql部分知识点 Mysql存储引擎包括MyISAM,InnoDB,BDB,MEMORY,MERGE,EXAMPLE,NDB cluster,CSV,BLACKHOLE,FEDERATED等,其中InnoDB和BDB提供事务安全表,其他存储引擎都是非事务安全表。MyISAM数据表,最好使用固定长度的数据列代替可变长度的数据列,MEMORY数据表目前都使用固定长度的数据行存储,因此无论使用CHAR或VARCHAR列都没有关系,两者都是作为CHAR类型处理的,对于InnoDB数据表,建议使用VARCHAR类型。索引原则:搜索的索引列,不一定是所要选择的列;使用唯一索引;使用短索引;利用最左前缀;不要过度索引;考虑在列上进行的比较类型。SQL Injection 原理:结构化查询语言(SQL)是一种用来和数据库交互的文本语言。SQL Injection 就是利用某些数据库的外部接口把用户数据插入到实际的数据库操作语言(SQL)当中,从而达到入侵数据库乃至操作系统的目的。它的产生主要是由于程序对用户输入的数据没有进行严格 的过滤,导致非法数据库查询语句的执行。检索包含最大/最小值的行:MIN() 和MAX() 的取值可以是一个字符串参数;在这些情况下, 它们返回最小或最大字符串值。DISTINCT 关键词可以被用来查找expr 的不同值的最小或最大值,然而,这产生的结果与省略DISTINCT 的结果相同。若找不到匹配的行,MIN()和MAX()返回NULL 。用rand()/rand(n)提取随机行。利用group by 的with rollup 子句做统计,当你使用ROLLUP时, 你不能同时使用ORDER BY子句进行结果排序。换言之, ROLLUP和ORDER BY 是互相排斥的,LIMIT 用在ROLLUP 后面。用bit group functions 做统计。操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性。这说明在大多数Unix 中数据库名和表名对大小写敏感,而在Windows 中对大小写不敏感。尽管在某些平台中数据库名和表名对大小写不敏感,不应在同一查询中使用不同的大小写来引用给定的数据库或表。列、索引、存储子程序和触发器名在任何平台上对大小写不敏感,列的别名也不敏感。默认情况,表别名在Unix 中对大小写敏感,但在Windows 或Mac OS X 中对大小写不敏感。在MySQL 中,InnoDB 表支持对外部关键字约束条件的检查。对于除InnoDB 类型的表,当使用REFERENCES tbl_name(col_name)子句定义列时可以使用外部关键字,该子句没有实际的效果,只作为备忘录或注释来提醒,你目前正定义的列指向另一个表中的一个列。通过show status和应用特点了解各种SQL的执行频率。可以通过慢查询日志定位那些执行效率较低的sql 语句,用–log-slowqueries[=file_name]选项启动时,mysqld 写一个包含所有执行时间超过long_query_time 秒的SQL 语句的日志文件。可以链接到管理维护中的相关章节;慢查询日志在查询结束以后才纪录,所以在应用反映执行效率出现问题的时候查询慢查询日志并不能定位问题,可以使用show processlist 命令查看当前MySQL 在进行的线程,包括线程的状态,是否锁表等等,可以实时的查看SQL 执行情况,同时对一些锁表操作进行优化。myisam 表的数据文件和索引文件是自动分开的;innodb 的数据和索引是存储在同一个表空间里面,但可以有多个文件组成。索引用于快速找出在某个列中有一特定值的行。对相关列使用索引是提高SELECT 操作性能的最佳途径。 查询要使用索引最主要的条件是查询条件中需要使用索引关键字,如果是多列索引,那么只有查询条件使用了多列关键字最左边的前缀时,才可以使用索引,否则将不能使用索引。不会使用已有索引的情况:如果mysql 估计使用索引比全表扫描更慢,则不使用索引;如果使用heap 表并且where 条件中不用=索引列,其他> 、<、>=、<=均不使用索引;如果不是索引列的第一部分;如果like 是以%开始;对where 后边条件为字符串的一定要加引号,字符串如果为数字mysql 会自动转为字符串,但是不使用索引。对于Myisam 类型的表,可以通过以下方式快速的导入大量的数据。 ALTER TABLE tblname DISABLE KEYS; loading the data ALTER TABLE tblname ENABLE KEYS; 这两个命令用来打开或者关闭Myisam 表非唯一索引的更新。在导入大量的数据到一个非空的Myisam 表时,通过设置这两个命令,可以提高导入的效率。对于导入大量数据到一个空的Myisam 表,默认就是先导入数据然后才创建索引的,所以不用进行设置。因为Innodb 类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率。如果Innodb 表没有主键,那么系统会默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这个优势提高导入数据的效率;在导入数据前执行SET UNIQUE_CHECKS=0,关闭唯一性校验,在导入结束后执行SET UNIQUE_CHECKS=1,恢复唯一性校验,可以提高导入的效率;如果应用使用自动提交的方式,建议导入前执行SET AUTOCOMMIT=0,关闭自动提交,导入结束后再执行SET AUTOCOMMIT=1,打开自动提交,也可以提高导入的效率。如果你同时从同一客户插入很多行,使用多个值表的INSERT 语句。这比使用分开INSERT 语句快(在一些情况中几倍)。如果你从不同客户插入很多行,能通过使用INSERT DELAYED 语句得到更高的速度。Delayed 的含义是让insert 语句马上执行,其实数据都被放在内存的队列中,并没有真正写入磁盘;这比每条语句分别插入要快的多;LOW_PRIORITY 刚好相反,在所有其他用户对表的读写完后才进行插入。将索引文件和数据文件分在不同的磁盘上存放(利用建表中的选项);如果进行批量插入,可以增加bulk_insert_buffer_size 变量值的方法来提高速度,但是,这只能对myisam 表使用;当从一个文本文件装载一个表时,使用LOAD DATA INFILE。这通常比使用很多INSERT 语句快20 倍;根据应用情况使用replace 语句代替insert;根据应用情况使用ignore 关键字忽略重复记录。对于or 子句,如果要利用索引,则or 之间的每个条件列都必须用到索引;如果没有索引,则应该考虑增加索引。MySQL 的默认的调度策略可用总结如下:写入操作优先于读取操作;对某张数据表的写入操作某一时刻只能发生一次,写入请求按照它们到达的次序来处理;对某张数据表的多个读取操作可以同时地进行。其他优化措施:使用持久的连接数据库以避免连接开销;经常检查所有查询确实使用了必要的索引;避免在频繁更新的表上执行复杂的SELECT 查询,以避免与锁定表有关的由于读、写冲突发生的问题;对于没有删除的行操作的MyISAM 表,插入操作和查询操作可以并行进行,因为没有删除操作的表查询期间不会阻塞插入操作.对于确实需要执行删除操作的表,尽量在空闲时间进行批量删除操作,避免阻塞其他操作;充分利用列有默认值的事实。只有当插入的值不同于默认值时,才明确地插入值。这减少MySQL 需要做的语法分析从而提高插入速度;对经常访问的可以重构的数据使用内存表,可以显著提高访问的效率;通过复制可以提高某些操作的性能。可以在复制服务器中分布客户的检索以均分负载。 为了防止备份期间对应用的影响,可以在复制服务器上执行备份操作;表的字段尽量不使用自增长变量,在高并发情况下该字段的自增可能对效率有比较大的影响,推荐通过应用来实现字段的自增长。通过拆分,提高表的访问效率,主要针对MyISAM存储引擎:纵向拆分是只按照应用访问的频度,将表中经常访问的字段和不经常访问的字段拆分成两个表,经常访问的字段尽量是定长的,这样可以有效的提高表的查询和更新的效率;横向拆分是指按照应用的情况,有目的的将数据横向拆分成几个表或者通过分区分到多个分区中,这样可以有效的避免Myisam 表的读取和更新导致的锁问题。表级锁在下列几种情况下比行级锁更优越:很多操作都是读表;在严格条件的索引上读取和更新,当更新或者删除可以用单独的索引来读取得到时;UPDATE tbl_name SET column=value WHERE unique_key_col=key_value;DELETE FROM tbl_name WHERE unique_key_col=key_value;SELECT 和INSERT 语句并发的执行,但是只有很少的UPDATE 和DELETE 语句;很多的扫描表和对全表的GROUP BY 操作,但是没有任何写表。行级锁定的优点:当在许多线程中访问不同的行时只存在少量锁定冲突;回滚时只有少量的更改;可以长时间锁定单一的行。行级锁定的缺点:比页级或表级锁定占用更多的内存;当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁;如果你在大部分数据上经常进行GROUP BY 操作或者必须经常扫描整个表,比其它锁定 明显慢很多;用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。如何减少锁冲突。对Myisam 类型的表:Myisam 类型的表可以考虑通过改成Innodb 类型的表来减少锁冲突;根据应用的情况,尝试横向拆分成多个表或者改成Myisam 分区对减少锁冲突也会有一定的帮助。对Innodb 类型的表:首先要确认,在对表获取行锁的时候,要尽量的使用索引检索纪录,如果没有使用索引访问,那么即便你只是要更新其中的一行纪录,也是全表锁定的。要确保sql是使用索引来访问纪录的,必要的时候,请使用explain 检查sql 的执行计划,判断是否按照预期使用了索引;由于mysql 的行锁是针对索引加的锁,不是针对纪录加的锁,所以虽然是访问不同行的纪录,但是如果是相同的索引键,是会被加锁的。应用设计的时候也要注意,这里和Oracle 有比较大的不同;当表有多个索引的时候,不同的事务可以使用不同的索引锁定不同的行,当表有主键或者唯一索引的时候,不是必须使用主键或者唯一索引锁定纪录,其他普通索引同样可以用来检索纪录,并只锁定符合条件的行;用SHOW INNODB STATUS 来确定最后一个死锁的原因。查询的结果中,包括死锁的事务的详细信息,包括执行的SQL 语句的内容,每个线程已经获得了什么锁,在等待什么锁,以及最后是哪个线程被回滚。详细的分析死锁产生的原因,可以通过改进程序有效的避免死锁的产生;如果应用并不介意死锁的出现,那么可以在应用中对发现的死锁进行处理;确定更合理的事务大小,小事务更少地倾向于冲突;如果你正使用锁定读,(SELECT … FOR UPDATE 或… LOCK IN SHARE MODE),试着用更低的隔离级别,比如READ COMMITTED;以固定的顺序访问你的表和行,则事务形成良好定义的查询并且没有死锁。应用中需要理清楚对数据库的访问逻辑,需要对相同表的访问,尽量集中在相同sql访问,一次提取结果,减少对数据库的重复访问。利用mysql 的主从复制可以有效的分流更新操作和查询操作,具体的实现是一个主服务器,承担更新操作,多台从服务器,承担查询操作,主从之间通过复制实现数据的同步。多台从服务器一方面用来确保可用性,一方面可以创建不同的索引满足不同查询的需要。

java泛型的一些常见用法

本文主要参考下面几篇文章: http://blog.csdn.net/seu_calvin/article/details/52230032 http://blog.csdn.net/orzlzro/article/details/7017435 http://sharewind.iteye.com/blog/1622164 https://www.zhihu.com/question/20400700 1、 泛型类(接口)的写法以及继承 // 类似java.util.function.Function public interface GenericInterface<T, R> { public R apply(T t); } // 类似java.util.stream.IntStream public interface InheritGeneric0 extends GenericInterface<String, Integer> { } // 类似java.util.function.UnaryOperator public interface InheritGeneric1<T> extends GenericInterface<T, T> { } // 类似java.util.HashMap public interface InheritGeneric2<T, R> extends GenericInterface<T, R> { } // JDK库尚未找到类似的 public interface InheritGeneric3<V, T, R> extends GenericInterface<T, R> { public V apply2(T t, R r); } 2、泛型方法的写法 public class Retryer<T> { private T value; private int id = 0; public Retryer() { } public Retryer(int id) { this.

Android 仪表盘

1:概述 在以前的项目中,需要实现一个根据用户的压力值显示不同的进度(类似仪表盘)圆弧的进度条。实现的原理其实很简单 ,自定义View 重写onDraw()方法在里面同一圆心画三个不同半径颜色实心圆弧,主要了解canvas.drawArc(rectF, startAngle, sweepAngle, true, mPaint);的使用,五个参数的意思分别表示,圆弧的位置和大小,圆弧开始角度,圆弧的结束角度,是否经过圆心,画笔, 我们只要动态改变 sweepAngle 参数就能达到我们想要的效果,废话不多说,直接看代码。 说了一大推先上个效果图 下面是实现代码 自定义的CustomSectorView.java package com.example.wem.sectorviewdemo.widget; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import android.util.Log; import android.view.View; public class CustomSectorView extends View { private static final String TAG = CustomSectorView.class.getSimpleName(); private float startAngle = 180, sweepAngle = 180; private float pointerStartAngle = 180, pointerSweepAngle = 0; private Paint mPaint; public CustomSectorView(Context context) { super(context); } public CustomSectorView(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); } @Override protected void onDraw(Canvas canvas) { float width = getWidth(); float height = getHeight(); int left = (int) (width / 6 + 0.

Linux环境下如何通过WMI对windows进行监控

以下内容使用到的一些工具请在http://download.csdn.net/detail/wqiancangq/9738919下载 sudo pip install wmic sudo pip install wmic-client-wrapper python 中代码 import wmi_client_wrapper as wmi wmic = wmi.WmiClientWrapper(username="Administrator",password="P@ssw0rd",host="10.1.1.152") 终端中直接使用wmic命令 wmic -U Administrator%P@ssw0rd //10.1.1.152 "Select * from Win32_LogicalDisk" Installation Pre-requisites $ sudo aptitude install autoconf Compilation $ cd /data/tools/ $ wget http://www.openvas.org/download/wmi/wmi-1.3.14.tar.bz2 $ bzip2 -cd wmi-1.3.14.tar.bz2 | tar xf - $ cd wmi-1.3.14/ $ sudo make //sudo make "CPP=gcc -E -ffreestanding" $ sudo cp Samba/source/bin/wmic /usr/local/bin/ Usage Usage: wmic -U user%password //host "

用例图

用例图是指由参与者(Actor)、用例(Use Case)以及它们之间的关系构成的用于描述系统功能的视图。用例图是被称为参与者的外部用户所能观察到的系统功能的模型图,呈现了一些参与者和一些用例,以及它们之间的关系,主要用于对系统、子系统或类的功能行为进行建模。 用例图从用户的角度出发,描述系统的功能,并指出各功能的操作者。用例图在软件开发阶段的需求分析阶段进行绘制。 用例图涉及到四种关系:关联、泛化、包含、扩展 (1)关联:表示参与者和用例之间的交互,是通信途径,任何一方都可发送或可接收消息。 箭头指向:指向消息接收者 (2)泛化:也叫继承关系,子用例继承父用例的行为和含义,子用例也可以增加新的行为和含义或者覆盖父用例中的行为和含义。 箭头指向:指向父用例 (3)包含:包含关系用来把一个较复杂的用例所表示的功能分解成较小的步骤。包含用例是必须的,如果缺少包含用例,基用例就是不完整的。 箭头指向:指向分解出来的功能用例 (4)扩展:扩展关系是指用例功能的延伸,与包含关系不同的是,扩展用例是可选的,如果缺少扩展用例,不会影响基用例的完整性。 箭头指向:指向基用例 下面是用Rational Rose 画的机房收费系统的用例图:

安卓实现查看通话记录

这是实现后的效果图,懒得去找图片,能看就行了 实现思路 1,通过内容提供者扫描手机的通话记录,并按照手机号进行排序,升序或降序都可以,再按照通话日期排序 Cursor cursor = cr.query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.NUMBER + "," + CallLog.Calls.DATE + " DESC"); 这里说明一下,按照手机号排序的原因是,为了方便整合同一个手机号的通话记录,日期排序是为了方便记录最后通话日期 这是我的bean public class CallLogBean { /** * 通话类型 0为,未接,1为 拨出,2,为 拨入 */ private int type; /** * 备注名称 */ private String remarkName; /** * 通话日期 */ private String dates; /** * 通话时间 */ private String duration; public void setDuration(String duration) { this.duration = duration; } public String getDuration() { return duration; } /** * 通话类型 0为,未接,1为 拨出,2,为 拨入 */ public int getType() { return type; } /** * 通话类型 0为,未接,1为 拨出,2,为 拨入 */ public void setType(int type) { this.

Storm学习教程

在这个教程中, 你将学到如何创建一个Storm topologies以及怎样把它部署到storm集群上。本教程中,Java将作为主要使用的语言,但在一小部分示例中将会使用Python来阐述storm处理多语言的能力。 预备工作 本教程使用的例子来自于 storm-starter 项目. 我们建议你拷贝该项目并跟随这个例子来进行学习。 请阅读 Setting up a development environment 和 Creating a new Storm project 创建好相应的基础环境。 Storm集群的组件 Storm集群在表面上与Hadoop集群相似。在Hadoop上运行"MapReduce jobs",而在Storm上运行的是"topologies"。 "Jobs" and "topologies" 它们本身非常的不同 -- 一个关键的不同的是MapReduce job最终会完成并结束,而topology的消息处理将无限期进行下去(除非你kill它)。 在storm集群中,有两类节点。Master节点运行守护进程称为"Nimbus",它有点像 Hadoop 的 "JobTracker"。Nimbus负责集群的代码分发,任务分配,故障监控。 每个工作节点运行的守护进程称为"Supervisor"。Supervisor 负责监听分配到它自己机器的作业,根据需要启动和停止相应的工作进程,当然这些工作进程也是Nimbus分派给它的。每个工作进程执行topology的一个子集;一个运行的topology是由分布在多个机器的多个工作进程组成的。 Nimbus 与 Supervisors 所有的协调工作是由 Zookeeper 集群完成的. 此外,Nimbus 守护进程 和 Supervisor 守护进程 是无状态的,快速失败的机制。 所有的状态保存在Zookeeper上或者本地磁盘中。这就是说,你用kill -9杀掉Nimbus 或者Supervisors,它们重新启动后就像什么都没有发生一样,这样的设计让storm集群拥有令人难以置信的稳定性。 Topologies 在Storm上进行实时计算,你需要创建名为 "topologies" 的这么个东西。一个topology是一个计算的图,每个在topology中的节点(以下部分也称作“组件”)包含了处理逻辑,以及多个节点间数据传送的联系和方式。运行一个topology很直接简单的。第一,你把你的java code和它所有的依赖打成一个单独的jar包。然后,你用如下的命令去运行就可以了。 storm jar all-my-code.jar org.apache.storm.MyTopology arg1 arg2 这个例子中运行的类是 org.apache.storm.MyTopology 且带着两个参数 arg1 和 arg2. 这个类的主要功能是定义topology,并被提交到Nimbus中。命令 storm jar 就是用来加载这个topology jar的。

debug看源码小技巧:当有多个子类时,调用的是哪个子类的方法

以前看到一句话,只停在知道这个层次,今天dubug时,遇到如下的问题,忽然想到,这不就是常说的那句话吗,这就是那句话的实际例子。遇到理论可以想到实例,遇到实例也要想到理论啊。就像高考填写诗词时,给你前一句你能填出后一句,但是给你后一句,却怎么也想不起来前一句。。。。 父类有两个实现类,实现类里都有doSomething方法,当父类的引用指向子类,子类调用doSomething()时,调用的是哪个子类的?1or2? 这是只要看父类的引用指向谁就行了 因此是调用子类1的方法。

Pyhton实例,抓取百度词条关于Python的内容(二)

直接上代码 1.UrlManager 管理器 # coding:utf8 class UrlManager(object): #初始化,待爬取URL和已爬取URL def __init__(self): self.new_urls = set() self.old_urls = set() #添加新URL进管理器 def add_new_url(self, url): if url is None: return if url not in self.new_urls and url not in self.old_urls: self.new_urls.add(url) #批量添加URLS def add_new_urls(self, urls): if urls is None or len(urls) == 0: return for url in urls: self.add_new_url(url) def has_new_url(self): return len(self.new_urls) != 0 #pop方法可以把其中的一个URL给弹出,并且移除 def get_new_url(self): new_url = self.new_urls.pop() self.old_urls.add(new_url) return new_url 2.