oracle下使用for update 和 rowid的区别

 oracle  oracle下使用for update 和 rowid的区别已关闭评论
5月 092022
 

使用oracle工具查询并修改数据时,为了简单经常会直接使用select …. for update语句, 但随之而来的问题是,你查询显示就打开了事务,显示的记录即使不修改实际也被锁定了。其实可以使用 select …, rowid from xxx的方式, 使用这种方式,只有当你编辑数据时才打开事务锁定,编辑完成保存提交释放事务

for update:

当语句运行时,事务提前打开,会在对应行(where子句)加上行级锁,无where子句等于全表上锁。若遇到客户端断网、测试人员忘记提交\回滚事务,则会发生锁表。

rowid: 运行后, 事务不会自动打开,并未给数据加上行级锁(通过物理地址去确定某一行数据),但可以编辑数据,提交事务的瞬间完成打开事务上锁、提交、解锁等动作,不易发生锁表

kotlin下泛型使用中in / out 区别

 kotlin  kotlin下泛型使用中in / out 区别已关闭评论
9月 242020
 

在看kotlin泛型资料时,对于使用in或out看得很头大:

  1. 根据需要,泛型参数可以扮演两种角色:生产者(producer)-> out 或消费者(consumer)-> in。生产者角色就意味着泛型参数可读而不可写;消费者角色则相反,可写而不可读。out关键字表明,泛型参数将扮演可读而不可写的生产者角色。也就是说,不能再用var关键字,需要改用val.
  2. 顺便说一下,你可能听到有人用协变(covariance)和逆变(contravariance)来描述outin的用处。

 

最终总结下其实如何使用就是:

  • 父类泛型对象可以赋值给子类泛型对象,用 in;
  • 子类泛型对象可以赋值给父类泛型对象,用 out。

Done!!

mybatis中#和$的区别

 mybatis, 开发  mybatis中#和$的区别已关闭评论
4月 232020
 

mybatis写sql语句时会看到#{}, ${}的写法,有什么区别呢?

1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。

2. $将传入的数据直接显示生成在sql中。如:select * from ${table};

3. #方式能够很大程度防止sql注入。

4.$方式无法防止Sql注入。

5.$方式一般用于传入数据库对象,例如传入表名,order by、like 语句只能用${}了,用#{}会多个’ ‘导致sql语句失效

6.一般能用#的就别用$.

Linux里使用shell中的$(( ))、$( )、“与${ }及区别

 linux, shell  Linux里使用shell中的$(( ))、$( )、“与${ }及区别已关闭评论
4月 072020
 
转一篇linux下关于“$(( ))、$( )、“与${ }”使用及区别的好文章。来自:https://blog.csdn.net/number_0_0/article/details/73291182
命令替换

在bash中,$( )` `(反引号)都是用来作命令替换的。
命令替换与变量替换差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。

exp 1

  1. $ echo today is $(date “+%Y-%m-%d”)
  2. today is 2014-07-01
$( )与``

在操作上,这两者都是达到相应的效果,但是建议使用$( ),理由如下:

  • ``很容易与”搞混乱,尤其对初学者来说。
  • 在多层次的复合替换中,``必须要额外的跳脱处理(反斜线),而$( )比较直观。
  • 最后,$( )的弊端是,并不是所有的类unix系统都支持这种方式,但反引号是肯定支持的。

exp 2

  1. # 将cmd1执行结果作为cmd2参数,再将cmd2结果作为cmd3的参数
  2. cmd3 $(cmd2 $(cmd1))
  3. # 如果是用反引号,直接引用是不行的,还需要作跳脱处理
  4. cmd3 `cmd2 \`cmd1\“
${ }变量替换

一般情况下,$var${var}是没有区别的,但是用${ }会比较精确的界定变量名称的范围

  1. $ A=B
  2. $ echo ${A}B
  3. BB

取路径、文件名、后缀
先赋值一个变量为一个路径,如下:
file=/dir1/dir2/dir3/my.file.txt

命令 解释 结果
${file#*/} 拿掉第一条 / 及其左边的字符串 dir1/dir2/dir3/my.file.txt
${file##*/} 拿掉最后一条 / 及其左边的字符串 my.file.txt
${file#*.} 拿掉第一个 . 及其左边的字符串 file.txt
${file##*.} 拿掉最后一个 . 及其左边的字符串 txt
${file%/*} 拿掉最后一条 / 及其右边的字符串 /dir1/dir2/dir3
${file%%/*} 拿掉第一条 / 及其右边的字符串 (空值)
${file%.*} 拿掉最后一个 . 及其右边的字符串 /dir1/dir2/dir3/my.file
${file%%.*} 拿掉第一个 . 及其右边的字符串 /dir1/dir2/dir3/my

记忆方法如下:

  • # 是去掉左边(在键盘上 # 在 $ 之左边)
  • % 是去掉右边(在键盘上 % 在 $ 之右边)
  • 单一符号是最小匹配;两个符号是最大匹配
  • *是用来匹配不要的字符,也就是想要去掉的那部分
  • 还有指定字符分隔号,与*配合,决定取哪部分

取子串及替换

命令 解释 结果
${file:0:5} 提取最左边的 5 个字节 /dir1
${file:5:5} 提取第 5 个字节右边的连续 5 个字节 /dir2
${file/dir/path} 将第一个 dir 提换为 path /path1/dir2/dir3/my.file.txt
${file//dir/path} 将全部 dir 提换为 path /path1/path2/path3/my.file.txt
${#file} 获取变量长度 27

根据状态为变量赋值

命令 解释 备注
${file-my.file.txt} 若 $file 没设定,则使用 my.file.txt 作传回值 空值及非空值不作处理
${file:-my.file.txt} 若 $file 没有设定或为空值,则使用 my.file.txt 作传回值 非空值时不作处理
${file+my.file.txt} 若$file 设为空值或非空值,均使用my.file.txt作传回值 没设定时不作处理
${file:+my.file.txt} 若 $file 为非空值,则使用 my.file.txt 作传回值 没设定及空值不作处理
${file=txt} 若 $file 没设定,则回传 txt ,并将 $file 赋值为 txt 空值及非空值不作处理
${file:=txt} 若 $file 没设定或空值,则回传 txt ,将 $file 赋值为txt 非空值时不作处理
${file?my.file.txt} 若 $file 没设定,则将 my.file.txt 输出至 STDERR 空值及非空值不作处理
${file:?my.file.txt} 若 $file没设定或空值,则将my.file.txt输出至STDERR 非空值时不作处理

tips:
以上的理解在于, 你一定要分清楚 unset 与 null 及 non-null 这三种赋值状态. 一般而言, : 与 null 有关, 若不带 : 的话, null 不受影响, 若带 : 则连 null 也受影响.

数组

  1. A=“a b c def” # 定义字符串
  2. A=(a b c def) # 定义字符数组
命令 解释 结果
${A[@]} 返回数组全部元素 a b c def
${A[*]} 同上 a b c def
${A[0]} 返回数组第一个元素 a
${#A[@]} 返回数组元素总个数 4
${#A[*]} 同上 4
${#A[3]} 返回第四个元素的长度,即def的长度 3
A[3]=xyz 则是将第四个组数重新定义为 xyz
$(( ))与整数运算

bash中整数运算符号

符号 功能
+ – * / 分别为加、减、乘、除
% 余数运算
& | ^ ! 分别为“AND、OR、XOR、NOT”

在 $(( )) 中的变量名称,可于其前面加 $ 符号来替换,也可以不用。

  1. $ a=5;b=7;c=2
  2. $ echo $((a+b*c))
  3. 19
  4. $ echo $(($a+$b*$c))
  5. 19

进制转换
$(( ))可以将其他进制转成十进制数显示出来。用法如下:
echo $((N#xx))
其中,N为进制,xx为该进制下某个数值,命令执行后可以得到该进制数转成十进制后的值。

  1. $ echo $((2#110)) # 二进制转十进制
  2. 6
  3. $ echo $((16#2a)) # 十六进制转十进制
  4. 42
  5. $ echo $((8#11)) # 八进制转十进制
  6. 9

(( ))重定义变量值

  1. $ a=5;b=7
  2. $ ((a++));echo $a
  3. 6
  4. $ ((a–));echo $a
  5. 5
$ ((a<b));echo $? 0

使用(( ))作整数测试时,不要跟[ ]的整数测试搞混乱了。

UIViewContentMode 中ScaleToFill、AspectFit、AspectFill等区别

 swift  UIViewContentMode 中ScaleToFill、AspectFit、AspectFill等区别已关闭评论
12月 262019
 

UIViewContentMode/ content Mode 中ScaleToFill、AspectFit、AspectFill有什么区别,见下面两张图就一目了然了:

swift 下 init()与init?()区别

 swift  swift 下 init()与init?()区别已关闭评论
12月 252019
 

swift 的类代码里,init()是正常初始化类,但如果初始数据不满足要求,或需要返回nil时,怎么处理呢? init?()就是派这个用场地!

引用https://www.hackingwithswift.com/example-code/language/whats-the-difference-between-init-and-init的内容,下面说的很详细,也有例子举例,大家一看就明白:

It’s the job of a regular Swift initializer to create a fully fledged instance of a new type, however sometimes the data that has been provided is insufficient or incorrect, and creation can’t proceed.

For example, consider this code:

struct Person {
    var ssn: String

    init(socialSecurityNumber: String) {
        self.ssn = socialSecurityNumber
    }
}

let person = Person(socialSecurityNumber: "111-11-1111")
print(person)

That defines a Person struct that can be created using a nine-digit social security number, then creates an instance of that struct.

But what should happen here?

let person = Person(socialSecurityNumber: "FISH")

In that instance we’re passing an invalid social security number, so really we expect creating a Person to fail.

This is where failable initializers come in: they are written as init?(), and can return nil rather than a value if something goes wrong during creation. For example, we could write a quick check to make sure the social security number is more or less correct like this:

struct Person {
    var ssn: String

    init?(socialSecurityNumber: String) {
        if socialSecurityNumber.count < 11 {
            return nil
        } else {
            self.ssn = socialSecurityNumber
        }
    }
}

Notice the initializer is now called init?() to reflect that it returns an optional – the process might return nil if the creation fails. The logic is pretty simple: if there are 11 digits we assume it’s correct, otherwise we return nil. Note: if you really wanted to validate that number you’d need to use a regular expression.

objective-c中categories和extentions简介

 objective-c  objective-c中categories和extentions简介已关闭评论
12月 132019
 

网上很多关于objective-c中categories和extentions的介绍都很含糊,但下面这篇文章自己觉得写的很好,虽然内容有些老了,但不影响你理解categories和extentions,来自:https://code.tutsplus.com/tutorials/objective-c-succinctly-categories-and-extensions–mobile-22016

Categories are an Objective-C language feature that let you add new methods to an existing class, much like C# extensions. However, do not confuse C# extensions with Objective-C extensions. Objective-C’s extensions are a special case of categories that let you define methods that must be declared in the main implementation block.

These are powerful features that have many potential uses. First, categories make it possible to split up a class’ interface and implementation into several files, which provides much-needed modularity for larger projects. Second, categories let you fix bugs in an existing class (e.g., NSString) without the need to subclass it. Third, they provide an effective alternative to the protected and private methods found in C# and other Simula-like languages.

category is a group of related methods for a class, and all of the methods defined in a category are available through the class as if they were defined in the main interface file. As an example, take the Person class that we’ve been working with throughout this book. If this were a large project, Person may have dozens of methods ranging from basic behaviors to interactions with other people to identity checking. The API might call for all of these methods to be available through a single class, but it’s much easier for developers to maintain if each group is stored in a separate file. In addition, categories eliminate the need to recompile the entire class every time you change a single method, which can be a time-saver for very large projects.

Let’s take a look at how categories can be used to achieve this. We start with a normal class interface and a corresponding implementation:

// Person.h
@interface Person : NSObject
@interface Person : NSObject
@property (readonly) NSMutableArray* friends;
@property (copy) NSString* name;
- (void)sayHello;
- (void)sayGoodbye;
@end
// Person.m
#import "Person.h"
@implementation Person
@synthesize name = _name;
@synthesize friends = _friends;
-(id)init{
    self = [super init];
    if(self){
        _friends = [[NSMutableArray alloc] init];
    }
    return self;
}
- (void)sayHello {
    NSLog(@"Hello, says %@.", _name);
}
- (void)sayGoodbye {
    NSLog(@"Goodbye, says %@.", _name);
}
@end

Nothing new here-just a Person class with two properties (the friends property will be used by our category) and two methods. Next, we’ll use a category to store some methods for interacting with other Person instances. Create a new file, but instead of a class, use the Objective-C Category template. Use Relations for the category name and Person for the Category on field:

Figure 28 Creating the PersonRelations class
Creating the Person+Relations class

As expected, this will create two files: a header to hold the interface and an implementation. However, these will both look slightly different than what we’ve been working with. First, let’s take a look at the interface:

// Person+Relations.h
#import <Foundation/Foundation.h>
#import "Person.h"
@interface Person (Relations)
- (void)addFriend:(Person *)aFriend;
- (void)removeFriend:(Person *)aFriend;
- (void)sayHelloToFriends;
@end

Instead of the normal @interface declaration, we include the category name in parentheses after the class name we’re extending. A category name can be anything, as long as it doesn’t conflict with other categories for the same class. A category’s file name should be the class name followed by a plus sign, followed by the name of the category (e.g., Person+Relations.h ).

So, this defines our category’s interface. Any methods we add in here will be added to the original Person class at run time. It will appear as though the addFriend:removeFriend:, and sayHelloToFriends methods are all defined in Person.h, but we can keep our functionality encapsulated and maintainable. Also note that you must import the header for the original class, Person.h. The category implementation follows a similar pattern:

// Person+Relations.m
#import "Person+Relations.h"
@implementation Person (Relations)
- (void)addFriend:(Person *)aFriend {
    [[self friends] addObject:aFriend];
}
- (void)removeFriend:(Person *)aFriend {
    [[self friends] removeObject:aFriend];
}
- (void)sayHelloToFriends {
    for (Person *friend in [self friends]) {
        NSLog(@"Hello there, %@!", [friend name]);
    }
}
@end

This implements all of the methods in Person+Relations.h. Just like the category’s interface, the category name appears in parentheses after the class name. The category name in the implementation should match the one in the interface.

Also, note that there is no way to define additional properties or instance variables in a category. Categories have to refer back to data stored in the main class (friends in this instance).

It’s also possible to override the implementation contained in Person.m by simply redefining the method in Person+Relations.m. This can be used to monkey patch an existing class; however, it’s not recommended if you have an alternative solution to the problem, since there would be no way to override the implementation defined by the category. That is to say, unlike the class hierarchy, categories are a flat organizational structure-if you implement the same method in two separate categories, it’s impossible for the runtime to figure out which one to use.

The only change you have to make to use a category is to import the category’s header file. As you can see in the following example, the Person class has access to the methods defined in Person.h along with those defined in the category Person+Relations.h:

// main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import "Person+Relations.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *joe = [[Person alloc] init];
        joe.name = @"Joe";
        Person *bill = [[Person alloc] init];
        bill.name = @"Bill";
        Person *mary = [[Person alloc] init];
        mary.name = @"Mary";
        [joe sayHello];
        [joe addFriend:bill];
        [joe addFriend:mary];
        [joe sayHelloToFriends];
    }
    return 0;
}

And that’s all there is to creating categories in Objective-C.

To reiterate, all Objective-C methods are public-there is no language construct to mark them as either private or protected. Instead of using “true” protected methods, Objective-C programs can combine categories with the interface/implementation paradigm to achieve the same result.

The idea is simple: declare “protected” methods as a category in a separate header file. This gives subclasses the ability to “opt-in” to the protected methods while unrelated classes use the “public” header file as usual. For example, take a standard Ship interface:

// Ship.h
#import <Foundation/Foundation.h>
@interface Ship : NSObject
- (void)shoot;
@end

As we’ve seen many times, this defines a public method called shoot. To declare a protected method, we need to create a Ship category in a dedicated header file:

// Ship_Protected.h
#import <Foundation/Foundation.h>
@interface Ship(Protected)
- (void)prepareToShoot;
@end

Any classes that need access to the protected methods (namely, the superclass and any subclasses) can simply import Ship_Protected.h. For example, the Ship implementation should define a default behavior for the protected method:

// Ship.m
#import "Ship.h"
#import "Ship_Protected.h"
@implementation Ship {
    BOOL _gunIsReady;
}
- (void)shoot {
    if (!_gunIsReady) {
        [self prepareToShoot];
        _gunIsReady = YES;
    }
    NSLog(@"Firing!");
}
- (void)prepareToShoot {
    // Execute some private functionality.
    NSLog(@"Preparing the main weapon...");
}
@end

Note that if we hadn’t imported Ship_Protected.h, this prepareToShoot implementation would be a private method, as discussed in the Methods chapter. Without a protected category, there would be no way for subclasses to access this method. Let’s subclass the Ship to see how this works. We’ll call it ResearchShip:

// ResearchShip.h
#import "Ship.h"
@interface ResearchShip : Ship
- (void)extendTelescope;
@end

This is a normal subclass interface-it should not import the protected header, as this would make the protected methods available to anyone that imports ResearchShip.h, which is precisely what we’re trying to avoid. Finally, the implementation for the subclass imports the protected methods and (optionally) overrides them:

// ResearchShip.m
#import "ResearchShip.h"
#import "Ship_Protected.h"
@implementation ResearchShip
- (void)extendTelescope {
    NSLog(@"Extending the telescope");
}
// Override protected method
- (void)prepareToShoot {
    NSLog(@"Oh shoot! We need to find some weapons!");
}
@end

To enforce the protected status of the methods in Ship_Protected.h, other classes aren’t allowed to import it. They’ll just import the normal “public” interfaces of the superclass and subclass:

// main.m
#import <Foundation/Foundation.h>
#import "Ship.h"
#import "ResearchShip.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Ship *genericShip = [[Ship alloc] init];
        [genericShip shoot];
        Ship *discoveryOne = [[ResearchShip alloc] init];
        [discoveryOne shoot];
    }
    return 0;
}

Since neither main.mShip.h, nor ResearchShip.h import the protected methods, this code won’t have access to them. Try adding a [discoveryOne prepareToShoot] method-it will throw a compiler error, since the prepareToShoot declaration is nowhere to be found.

To summarize, protected methods can be emulated by placing them in a dedicated header file and importing that header file into the implementation files that require access to the protected methods. No other files should import the protected header.

While the workflow presented here is a completely valid organizational tool, keep in mind that Objective-C was never meant to support protected methods. Think of this as an alternative way to structure an Objective-C method, rather than a direct replacement for C#/Simula-style protected methods. It’s often better to look for another way to structure your classes rather than forcing your Objective-C code to act like a C# program.

One of the biggest issues with categories is that you can’t reliably override methods defined in categories for the same class. For example, if you defined an addFriend: class in Person(Relations) and later decided to change the addFriend: implementation via a Person(Security) category, there is no way for the runtime to know which method it should use since categories are, by definition, a flat organizational structure. For these kinds of cases, you need to revert to the traditional subclassing paradigm.

Also, it’s important to note that a category can’t add instance variables. This means you can’t declare new properties in a category, as they could only be synthesized in the main implementation. Additionally, while a category technically does have access to its classes’ instance variables, it’s better practice to access them through their public interface to shield the category from potential changes in the main implementation file.

Extensions (also called class extensions) are a special type of category that requires their methods to be defined in the main implementation block for the associated class, as opposed to an implementation defined in a category. This can be used to override publicly declared property attributes. For example, it is sometimes convenient to change a read-only property to a read-write property within a class’ implementation. Consider the normal interface for a Ship class:

Included code sample: Extensions

// Ship.h
#import <Foundation/Foundation.h>
#import "Person.h"
@interface Ship : NSObject
@property (strong, readonly) Person *captain;
- (id)initWithCaptain:(Person *)captain;
@end

It’s possible to override the @property definition inside of a class extension. This gives you the opportunity to re-declare the property as readwrite in the implementation file. Syntactically, an extension looks like an empty category declaration:

// Ship.m
#import "Ship.h"
// The class extension.
@interface Ship()
@property (strong, readwrite) Person *captain;
@end
// The standard implementation.
@implementation Ship
@synthesize captain = _captain;
- (id)initWithCaptain:(Person *)captain {
    self = [super init];
    if (self) {
        // This WILL work because of the extension.
        [self setCaptain:captain];
    }
    return self;
}
@end

Note the () appended to the class name after the @interface directive. This is what marks it as an extension rather than a normal interface or a category. Any properties or methods that appear in the extension must be declared in the main implementation block for the class. In this case, we aren’t adding any new fields-we’re overriding an existing one. But unlike categories, extensions can add extra instance variables to a class, which is why we’re able to declare properties in a class extension but not a category.

Because we re-declared the captain property with a readwrite attribute, the initWithCaptain: method can use the setCaptain: accessor on itself. If you were to delete the extension, the property would return to its read-only status and the compiler would complain. Clients using the Ship class aren’t supposed to import the implementation file, so the captain property will remain read-only.

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Ship.h"
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person *heywood = [[Person alloc] init];
        heywood.name = @"Heywood";
        Ship *discoveryOne = [[Ship alloc] initWithCaptain:heywood];
        NSLog(@"%@", [discoveryOne captain].name);
        Person *dave = [[Person alloc] init];
        dave.name = @"Dave";
        // This will NOT work because the property is still read-only.
        [discoveryOne setCaptain:dave];
    }
    return 0;
}

Another common use case for extensions is for declaring private methods. In the previous chapter, we saw how private methods can be declared by simply adding them anywhere in the implementation file. But, prior to Xcode 4.3, this was not the case. The canonical way to create a private method was to forward-declare it using a class extension. Let’s take a look at this by slightly altering the Ship header from the previous example:

// Ship.h
#import <Foundation/Foundation.h>
@interface Ship : NSObject
- (void)shoot;
@end

 

Next, we’re going to recreate the example we used when we discussed private methods in the Methods chapter. Instead of simply adding the private prepareToShoot method to the implementation, we need to forward-declare it in a class extension.

// Ship.m
#import "Ship.h"
// The class extension.
@interface Ship()
- (void)prepareToShoot;
@end
// The rest of the implementation.
@implementation Ship {
    BOOL _gunIsReady;
}
- (void)shoot {
    if (!_gunIsReady) {
        [self prepareToShoot];
        _gunIsReady = YES;
    }
    NSLog(@"Firing!");
}
- (void)prepareToShoot {
    // Execute some private functionality.
    NSLog(@"Preparing the main weapon...");
}
@end

The compiler ensures the extension methods are implemented in the main implementation block, which is why it functions as a forward-declaration. Yet because the extension is encapsulated in the implementation file, other objects shouldn’t ever know about it, giving us another way to emulate private methods. While newer compilers save you this trouble, it’s still important to understand how class extensions work, as it has been a common way to leverage private methods in Objective-C programs until very recently.

This chapter covered two of the more unique concepts in the Objective-C programming language: categories and extensions. Categories are a way to extend the API of existing classes, and extensions are a way to add required methods to the API outside of the main interface file. Both of these were initially designed to ease the burden of maintaining large code bases.

The next chapter continues our journey through Objective-C’s organizational structures. We’ll learn how to define a protocol, which is an interface that can be implemented by a variety of classes.

Swift中的!和?, 问号 和叹号 的使用和区别介绍

 swift  Swift中的!和?, 问号 和叹号 的使用和区别介绍已关闭评论
8月 132019
 

一般我们在一下两种情况下会遇到!和?的使用
1.声明变量时

var number :Int?
var str : String

2.在对变量操作时

number?.hashValue
str!.hashValue

由于这两种情况的意义不同,所以分开进行解释:

1.声明变量时
在声明一个变量时如果不手动初始化,Swift不会自动初始化该变量为一个默认值的。

var a : String
var b = a           //error:因为没有初始化a,a没有值

但是对于Optional的变量则不同,Optional的变量在声明时如果不初始化,Swift会自动将该变量初始化为nil。声明变量时在类型后添加?或者!就是告诉编译器这个一个Optional的变量,如果没有初始化,你就将其初始化为nil

var a : String?           //a 为nil
var b : String!           //b 为nil
var a_test = a            //a_test为nil
var b_test = b            //b_test为nil

但是这两者之间还是有一些区别的,介绍后面之后再讲。
Optional事实上是一个枚举类型,从下图可以看出,Optional包含None和Some两种类型,而nil就是Optional.None,非nil就是Optional.some。如果Optional变量在声明时不初始化,Swift会调用init()来初始化变量为nil,而用非nil的值初始化变量时,会通过Some(T)把该原始值包装,所以在之后使用的时候我们需要通过解包取出原始值才能使用。

2.对变量进行操作时

var arrayCount = dataList?.count

这时问号的意思类似于isResponseToSelector,即如果变量是nil,则不能响应后面的方法,所以会直接返回nil。如果变量非nil,就会拆Some(T)的包,取出原始值执行后面的操作。

var arrayCount = dataList!.count

这里的叹号和之前的问号则不同,这里表示我确定dataList一定是非nil的,所以直接拆包取出原始值进行处理。因此此处如果不小心让dataList为nil,程序就会crash掉。

回到上面声明时?和!区别的问题上去
声明变量时的?只是单纯的告诉Swift这是Optional的,如果没有初始化就默认为nil,而通过!声明,则之后对该变量操作的时候都会隐式的在操作前添加一个!。

总结

  1. 问号?
    a.声明时添加?,告诉编译器这个是Optional的,如果声明时没有手动初始化,就自动初始化为nil
    b.在对变量值操作前添加?,判断如果变量时nil,则不响应后面的方法。
  2. 叹号!
    a.声明时添加!,告诉编译器这个是Optional的,并且之后对该变量操作的时候,都隐式的在操作前添加!
    b.在对变量操作前添加!,表示默认为非nil,直接解包进行处理

 

来自:https://segmentfault.com/a/1190000000533936。

var、let、const区别

 javascript  var、let、const区别已关闭评论
2月 182019
 

var、let、const区别

在javascript中有三种声明变量的方式:var、let、const。

var 声明全局变量,换句话理解就是,声明在for循环中的变量,跳出for循环同样可以使用。

for(var i=0;i<=1000;i++){ 
var sum=0; 
sum+=i; 

alert(sum);

声明在for循环内部的sum,跳出for循环一样可以使用,不会报错正常弹出结果

 

let:声明块级变量,即局部变量。 

在上面的例子中,跳出for循环,再使用sum变量就会报错,有着严格的作用域,变量只作用域当前隶属的代码块,不可重复定义同一个变量,不可在声明之前调用,必须先定义再使用,会报错,循环体中可以用let

注意:必须声明’use strict’;后才能使用let声明变量否则浏览并不能显示结果,

 

const:用于声明常量,也具有块级作用域 ,也可声明块级。

const PI=3.14;

它和let一样,也不能重复定义同一个变量,const一旦定义,无法修改

SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系

 spring  SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系已关闭评论
5月 162018
 

SpringMVC的拦截器(Interceptor)和过滤器(Filter)的区别与联系,挺不错的一篇文章,分享下https://blog.csdn.net/xiaoyaotan_111/article/details/53817918

一 简介

(1)过滤器:

依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等

(2)拦截器:

依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理

二 多个过滤器与拦截器的代码执行顺序

如果在一个项目中仅仅只有一个拦截器或者过滤器,那么我相信相对来说理解起来是比较容易的。但是我们是否思考过:如果一个项目中有多个拦截器或者过滤器,那么它们的执行顺序应该是什么样的?或者再复杂点,一个项目中既有多个拦截器,又有多个过滤器,这时它们的执行顺序又是什么样的呢?

下面我将用简单的代码来测试说明:

(1)先定义两个过滤器:

i)过滤器1:

[java] view plain copy

  1. package cn.zifangsky.filter;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.FilterChain;  
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import org.springframework.web.filter.OncePerRequestFilter;  
  11.   
  12. public class TestFilter1 extends OncePerRequestFilter {  
  13.   
  14.     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
  15.             throws ServletException, IOException {  
  16.         //在DispatcherServlet之前执行  
  17.         <a href=“http://www.07net01.com/tags-system-0.html” class=“infotextkey” style=“background:transparent;color:rgb(66,139,202);” target=“_blank”>system</a>.out.println(“############TestFilter1 doFilterInternal executed############”);  
  18.         filterChain.doFilter(request, response);  
  19.         //在视图页面返回给<a href=”http://www.07net01.com/tags-%E5%AE%A2%E6%88%B7%E7%AB%AF-0.html” class=”infotextkey” style=”background:transparent;color:rgb(66,139,202);” target=”_blank”>客户端</a>之前执行,但是执行顺序在Interceptor之后  
  20.         System.out.println(“############TestFilter1 doFilter after############”);  
  21. //      try {  
  22. //          Thread.sleep(10000);  
  23. //      } catch (InterruptedException e) {  
  24. //          e.printStackTrace();  
  25. //      }  
  26.     }  
  27.   
  28. }  

ii)过滤器2:

[java] view plain copy

  1. package cn.zifangsky.filter;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.FilterChain;  
  6. import javax.servlet.ServletException;  
  7. import javax.servlet.http.HttpServletRequest;  
  8. import javax.servlet.http.HttpServletResponse;  
  9.   
  10. import org.springframework.web.filter.OncePerRequestFilter;  
  11.   
  12. public class TestFilter2 extends OncePerRequestFilter {  
  13.   
  14.     protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)  
  15.             throws ServletException, IOException {  
  16.         System.out.println(“############TestFilter2 doFilterInternal executed############”);  
  17.         filterChain.doFilter(request, response);  
  18.         System.out.println(“############TestFilter2 doFilter after############”);  
  19.   
  20.     }  
  21.   
  22. }  

iii)在web.xml中注册这两个过滤器:

[xml] view plain copy

  1.     <!– 自定义过滤器:testFilter1 –>   
  2.    <filter>  
  3.         <filter-name>testFilter1</filter-name>  
  4.         <filter-class>cn.zifangsky.filter.TestFilter1</filter-class>  
  5.     </filter>  
  6.     <filter-mapping>  
  7.         <filter-name>testFilter1</filter-name>  
  8.         <url-pattern>/*</url-pattern>  
  9.     </filter-mapping>  
  10.     <!– 自定义过滤器:testFilter2 –>   
  11.    <filter>  
  12.         <filter-name>testFilter2</filter-name>  
  13.         <filter-class>cn.zifangsky.filter.TestFilter2</filter-class>  
  14.     </filter>  
  15.     <filter-mapping>  
  16.         <filter-name>testFilter2</filter-name>  
  17.         <url-pattern>/*</url-pattern>  
  18.     </filter-mapping>  

(2)再定义两个拦截器:

i)拦截器1,基本拦截器:

[java] view plain copy

  1. package cn.zifangsky.interceptor;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpServletResponse;  
  5.   
  6. import org.springframework.web.servlet.HandlerInterceptor;  
  7. import org.springframework.web.servlet.ModelAndView;  
  8.   
  9. public class BaseInterceptor implements HandlerInterceptor{  
  10.       
  11.     /** 
  12.      * 在DispatcherServlet之前执行 
  13.      * */  
  14.     public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {  
  15.         System.out.println(“************BaseInterceptor preHandle executed**********”);  
  16.         return true;  
  17.     }  
  18.   
  19.     /** 
  20.      * 在controller执行之后的DispatcherServlet之后执行 
  21.      * */  
  22.     public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)  
  23.             throws Exception {  
  24.         System.out.println(“************BaseInterceptor postHandle executed**********”);  
  25.     }  
  26.       
  27.     /** 
  28.      * 在页面渲染完成返回给客户端之前执行 
  29.      * */  
  30.     public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)  
  31.             throws Exception {  
  32.         System.out.println(“************BaseInterceptor afterCompletion executed**********”);  
  33. //      Thread.sleep(10000);  
  34.     }  
  35.   
  36. }  

ii)指定controller请求的拦截器:

[java] view plain copy

  1. package cn.zifangsky.interceptor;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4. import javax.servlet.http.HttpServletResponse;  
  5.   
  6. import org.springframework.web.servlet.HandlerInterceptor;  
  7. import org.springframework.web.servlet.ModelAndView;  
  8.   
  9. public class TestInterceptor implements HandlerInterceptor {  
  10.   
  11.     public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {  
  12.         System.out.println(“************TestInterceptor preHandle executed**********”);  
  13.         return true;  
  14.     }  
  15.   
  16.     public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)  
  17.             throws Exception {  
  18.         System.out.println(“************TestInterceptor postHandle executed**********”);  
  19.     }  
  20.   
  21.     public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)  
  22.             throws Exception {  
  23.         System.out.println(“************TestInterceptor afterCompletion executed**********”);  
  24.     }  
  25. }  

iii)在SpringMVC的配置文件中注册这两个拦截器:

[java] view plain copy

  1. <!– 拦截器 –>  
  2. nbsp;   <mvc:interceptors>  
  3.     <!– 对所有请求都拦截,公共拦截器可以有多个 –>  
  4.     <bean name=“baseInterceptor” class=“cn.zifangsky.interceptor.BaseInterceptor” />  
  5.     <!– <bean name=“testInterceptor” class=“cn.zifangsky.interceptor.TestInterceptor” /> –>  
  6.     <mvc:interceptor>       
  7.         <!– 对/test.html进行拦截 –>  
  8.         <mvc:mapping path=“/test.html”/>  
  9.         <!– 特定请求的拦截器只能有一个 –>  
  10.         <bean class=“cn.zifangsky.interceptor.TestInterceptor” />  
  11.     </mvc:interceptor>  
  12. </mvc:interceptors>  

(3)定义一个测试使用的controller:

[java] view plain copy

  1. package cn.zifangsky.controller;  
  2.   
  3. import org.springframework.stereotype.Controller;  
  4. import org.springframework.web.bind.annotation.RequestMapping;  
  5. import org.springframework.web.servlet.ModelAndView;  
  6.   
  7. @Controller  
  8. public class TestController {  
  9.       
  10.     @RequestMapping(“/test.html”)  
  11.     public ModelAndView handleRequest(){  
  12.         System.out.println(“———TestController executed——–“);  
  13.         return new ModelAndView(“test”);  
  14.     }  
  15. }  

(4)视图页面test.jsp:

[html] view plain copy

  1. <%@ page language=“java” contentType=“text/html; charset=UTF-8”  
  2.     pageEncoding=“UTF-8”%>  
  3. <%  
  4. String path = request.getContextPath();  
  5. String basePath = request.getScheme()+”://”+request.getServerName()+”:”+request.getServerPort()+path+”/”;  
  6. %>      
  7. <html>  
  8. <head>  
  9. <meta http-equiv=“Content-Type” content=“text/html; charset=UTF-8”>  
  10. <base href=“http://983836259.blog.51cto.com/7311475/”>  
  11. <title>FilterDemo</title>  
  12. </head>  
  13. <body>  
  14.     <%  
  15.         System.out.println(“test.jsp is loading”);  
  16.     %>  
  17.     <div align=“center”>  
  18.         This is test page  
  19.     </div>  
  20. </body>  
  21. </html>  

(5)测试效果:

启动此测试项目,可以看到控制台中输出如下:

wKioL1hHhYrRCpQYAABafsYR7go378.png

这就说明了过滤器的运行是依赖于servlet容器的,跟springmvc等框架并没有关系。并且,多个过滤器的执行顺序跟xml文件中定义的先后关系有关

接着清空控制台中的输出内容并访问:http://localhost:9180/FilterDemo/test.html

可以看到,此时的控制台输出结果如下:

wKiom1hHhaPRQuBxAACG4WdOJbM758.png

相信从这个打印输出,大家就可以很清晰地看到有多个拦截器和过滤器存在时的整个执行顺序了。当然,对于过个拦截器它们之间的执行顺序跟在SpringMVC的配置文件中定义的先后顺序有关

注:对于整个SpringMVC的执行流程来说,如果加上上面的拦截器和过滤器,其最终的执行流程就如下图所示:

wKiom1hHhbmxseDtAACidU9Y84s787.png

shell中$(( ))与$( )还有${ }的区别

 开发  shell中$(( ))与$( )还有${ }的区别已关闭评论
1月 222018
 

学习了, 来自:http://blog.csdn.net/tg5156/article/details/19406275

$( )与` `(反引号)

在bash shell中,$( )与` `(反引号)都是用来做命令替换(command substitution)用的。
$ echo the last sunday is $(date -d “last sunday” +%Y-%m-%d)
得到上一星期天的日期

用$( )的理由

1. ` `很容易与’ ‘(单引号)搞混。有时在一些奇怪的字形显示中,两种符号是一模一样的(直竖两点)。
2. 在多层次的复合替换中,` `须要额外的跳脱(\`)处理,而$( )则比较直观。例如:
command1 `command2 `command3` `
原本的意图是在command2 `command3`中先将command3替换出来给command2处理,然后再将结果传给command1 `command2 …`来处理。
然而,真正的结果在命令行中却是分成了`command2`与` `两段。
正确的输入应该如下:
command1 `command2 \`command3\` `
换成$( )则一目了然:
command1 $(command2 $(command3))

$( )的不足

` `基本上可在全部的unix shell中使用,若写成shell script移植性比较高。而$( )并不是每一种shell都能使用。

${ }用来作变量替换

一般情况下,$var与${var}作用相同。但是用${ }会比较精确的界定变量名称的范围,例如:
$ A=B
$ echo $AB
原本是打算先将$A的结果替换出来,然后再补一个B字母于其后,但在命令行上,真正的结果却是只会替换变量名称为AB的值出来。
使用${ }就没问题了:
$ echo ${A}B
BB

${ }的一些特异功能

定义一个变量:
file=/dir1/dir2/dir3/my.file.txt
可以用${ }分别替换获得不同的值:
${file#*/} 拿掉第一个 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt
${file##*/} 拿掉最后一个 / 及其左边的字符串:my.file.txt
${file#*.} 拿掉第一个 . 及其左边的字符串:file.txt
${file##*.} 拿掉最后一个 . 及其左边的字符串:txt
${file%/*} 拿掉最后一个 / 及其右边的字符串:/dir1/dir2/dir3
${file%%/*} 拿掉第一个 / 及其右边的字符串:(空值)
${file%.*} 拿掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file
${file%%.*} 拿掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my
记忆的方法:
# 去掉左边(键盘上 # 在 $ 的左边)
% 去掉右边(在键盘上 % 在 $ 的右边)
单一符号是最小匹配,两个符号是最大匹配。
${file:0:5} 提取最左边的 5 个字节:/dir1
${file:5:5} 提取第 5 个字节右边的连续 5 个字节:/dir2
也可以对变量值里的字符串作替换:
${file/dir/path} 将第一个 dir 替换为 path:/path1/dir2/dir3/my.file.txt
${file//dir/path} 将全部 dir 替换为 path:/path1/path2/path3/my.file.txt
利用${ }还可针对不同的变量状态赋值(未设定、空值、非空值): 
${file-my.file.txt} 若 $file 未设定,则使用 my.file.txt 作传回值。(空值及非空值时不作处理) 
${file:-my.file.txt} 若 $file 未设定或为空值,则使用 my.file.txt 作传回值。(非空值时不作处理)
${file+my.file.txt} 若 $file 设为空值或非空值,均使用 my.file.txt 作传回值。(未设定时不作处理)
${file:+my.file.txt} 若 $file 为非空值,则使用 my.file.txt 作传回值。(未设定及空值时不作处理)
${file=my.file.txt} 若 $file 未设定,则使用 my.file.txt 作传回值,同时将 $file 赋值为 my.file.txt。 (空值及非空值时不作处理)
${file:=my.file.txt} 若 $file 未设定或为空值,则使用 my.file.txt 作传回值,同时将 $file 赋值为 my.file.txt。 (非空值时不作处理)
${file?my.file.txt} :若 $file 未设定,则将 my.file.txt 输出至 STDERR。(空值及非空值时不作处理)
${file:?my.file.txt} :若 $file 未设定或为空值,则将 my.file.txt 输出至 STDERR。(非空值时不作处理)
以上的理解在于,一定要分清楚 unset 与 null 及 non-null 这三种赋值状态。
一般而言,与 null 有关,若不带 : 的话,null 不受影响,若带 : 则连 null 也受影响。
${#var} 可计算出变量值的长度:
${#file} 可得到 27,/dir1/dir2/dir3/my.file.txt 刚好是 27 个字节。

bash数组(array)处理方法

一般而言,A=”a b c def”只是将 $A 替换为一个单一的字符串,但是改为 A=(a b c def),则是将 $A 定义为数组。
bash的数组替换方法可参考如下方法:
${A[@]} 或 ${A[*]} 得到 a b c def(全部数组)
${A[0]} 得到 a (第一个元素),${A[1]} 第二个…
${#A[@]} 或 ${#A[*]} 得到 4 (数组数量)
${#A[0]} 得到 1 (第一个元素 a 的长度),${#A[3]} 得到 3 (第四个元素 def 的长度)
A[3]=xyz 将第四个元素重新定义为 xyz

$(( ))的用途

用来作整数运算。在 bash 中,$(( ))的整数运算符号大致有这些:
+ – * / 加、减、乘、除
% 余数运算
& | ^ ! AND、OR、XOR、NOT运算
举例:
$ a=5; b=7; c=2
$ echo $((a+b*c))
19
$ echo $(((a+b)/c))
6
$ echo $(((a*b)%c))
1
在$(( ))中的变量名称也可以在其前面加 $ 符号:$(($a+$b*$c))也可以得到 19 的结果。
此外,$(( ))还可以作不同进制(如二进制、八进位、十六进制)运算,只是输出结果皆为十进制而已。
echo $((16#2a)) 结果为 42 (16进位转十进制)
举一个实用的例子:
当前的 umask 是 022,新建文件的权限为:
$ umask 022
$ echo “obase=8; $(( 8#666 & (8#777 ^ 8#$(umask)) ))” | bc
644
事实上,单纯用(( ))也可以重定义变量值,或作testing:
a=5; ((a++)) 将 $a 重定义为 6
a=5; ((a–)) a=4
a=5; b=7; ((a < b)) 会得到 0 (true) 的返回值
常见的用于(( ))的测试符号有以下这些:
< 小于
> 大于
<= 小于或等于
>= 大于或等于
== 等于
!= 不等于

JQuery中的load()、$.get()和$.post()详解

 jquery  JQuery中的load()、$.get()和$.post()详解已关闭评论
1月 182018
 

文章解析的比较清楚,来自: http://blog.csdn.net/csdn_yudong/article/details/52537609

load()

1.载入HTML文档 
load()方法是jQuery中最为简单和常用的Ajax方法,能载入远程HTML代码并插入DOM中。 
它的结构为:

load(url [,data][,callback])
参数名称 类型 说明
url String 请求HTML页面的URL地址
data(可选) Object 发送至服务器的key/value数据
callback(可选) Function 请求完成时的回调函数,无论请求成功或失败

首先创建一个test.html文件,用于被load()方法加载并追加到页面中。

test.html 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <div class="comment"> <h6>张三:</h6> <p class="para">沙发.</p> </div> <div class="comment"> <h6>李四:</h6> <p class="para">板凳.</p> </div> <div class="comment"> <h6>王五:</h6> <p class="para">地板.</p> </div> </body> </html> 

然后再建一个demo1.html,在上面添加两个元素:<button>用来触发Ajax事件,id为”resText”的元素用来显示追加的HTML内容。HTML代码如下:

demo1.html 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css"> * { margin:0; padding:0;} body { font-size:12px;} .comment { margin-top:10px; padding:10px; border:1px solid #ccc;background:#DDD;} .comment h6 { font-weight:700; font-size:14px;} .para { margin-top:5px; text-indent:2em;background:#DDD;} </style> <!--   引入jQuery --> <script src="https://cdn.bootcss.com/jquery/1.7.1/jquery.min.js"></script> <script language="javascript" type="text/javascript"> $(function(){ $("#send").click(function(){ $("#resText").load("test.html");
      })
  }) </script> </head> <body> <input type="button" id="send" value="Ajax获取" /> <div class="comment"> 已有评论: </div> <div id="resText" ></div> </body> </html> 

显然,load()方法完成了原本很繁琐的工作。开发人员只需要使用jQuery选择器为HTML片段指定目标位置,然后将要加载的文件的URL作为参数传递给load()方法即可。当单击按钮后,test.html页面的HTML内ring就会被加载并插入主页面<div id=”resText”></div>的元素中。

2.筛选载入的HTML文档 
上面的例子是将test.html页面中的内容都加载到id为”resText”的元素里。如果只需要加载test.html页面内的某些元素,那么可以使用load()方法的URL参数来达到目的。通过为URL参数指定选择符,就可以很方便地从加载过来的HTML文档里筛选出所需要的内容。

load()方法的URL参数的语法结构为:“url selector”。注意,URL和选择器之间有一个空格。

例如只需要加载test.html页面中class为”para”的内容,可以将demo1.html中的

$("#resText").load("test.html");

改为

$("#resText").load("test.html  .para");

3.传递方法 
load()方法的传递方式根据参数data来自动指定。如果没有参数传递,则采用GET方式传递;反之,则会自动转换为POST方法。

//无参数传递,则是GET方式
$('#resText').load('test.php',function(){
    //... });
//有参数传递,则是POST方式
$('#resText').load('test.php',{name:'rain',age:'22'},function(){
    //... });

4.回调函数 
对于必须在加载完成后才能继续的操作,load()方法提供了回调函数(callback),该函数有3个参数,分别代表请求返回的内容请求状态XMLHttpRequest对象,jQuery代码如下:

$("#resText").load("test.html",function (responseText, textStatus, XMLHttpRequest){ alert(responseText); //请求返回的内容 alert(textStatus); //请求状态:success,error alert(XMLHttpRequest); //XMLHttpRequest对象 });

在load()方法中,无论Ajax请求是否成功,只要当请求完成(complete)后,回调函数(callback)就被触发。


load()方法通常用来从Web服务器上获取静态的数据文件,然后这并不能体现Ajax的全部价值。在项目中,如果需要传递一些参数给服务器中的页面,那么可以使用$.get()或者$.post()或者$.ajax()方法。


$.get()

$.get()方法使用GET方式来进行异步请求。 
它的结构为:

$.get(url[,data][,callback][,type])
参数名称 类型 说明
url String 请求的HTML页的URL地址
data(可选) Object 发送至服务器的key/value数据会作为QueryString附加到请求URL中
callback(可选) Function 载入成功时回调函数(只有当Response的返回状态是success才调用该方法)自动将请求结果和状态传递给该方法
type(可选) String 服务器端返回内容的样式,包括xml、html、script、json、text和_default

我们用$.get()来实现评论的功能:

get1.html 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style type="text/css"> * { margin:0; padding:0;} body { font-size:12px;} .comment { margin-top:10px; padding:10px; border:1px solid #ccc;background:#DDD;} .comment h6 { font-weight:700; font-size:14px;} .para { margin-top:5px; text-indent:2em;background:#DDD;} </style> <!--   引入jQuery --> <script src="../scripts/jquery.js" type="text/javascript"></script> <script type="text/javascript"> //<![CDATA[ $(function(){ $("#send").click(function(){ $.get("get1.php", { 
                        username :  $("#username").val() , 
                        content :  $("#content").val()  
                    }, function (data, textStatus){ $("#resText").html(data); // 把返回的数据添加到页面上 }
            );
       })
    }) //]]> </script> </head> <body> <form id="form1" action="#"> <p>评论:</p> <p>姓名: <input type="text" name="username" id="username" /></p> <p>内容: <textarea name="content" id="content" rows="2" cols="20"></textarea></p> <p><input type="button" id="send" value="提交"/></p> </form> <div class='comment'>已有评论:</div> <div id="resText" > </div> </body> </html> 

get1.html向get1.php发送get请求,服务器端get1.php的代码如下:

<?php 
    header("Content-Type:text/html; charset=utf-8");
    echo "<div class='comment'><h6>{$_REQUEST['username']}:</h6><p class='para'>{$_REQUEST['content']}</p></div>";
?> 

由于服务器端get1.php返回的数据格式是一段HTML片段,因此并不需要经过处理就可以将新的HTML数据插入到主页面中。 
我们再来看一下get.html中的核心代码jQuery是如何完成get请求的:

$(function(){ $("#send").click(function(){ $.get("get1.php", { 
                        username :  $("#username").val() , 
                        content :  $("#content").val()  
                    }, function (data, textStatus){ $("#resText").html(data); // 把返回的数据添加到页面上 }
            );
       })
    })

我们可以看到在回调函数中,我们直接将返回回来的data(也就是HTML片段)直接在html中使用。

HTML片段实现起来只需要很少的工作量,但这种固定的数据结构并不一定能够在其他的Web应用程序中得到重用。

XML文档

服务器端是如何接收数据然后返回XML的呢? 
代码如下:

get2.php 
<?php 
    header("Content-Type:text/xml; charset=utf-8");
    echo "<?xml version='1.0' encoding='utf-8'?>".
         "<comments>".
         "<comment username='{$_REQUEST['username'] }' >".
         "<content>{$_REQUEST['content']}</content>".
         "</comment>".
         "</comments>";
?> 

注意:由于服务器端返回的数据格式是XML文档,因此需要在服务端设置Content-Type类型,代码如下:

header("Content-Type:text/xml; charset=utf-8");

对于服务器端返回的数据是XML格式的情况,我们需要对返回的数据进行处理,才能应用到HTML中,jQuery有强大的DOM处理能力,处理XML文档与处理HTML文档一样,也可以使用常规的attr()、find()、filter()以及其他方法。jQuery代码如下:

$(function(){ $("#send").click(function(){ $.get("get2.php", { 
      username :  $("#username").val() , 
      content :  $("#content").val()  
    }, function (data, textStatus){ var username = $(data).find("comment").attr("username"); var content = $(data).find("comment content").text(); var txtHtml = "<div class='comment'><h6>"+username+":</h6><p class='para'>"+content+"</p></div>";
      $("#resText").html(txtHtml); // 把返回的数据添加到页面上 },'XML');
  });
})

返回数据格式为XML文档的过程实现起来比HTML片段要稍微复杂些,但XML文档的可移植性是其他数据格式无法比拟的,因此以这种格式提供的数据的重要性将极大提高。不过,XML文档体积相对较大,与其他文件格式相比,解析和操作它们的速度要慢一些。

JSON文件 
之所以会出现这种数据格式的文件,很大程度上是因为XML文档体积大和难以解析。JSON文件和XML文档一样,也可以方便的被重用。而且,JSON文件非常简洁,也容易阅读。

服务器端是如何接收数据然后返回JSON的呢? 
代码如下:

get3.php 
<?php 
    header("Content-Type:text/html; charset=utf-8");
    echo "{ \"username\" : \"{$_REQUEST['username']}\" , \"content\" : \"{$_REQUEST['content']}\"}" ?>

JSON的格式还是比较严格的,所以格式不能写错了。 
由于服务器端返回的数据格式是JSON文件,因此需要对返回的数据进行处理之后,才可以将新的HTML数据添加到主页面中。HTML文件其他部分还是一样,要修改的地方是jQuery部分,jQuery代码如下:

$(function(){ $("#send").click(function(){ $.get("get3.php", { 
                username :  $("#username").val() , 
                content :  $("#content").val()  
            }, function (data, textStatus){ var username = data.username; var content = data.content; var txtHtml = "<div class='comment'><h6>"+username+":</h6><p class='para'>"+content+"</p></div>";
        $("#resText").html(txtHtml); // 把返回的数据添加到页面上 },"json");
       });
    })

在上面的代码中,将$.get()方法的第4个参数(type)设置为”json”来代表期待服务器返回的数据格式。

对于服务器端返回HTML片段、XML数据、JSON数据的优缺点进行分析,可以的得知在不需要与其他应用程序共享数据的时候,使用HTML片段来提供返回数据一般来说是最简单的;如果数据需要重用,那么JSON文件是不错的选择,它在性能和文件大小方面具有优势,它是Web服务器领域的“世界语”,我们推荐使用JSON。

$.post()

它与$.get()方法的结构和使用方式都相同,不过它们之间仍然有以下区别。

  • GET请求会将参数跟在URL后进行传递,而POST请求则是作为HTPP消息的实体内容发送给Web服务器。当然,在Ajax请求中,这种区别对用户是不可见的
  • GET方式对传输的数据有大小限制(通常不能大于2KB),而使用POST方式传递的数据量要比GET方式大得多(理论上不受限制)
  • GET方式请求的数据会被浏览器缓存起来,因此其他人就可以从浏览器的历史记录中读取到这些数据,例如账号和密码等。在某种情况下,GET方式会带来严重的安全性问题,而POST方式相对来说就可以避免这些问题。
  • GET方式和POST方式传递的数据在服务器端的获取也不相同。在PHP中,GET方式的数据可以用$_GET[]获取,而POST方式可以用$_POST[]获取。两种方式都可以用$_REQUEST[]来获取。

由于POST和GET方式提交的所有数据都可以通过$_REQUEST[]来获取,因此只需要改变jQuery函数,就可以将程序在GET请求和POST请求之间切换。 
代码如下:

$(function(){ $("#send").click(function(){ $.post("post1.php", { 
      username :  $("#username").val() , 
      content :  $("#content").val()  
    }, function (data, textStatus){ $("#resText").html(data); // 把返回的数据添加到页面上 });
  })
})

load()、$.get()和$.post(),我们可以发现,$.get()和$.post()方法是jQuery中的全局函数,而在此之前讲的load()是对jQuery对象进行操作的。

ScheduledExecutorService类 scheduleWithFixedDelay() 和 scheduleFixedRate() 区别

 java  ScheduledExecutorService类 scheduleWithFixedDelay() 和 scheduleFixedRate() 区别已关闭评论
7月 312017
 

好记性不如烂笔头, 不用容易忘记,记录下 scheduleWithFixedDelay() 和 scheduleFixedRate() 区别

来自:http://blog.csdn.net/butingnal/article/details/12775277

先说scheduleWithFixedDelay(),

scheduleWithFixedDelay从字面意义上可以理解为就是以固定延迟(时间)来执行线程任务,它实际上是不管线程任务的执行时间的,每次都要把任务执行完成后再延迟固定时间后再执行下一次。

而scheduleFixedRate呢,是以固定频率来执行线程任务,固定频率的含义就是可能设定的固定时间不足以完成线程任务,但是它不管,达到设定的延迟时间了就要执行下一次了。

不知道大家理解了没有,下面是示例:

 

[java] view plain copy

  1. public static void scheduleWithFixedDelay() {  
  2.   
  3.     final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);  
  4.     // 响铃线程  
  5.     final Runnable beeper = new Runnable() {  
  6.         public void run() {  
  7.             SimpleDateFormat sf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);  
  8.             long time = (long) (Math.random() * 1000);  
  9.             // 输出线程的名字和使用目标对象及休眠的时间  
  10.             System.out.println(sf.format(new Date())+“线程:”+Thread.currentThread().getName()+“:Sleeping”+time+“ms”);  
  11.             try {  
  12.                 Thread.sleep(time);  
  13.             } catch (InterruptedException e) {  
[java] view plain copy

  1.         }  
  2.         }  
  3.     };  
  4.     // 设定执行线程计划,初始10s延迟,每次任务完成后延迟10s再执行一次任务  
  5.     final ScheduledFuture<?> sFuture=scheduledExecutorService.scheduleWithFixedDelay(beeper,10,10,TimeUnit.SECONDS);  
  6.   
  7.     // 40s后取消线程任务  
  8.     scheduledExecutorService.schedule(new Runnable() {  
  9.         public void run() {  
  10.             sFuture.cancel(true);  
  11.             scheduledExecutorService.shutdown();  
  12.         }  
  13.     }, 40, TimeUnit.SECONDS);  
  14.   
  15. }  


执行结果:

2013-10-16 10:45:51 线程:pool-1-thread-2:Sleeping 726ms
2013-10-16 10:46:02 线程:pool-1-thread-2:Sleeping 288ms
2013-10-16 10:46:12 线程:pool-1-thread-2:Sleeping 294ms

从执行结果数量看只执行了3次,因为每次要把任务执行完成再执行下一次,导致40s按10s的延迟时间不足以执行4次。

 

 

[html] view plain copy

  1. public static void scheduleAtFixedRate() {  
  2.     // 声明线程池  
  3.     final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);  
  4.     // 响铃线程  
  5.     final Runnable beeper = new Runnable() {  
  6.         public void run() {  
  7.             SimpleDateFormat sf = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);  
  8.             long time = (long) (Math.random() * 1000);  
  9.             // 输出线程的名字和使用目标对象及休眠的时间  
  10.             System.out.println(sf.format(new Date()) + ” 线程:” + Thread.currentThread().getName() + “:Sleeping ” + time + “ms”);  
  11.             try {  
  12.                 Thread.sleep(time);  
  13.             } catch (InterruptedException e) {  
  14.             }  
  15.         }  
  16.     };  
  17.     // 计划响铃,初始延迟10s然后以10s的频率执行响铃  
  18.     final ScheduledFuture<?> beeperHandle = scheduledExecutorService.scheduleAtFixedRate(beeper, 10, 10, TimeUnit.SECONDS);  
  19.   
  20.     // 取消响铃并关闭线程  
  21.     final Runnable cancelBeeper = new Runnable() {  
  22.         public void run() {  
  23.             System.out.println(Thread.currentThread().getName() + “CANCEL…”);  
  24.             beeperHandle.cancel(true);  
  25.             scheduledExecutorService.shutdown();  
  26.         }  
  27.     };  
  28.     // 60s后执行scheduleAtFixedRate  
  29.     scheduledExecutorService.schedule(cancelBeeper, 40, TimeUnit.SECONDS);  
  30. }  

 

执行结果:

2013-10-16 10:16:50 线程:pool-1-thread-1:Sleeping 868ms
2013-10-16 10:17:00 线程:pool-1-thread-1:Sleeping 587ms
2013-10-16 10:17:10 线程:pool-1-thread-1:Sleeping 313ms
2013-10-16 10:17:20 线程:pool-1-thread-1:Sleeping 969ms
pool-1-thread-1CANCEL…

看时间我们就可以知道是每个10s就执行下一次了。

hadoop、storm和spark的区别、比较

 开发  hadoop、storm和spark的区别、比较已关闭评论
9月 212016
 

整理的一些网上关于hadoop、storm和spark的资料。

一、hadoop、Storm该选哪一个?

为了区别hadoop和Storm,该部分将回答如下问题
1.hadoop、Storm各是什么运算
2.Storm为什么被称之为流式计算系统
3.hadoop适合什么场景,什么情况下使用hadoop
4.什么是吞吐量

首先整体认识:Hadoop是磁盘级计算,进行计算时,数据在磁盘上,需要读写磁盘;Storm是内存级计算,数据直接通过网络导入内存。读写内存比读写磁盘速度快n个数量级。根据Harvard CS61课件,磁盘访问延迟约为内存访问延迟的75000倍。所以Storm更快。

注释:
1. 延时 , 指数据从产生到运算产生结果的时间,“快”应该主要指这个。
2. 吞吐, 指系统单位时间处理的数据量。

storm的网络直传、内存计算,其时延必然比hadoop的通过hdfs传输低得多;当计算模型比较适合流式时,storm的流式处理,省去了批处理的收集数据的时间;因为storm是服务型的作业,也省去了作业调度的时延。所以从时延上来看,storm要快于hadoop。

从原理角度来讲:

  • Hadoop M/R基于HDFS,需要切分输入数据、产生中间数据文件、排序、数据压缩、多份复制等,效率较低。

  • Storm 基于ZeroMQ这个高性能的消息通讯库,不持久化数据。

为什么storm比hadoop快,下面举一个应用场景
说一个典型的场景,几千个日志生产方产生日志文件,需要进行一些ETL操作存入一个数据库。

假设利用hadoop,则需要先存入hdfs,按每一分钟切一个文件的粒度来算(这个粒度已经极端的细了,再小的话hdfs上会一堆小文件),hadoop开始计算时,1分钟已经过去了,然后再开始调度任务又花了一分钟,然后作业运行起来,假设机器特别多,几钞钟就算完了,然后写数据库假设也花了很少的时间,这样,从数据产生到最后可以使用已经过去了至少两分多钟。
而流式计算则是数据产生时,则有一个程序去一直监控日志的产生,产生一行就通过一个传输系统发给流式计算系统,然后流式计算系统直接处理,处理完之后直接写入数据库,每条数据从产生到写入数据库,在资源充足时可以在毫秒级别完成。

同时说一下另外一个场景:
如果一个大文件的wordcount,把它放到storm上进行流式的处理,等所有已有数据处理完才让storm输出结果,这时候,你再把它和hadoop比较快慢,这时,其实比较的不是时延,而是比较的吞吐了。

——————————————————————————————————————————–
最主要的方面:Hadoop使用磁盘作为中间交换的介质,而storm的数据是一直在内存中流转的。
两者面向的领域也不完全相同,一个是批量处理,基于任务调度的;另外一个是实时处理,基于流。
以水为例,Hadoop可以看作是纯净水,一桶桶地搬;而Storm是用水管,预先接好(Topology),然后打开水龙头,水就源源不断地流出来了。

——————————————————————————————————————————–
Storm的主工程师Nathan Marz表示: Storm可以方便地在一个计算机集群中编写与扩展复杂的实时计算,Storm之于实时处理,就好比Hadoop之于批处理。Storm保证每个消息都会得到处理,而且它很快——在一个小集群中,每秒可以处理数以百万计的消息。更棒的是你可以使用任意编程语言来做开发。
Storm的主要特点如下:
1.简单的编程模型。类似于MapReduce降低了并行批处理复杂性,Storm降低了进行实时处理的复杂性。
2.可以使用各种编程语言。你可以在Storm之上使用各种编程语言。默认支持Clojure、Java、Ruby和Python。要增加对其他语言的支持,只需实现一个简单的Storm通信协议即可。
3.容错性。Storm会管理工作进程和节点的故障。
4.水平扩展。计算是在多个线程、进程和服务器之间并行进行的。
5.可靠的消息处理。Storm保证每个消息至少能得到一次完整处理。任务失败时,它会负责从消息源重试消息。
6.快速。系统的设计保证了消息能得到快速的处理,使用MQ作为其底层消息队列。
7.本地模式。Storm有一个“本地模式”,可以在处理过程中完全模拟Storm集群。这让你可以快速进行开发和单元测试。

——————————————————————————————————————————–
在消耗资源相同的情况下,一般来说storm的延时低于mapreduce。但是吞吐也低于mapreduce。storm是典型的流计算系统,mapreduce是典型的批处理系统。下面对流计算和批处理系统流程

这个个数据处理流程来说大致可以分三个阶段:
1. 数据采集与准备
2. 数据计算(涉及计算中的中间存储), 题主中的“那些方面决定”应该主要是指这个阶段处理方式。
3. 数据结果展现(反馈)

1)数据采集阶段,目前典型的处理处理策略:数据的产生系统一般出自页面打点和解析DB的log,流计算将数据采集中消息队列(比如kafaka,metaQ,timetunle)等。批处理系统一般将数据采集进分布式文件系统(比如HDFS),当然也有使用消息队列的。我们暂且把消息队列和文件系统称为预处理存储。二者在延时和吞吐上没太大区别,接下来从这个预处理存储进入到数据计算阶段有很大的区别,流计算一般在实时的读取消息队列进入流计算系统(storm)的数据进行运算,批处理一系统一般会攒一大批后批量导入到计算系统(hadoop),这里就有了延时的区别。
2)数据计算阶段,流计算系统(storm)的延时低主要有一下几个方面(针对题主的问题)
A: storm 进程是常驻的,有数据就可以进行实时的处理
mapreduce 数据攒一批后由作业管理系统启动任务,Jobtracker计算任务分配,tasktacker启动相关的运算进程
B: stom每个计算单元之间数据之间通过网络(zeromq)直接传输。
mapreduce map任务运算的结果要写入到HDFS,在于reduce任务通过网络拖过去运算。相对来说多了磁盘读写,比较慢
C: 对于复杂运算
storm的运算模型直接支持DAG(有向无环图)
mapreduce 需要肯多个MR过程组成,有些map操作没有意义的

3)数据结果展现
流计算一般运算结果直接反馈到最终结果集中(展示页面,数据库,搜索引擎的索引)。而mapreduce一般需要整个运算结束后将结果批量导入到结果集中。

实际流计算和批处理系统没有本质的区别,像storm的trident也有批概念,而mapreduce可以将每次运算的数据集缩小(比如几分钟启动一次),facebook的puma就是基于hadoop做的流计算系统。

 

二、高性能并行计算引擎Storm和Spark比较

Spark基于这样的理念,当数据庞大时,把计算过程传递给数据要比把数据传递给计算过程要更富效率。每个节点存储(或缓存)它的数据集,然后任务被提交给节点。

所以这是把过程传递给数据。这和Hadoop map/reduce非常相似,除了积极使用内存来避免I/O操作,以使得迭代算法(前一步计算输出是下一步计算的输入)性能更高。

Shark只是一个基于Spark的查询引擎(支持ad-hoc临时性的分析查询)

而Storm的架构和Spark截然相反。Storm是一个分布式流计算引擎。每个节点实现一个基本的计算过程,而数据项在互相连接的网络节点中流进流出。和Spark相反,这个是把数据传递给过程。

两个框架都用于处理大量数据的并行计算。

Storm在动态处理大量生成的“小数据块”上要更好(比如在Twitter数据流上实时计算一些汇聚功能或分析)。

Spark工作于现有的数据全集(如Hadoop数据)已经被导入Spark集群,Spark基于in-memory管理可以进行快讯扫描,并最小化迭代算法的全局I/O操作。

不过Spark流模块(Streaming Module)倒是和Storm相类似(都是流计算引擎),尽管并非完全一样。

Spark流模块先汇聚批量数据然后进行数据块分发(视作不可变数据进行处理),而Storm是只要接收到数据就实时处理并分发。

不确定哪种方式在数据吞吐量上要具优势,不过Storm计算时间延迟要小。

总结下,SparkStorm设计相反,而Spark Steaming才和Storm类似,前者有数据平滑窗口(sliding window),而后者需要自己去维护这个窗口。

转自:http://flyingsnail.blog.51cto.com/5341669/1571281

**************************************************************************************************

其它文章说明:




分布式计算(Distributed Computing)

对于如何处理大数据,计算机科学界有两大方向:第一个方向是集中式计算,就是通过不断增加处理器的数量来增强单个计算机的计算能力,从而提高处理数据的速度。第二个方向是分布式计算,就是把一组计算机通过网络相互连接组成分散系统,然后将需要处理的大量数据分散成多个部分,交由分散系统内的计算机组同时计算,最后将这些计算结果合并得到最终的结果。尽管分散系统内的单个计算机的计算能力不强,但是由于每个计算机只计算一部分数据,而且是多台计算机同时计算,所以就分散系统而言,处理数据的速度会远高于单个计算机。
过去,分布式计算理论比较复杂,技术实现比较困难,因此在处理大数据方面,集中式计算一直是主流解决方案。IBM的大型机就是集中式计算的典型硬件,很多银行和政府机构都用它处理大数据。不过,对于当时的互联网公司来说,IBM的大型机的价格过于昂贵。因此,互联网公司的把研究方向放在了可以使用在廉价计算机上的分布式计算上。

服务器集群(Server Cluster)

服务器集群是一种提升服务器整体计算能力的解决方案。它是由互相连接在一起的服务器群所组成的一个并行式或分布式系统。服务器集群中的服务器运行同一个计算任务。因此,从外部看,这群服务器表现为一台虚拟的服务器,对外提供统一的服务。
尽管单台服务器的运算能力有限,但是将成百上千的服务器组成服务器集群后,整个系统就具备了强大的运算能力,可以支持大数据分析的运算负荷。Google,Amazon,阿里巴巴的计算中心里的服务器集群都达到了5000台服务器的规模。

大数据的技术基础:MapReduce、Google File System和BigTable
2003年到2004年间,Google发表了MapReduce、GFS(Google File System)和BigTable三篇技术论文,提出了一套全新的分布式计算理论。
MapReduce是分布式计算框架,GFS(Google File System)是分布式文件系统,BigTable是基于Google File System的数据存储系统,这三大组件组成了Google的分布式计算模型。
Google的分布式计算模型相比于传统的分布式计算模型有三大优势:首先,它简化了传统的分布式计算理论,降低了技术实现的难度,可以进行实际的应用。其次,它可以应用在廉价的计算设备上,只需增加计算设备的数量就可以提升整体的计算能力,应用成本十分低廉。最后,它被Google应用在Google的计算中心,取得了很好的效果,有了实际应用的证明。

后来,各家互联网公司开始利用Google的分布式计算模型搭建自己的分布式计算系统,Google的这三篇论文也就成为了大数据时代的技术核心

主流的三大分布式计算系统:Hadoop,Spark和Storm
由于Google没有开源Google分布式计算模型的技术实现,所以其他互联网公司只能根据Google三篇技术论文中的相关原理,搭建自己的分布式计算系统。
Yahoo的工程师Doug Cutting和Mike Cafarella在2005年合作开发了分布式计算系统Hadoop。后来,Hadoop被贡献给了Apache基金会,成为了Apache基金会的开源项目。Doug Cutting也成为Apache基金会的主席,主持Hadoop的开发工作。
Hadoop采用MapReduce分布式计算框架,并根据GFS开发了HDFS分布式文件系统,根据BigTable开发了HBase数据存储系统。尽管和Google内部使用的分布式计算系统原理相同,但是Hadoop在运算速度上依然达不到Google论文中的标准。

不过,Hadoop的开源特性使其成为分布式计算系统的事实上的国际标准。Yahoo,Facebook,Amazon以及国内的百度,阿里巴巴等众多互联网公司都以Hadoop为基础搭建自己的分布式计算系统。
Spark也是Apache基金会的开源项目,它由加州大学伯克利分校的实验室开发,是另外一种重要的分布式计算系统。它在Hadoop的基础上进行了一些架构上的改良。Spark与Hadoop最大的不同点在于,Hadoop使用硬盘来存储数据,而Spark使用内存来存储数据,因此Spark可以提供超过Hadoop100倍的运算速度。但是,由于内存断电后会丢失数据,Spark不能用于处理需要长期保存的数据。
Storm是Twitter主推的分布式计算系统,它由BackType团队开发,是Apache基金会的孵化项目。它在Hadoop的基础上提供了实时运算的特性,可以实时的处理大数据流。不同于Hadoop和Spark,Storm不进行数据的收集和存储工作,它直接通过网络实时的接受数据并且实时的处理数据,然后直接通过网络实时的传回结果。
Hadoop,Spark和Storm是目前最重要的三大分布式计算系统,Hadoop常用于离线的复杂的大数据处理,Spark常用于离线的快速的大数据处理,而Storm常用于在线的实时的大数据处理。

转自:http://blog.sina.com.cn/s/blog_631d3a630101nb77.html

ASCII、Unicode、GBK和UTF-8字符编码的区别联系

 其它  ASCII、Unicode、GBK和UTF-8字符编码的区别联系已关闭评论
9月 062016
 

重新温习下编码知识,来自:http://dengo.org/archives/901

很久很久以前,有一群人,他们决定用8个可以开合的晶体管来组合成不同的状态,以表示世界上的万物。他们看到8个开关状态是好的,于是他们把这称为”字节“。再后来,他们又做了一些可以处理这些字节的机器,机器开动了,可以用字节来组合出很多状态,状态开始变来变去。他们看到这样是好的,于是它们就这机器称为”计算机“。

开始计算机只在美国用。八位的字节一共可以组合出256(2的8次方)种不同的状态。 他们把其中的编号从0开始的32种状态分别规定了特殊的用途,一但终端、打印机遇上约定好的这些字节被传过来时,就要做一些约定的动作。遇上0×10, 终端就换行,遇上0×07, 终端就向人们嘟嘟叫,例好遇上0x1b, 打印机就打印反白的字,或者终端就用彩色显示字母。他们看到这样很好,于是就把这些0×20以下的字节状态称为”控制码”。他们又把所有的空 格、标点符号、数字、大小写字母分别用连续的字节状态表示,一直编到了第127号,这样计算机就可以用不同字节来存储英语的文字了。大家看到这样,都感觉 很好,于是大家都把这个方案叫做 ANSI的”Ascii”编码(American Standard Code for Information Interchange,美国信息互换标准代码)。当时世界上所有的计算机都用同样的ASCII方案来保存英文文字。

后来,就像建造巴比伦塔一样,世界各地的都开始使用计算机,但是很多国家用的不是英文,他们的字母里有许多是ASCII里没有的,为了可以在计算机保存他们的文字,他们决定采用 127号之后的空位来表示这些新的字母、符号,还加入了很多画表格时需要用下到的横线、竖线、交叉等形状,一直把序号编到了最后一个状态255。从128 到255这一页的字符集被称”扩展字符集“。从此之后,贪婪的人类再没有新的状态可以用了,美帝国主义可能没有想到还有第三世界国家的人们也希望可以用到计算机吧!

等中国人们得到计算机时,已经没有可以利用的字节状态来表示汉字,况且有6000多个常用汉字需要保存呢。但是这难不倒智慧的中国人民,我们不客气地把那些127号之后的奇异符号们直接取消掉, 规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。 中国人民看到这样很不错,于是就把这种汉字方案叫做 “GB2312“。GB2312 是对 ASCII 的中文扩展。

但是中国的汉字太多了,我们很快就就发现有许多人的人名没有办法在这里打出来,特别是某些很会麻烦别人的国家领导人。于是我们不得不继续把 GB2312 没有用到的码位找出来老实不客气地用上。 后来还是不够用,于是干脆不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。结果扩展之后的编码方案被称为 GBK 标准,GBK包括了GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。 后来少数民族也要用电脑了,于是我们再扩展,又加了几千个新的少数民族的字,GBK扩成了 GB18030。从此之后,中华民族的文化就可以在计算机时代中传承了。 中国的程序员们看到这一系列汉字编码的标准是好的,于是通称他们叫做 “DBCS“(Double Byte Charecter Set 双字节字符集)。在DBCS系列标准里,最大的特点是两字节长的汉字字符和一字节长的英文字符并存于同一套编码方案里,因此他们写的程序为了支持中文处理,必须要注意字串里的每一个字节的值,如果这个值是大于127的,那么就认为一个双字节字符集里的字符出现了。那时候凡是受过加持,会编程的计算机僧侣 们都要每天念下面这个咒语数百遍: “一个汉字算两个英文字符!一个汉字算两个英文字符……”

因为当时各个国家都像中国这样搞出一套自己的编码标准,结果互相之间谁也不懂谁的编码,谁也不支持别人的编码,连大陆和台湾这样只相隔了150海里,使用着同一种语言的兄弟地区,也分别采用了不同的 DBCS 编码方案——当时的中国人想让电脑显示汉字,就必须装上一个”汉字系统”,专门用来处理汉字的显示、输入的问题,但是那个台湾的愚昧封建人士写的算命程序就必须加装另一套支持 BIG5 编码的什么”倚天汉字系统”才可以用,装错了字符系统,显示就会乱了套!这怎么办?而且世界民族之林中还有那些一时用不上电脑的穷苦人民,他们的文字又怎么办? 真是计算机的巴比伦塔命题啊!

正在这时,大天使加百列及时出现了——一个叫 ISO (国际标谁化组织)的国际组织决定着手解决这个问题。他们采用的方法很简单:废了所有的地区性编码方案,重新搞一个包括了地球上所有文化、所有字母和符号 的编码!他们打算叫它”Universal Multiple-Octet Coded Character Set”,简称 UCS, 俗称 “unicode“。
unicode开始制订时,计算机的存储器容量极大地发展了,空间再也不成为问题了。于是 ISO 就直接规定必须用两个字节,也就是16位来统一表示所有的字符,对于ASCII里的那些“半角”字符,unicode包持其原编码不变,只是将其长度由原来的8位扩展为16位,而其他文化和语言的字符则全部重新统一编码。由于”半角”英文符号只需要用到低8位,所以其高8位永远是0,因此这种大气的方案在保存英文文本时会多浪费一倍的空间。

这时候,从旧社会里走过来的程序员开始发现一个奇怪的现象:他们的strlen函数靠不住了,一个汉字不再是相当于两个字符了,而是一个!是的,从unicode开始,无论是半角的英文字母,还是全角的汉字,它们都是统一的”一个字符“!同时,也都是统一的”两个字节“,请注意”字符”和”字节”两个术语的不同,“字节”是一个8位的物理存贮单元,而“字符”则是一个文化相关的符号。在unicode中,一个字符就是两个字节。一个汉字算两个英文字符的时代已经快过去了。

unicode同样也不完美,这里就有两个的问题,一个是,如何才能区别unicode和ascii?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果unicode统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储空间来说是极大的浪费,文本文件的大小会因此大出二三倍,这是难以接受的。

unicode在很长一段时间内无法推广,直到互联网的出现,为解决unicode如何在网络上传输的问题,于是面向传输的众多 UTF(UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。UTF-8就是在互联网上使用最广的一种unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。

UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,保留了ASCII字符一个字节的编码做为它的一部分,注意的是unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节)。从unicode到uft-8并不是直接的对应,而是要过一些算法和规则来转换。

Unicode符号范围 | UTF-8编码方式

(十六进制)         |        (二进制)
—————————————————————–
0000 0000-0000 007F | 0xxxxxxx
0000 0080-0000 07FF | 110xxxxx 10xxxxxx
0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

之前一直对字符编码很模糊,网查资料被忽悠地晕头转向,看完这篇风趣的文章,把之前模糊的知识点串联起来,并稍加总结,我和我的小伙伴们都明白了!