日期: 2021 年 6 月 1 日

iOS 开发 — Swift (八) 闭包

闭包
与 OC 中的 Block 类似,闭包主要用于异步操作执行完成后的代码回调,网络访问结果以参数的形式传递给调用方

定义一个函数
//: 定义一个 sum 函数
func sum(num1 num1: Int, num2: Int) -> Int {
return num1 + num2
}
sum(num1: 10, num2: 30)

//: 在 Swift 中函数本身就可以当作参数被定义和传递
let mySum = sum
let result = mySum(num1: 20, num2: 30)
定义一个闭包
闭包 = { (行参) -> 返回值 in // 代码实现 }
in 用于区分函数定义和代码实现
//: 闭包 = { (行参) -> 返回值 in // 代码实现 }
let sumFunc = { (num1 x: Int, num2 y: Int) -> Int in
return x + y
}
sumFunc(num1: 10, num2: 20)
闭包格式小结
// 格式: let 闭包名: (形参) -> 返回类型 = { (形参1, 形参2, …) in 代码实现 }
// 说明: 使用形参列表,可以直接提供外部参数
//
// 格式: let 闭包名: (形参类型) -> 返回类型 = { (形参1, 形参2, …) in 代码实现 }
//
// 格式: { (外部参数1 形参1, 外部参数2 形参2, …) -> 返回类型 in 代码实现 }
// 说明: 使用外部参数会方便调用
//
// 格式: { (形参列表) -> 返回类型 in 代码实现 }
*简单的闭包,如果没有参数/返回值,则 参数/返回值/in 统统都可以省略
{ 代码实现 }
let demoFunc = {
print(“hello”)
}

闭包的基本使用
GCD 异步
模拟在后台线程加载数据
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0), { () -> Void in
print(“耗时操作 \(NSThread .currentThread())”)
})
}
尾随闭包,如果闭包是*后一个参数,可以用以下写法
注意上下两段代码,} 的位置
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
print(“耗时操作 \(NSThread .currentThread())”)
}
}
闭包的简写,如果闭包中没有参数和返回值,可以省略
func loadData() {
dispatch_async(dispatch_get_global_queue(0, 0)) {
print(“耗时操作 \(NSThread .currentThread())”)
}
}
自定义闭包参数,实现主线程回调
添加没有参数,没有返回值的闭包
override func viewDidLoad() {
super.viewDidLoad()

loadData {
print(“完成回调”)
}
}

// MARK: – 自定义闭包参数
func loadData(finished: ()->()) {

dispatch_async(dispatch_get_global_queue(0, 0)) {
print(“耗时操作 \(NSThread.currentThread())”)

dispatch_sync(dispatch_get_main_queue()) {
print(“主线程回调 \(NSThread.currentThread())”)

// 执行回调
finished()
}
}
}
添加回调参数
override func viewDidLoad() {
super.viewDidLoad()

loadData4 { (html) -> () in
print(html)
}
}

/// 加载数据
/// 完成回调 – 传入回调闭包,接收异步执行的结果
func loadData4(finished: (html: String) -> ()) {

dispatch_async(dispatch_get_global_queue(0, 0)) {
print(“加载数据 \(NSThread.currentThread())”)

dispatch_sync(dispatch_get_main_queue()) {
print(“完成回调 \(NSThread.currentThread())”)

finished(html: “<h1>hello world</h1>”)
}
}
}

 

iOS 开发 — Swift (七) 函数

函数
目标
掌握函数的定义格式
掌握外部参数的用处
掌握无返回类型的三种函数定义方式
代码实现
函数定义
函数的定义
格式 func 函数名(行参列表) -> 返回值 {代码实现}
调用 let result = 函数名(值1, 参数2: 值2…)
func sum(a: Int, b: Int) -> Int {
return a + b
}

let result = sum(10, b: 20)
函数格式小结
// 格式:func 函数名(形参1: 类型 = 默认值, _ 形参2: 类型 = 默认值…) -> 返回值 { // 代码实现 }
// 说明:包含默认值的函数可以不用传递,并且可以任意组合
//
// 格式:func 函数名(形参1: 类型, _ 形参2: 类型…) -> 返回值 { // 代码实现 }
// 说明:_ 可以忽略外部参数,与其他语言的函数风格更加类似
//
// 格式:func 函数名(外部参数1 形参1: 类型, 外部参数2 形参2: 类型…) -> 返回值 { // 代码实现 }
// 说明:外部参数名供外部调用使用,形参 在函数内部使用
//
// 格式:func 函数名(形参列表) -> 返回值 { // 代码实现 }
没有返回值
没有返回值的函数,一共有三种写法
省略
()
Void
func demo(str: String) -> Void {
print(str)
}
func demo1(str: String) -> () {
print(str)
}
func demo2(str: String) {
print(str)
}

demo(“hello”)
demo1(“hello world”)
demo2(“olleh”)
外部参数
在形参名前再增加一个外部参数名,能够方便调用人员更好地理解函数的语义
格式:func 函数名(外部参数名 形式参数名: 形式参数类型) -> 返回值类型 { // 代码实现 }
Swift 2.0 中,默认*个参数名省略
func sum1(num1 a: Int, num2 b: Int) -> Int {
return a + b
}

sum1(num1: 10, num2: 20)

iOS 开发 — Swift 语法篇 (六) 集合

集合
数组
数组使用 [] 定义,这一点与 OC 相同
//: [Int]
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
遍历
let array1 = [“老王”, “老李”]

// 通过下标遍历数组
for i in 0..<array1.count {
print(array1[i])
}

// 顺序遍历数组
for s in array1 {
print(s)
}

// 遍历同时获取下标
for s in array1.enumerate() {
print(“\(s.index) \(s.element)”)
}

// 遍历同时获取下标方法2
for (i, e) in array1.enumerate() {
print(“\(i) \(e)”)
}

// 倒序遍历数组
for s in array1.reverse() {
print(s)
}

// 倒序同时获取下标
for e in array1.reverse().enumerate() {
print(e)
}
可变&不可变
let 定义不可变数组
var 定义可变数组
let array = [“zhangsan”, “lisi”]
//: 不能向不可变数组中追加内容
//array.append(“wangwu”)
var array1 = [“zhangsan”, “lisi”]

//: 向可变数组中追加内容
array1.append(“wangwu”)
数组的类型
如果初始化时,所有内容类型一致,择数组中保存的是该类型的内容
如果初始化时,所有内容类型不一致,择数组中保存的是 NSObject
// array1 仅允许追加 String 类型的值
//array1.append(18)

var array2 = [“zhangsan”, 18]
// 在 Swift 中,数字可以直接添加到集合,不需要再转换成 `NSNumber`
array2.append(100)
// 如果向 数组添加 `CG` 结构体,需要使用 `NSValue` 转换
array2.append(NSValue(CGPoint: CGPoint(x: 10, y: 10)))
数组的定义和实例化
使用 : 可以只定义数组的类型
实例化之前不允许添加值
使用 [类型]() 可以实例化一个空的数组
var array3: [String]
//: 实例化之前不允许添加值
//array3.append(“laowang”)
//: 实例化一个空的数组
array3 = [String]()
array3.append(“laowang”)
数组的合并
必须是相同类型的数组才能够合并
开发中,通常数组中保存的对象类型都是一样的!
array3 += array1

// 必须是相同类型的数组才能够合并,以下两句代码都是不允许的
//array3 += array2
//array2 += array3
数组的删除
//: 删除指定位置的元素
array3.removeAtIndex(3)
//: 清空数组
array3.removeAll()
内存分配
如果向数组中追加元素,超过了容量,会直接在现有容量基础上 * 2
var array: [String] = [String]()

for i in 0..<9 {
array.append(“\(i) – hello”)
print(“\(array) \(array.capacity)”)
}
字典
定义
同样使用 [] 定义字典
let 不可变字典
var 可变字典
[String : NSObject] 是*常用的字典类型
//: [String : NSObject] 是*常用的字典类型
var dict = [“name”: “zhangsan”, “age”: 18]
赋值
赋值直接使用 dict[key] = value 格式
如果 key 不存在,会设置新值
如果 key 存在,会覆盖现有值
//: * 如果 key 不存在,会设置新值
dict[“title”] = “boss”
//: * 如果 key 存在,会覆盖现有值
dict[“name”] = “lisi”
dict
删除一个 KEY
dict.removeValueForKey(“age”)
遍历
k,v 可以随便写
前面的是 key
后面的是 value
for d in dict {
print(“\(d.0) \(d.1)”)
}

// 遍历
for (k, v) in dict {
print(“\(k) ~~~ \(v)”)
}
合并字典
如果 key 不存在,会建立新值,否则会覆盖现有值
//: 合并字典
var dict1 = [String: NSObject]()
dict1[“nickname”] = “大老虎”
dict1[“age”] = 100

//: 如果 key 不存在,会建立新值,否则会覆盖现有值
for (k, v) in dict1 {
dict[k] = v
}
print(dict)

 

iOS 开发 — Swift 语法篇 (五) 字符串

字符串
在 Swift 中*大多数的情况下,推荐使用 String 类型

String 是一个结构体,性能更高
String 目前具有了*大多数 NSString 的功能
String 支持直接遍历
NSString 是一个 OC 对象,性能略差
Swift 提供了 String 和 NSString 之间的无缝转换
字符串演练
遍历字符串中的字符
for s in str.characters {
print(s)
}
字符串长度
let str = “hello世界”

// 返回字符串转换成对应编码的字节数
// 一个中文在 UTF8 字符集中占 3 个字节
print(str.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))

// 返回字符个数 – 字符串长度
print(str.characters.count)
字符串拼接
直接在 “” 中使用 \(变量名) 的方式可以快速拼接字符串
let name = “老王”
let age = 18
let point = CGPoint(x: 100, y: 200)

print(“\(name) \(age) \(point)”)
我和我的小伙伴再也不要考虑 stringWithFormat 了 😀

可选项的拼接
如果变量是可选项,拼接的结果中会有 Optional
为了应对强行解包存在的风险,苹果提供了 ?? 操作符
?? 操作符用于检测可选项是否为 nil
如果不是 nil,使用当前值
如果是 nil,使用后面的值替代
let str1 = “Hello”
let str2 = “World”
let i: Int? = 32
str = “\(i ?? 0) 个 ” + str1 + ” ” + str2
格式化字符串
在实际开发中,如果需要指定字符串格式,可以使用 String(format:…) 的方式
let h = 8
let m = 23
let s = 9
let timeString = String(format: “%02d:%02d:%02d”, arguments: [h, m, s])
let timeStr = String(format: “%02d:%02d:%02d”, h, m, s)
String & Range 的结合
在 Swift 中,String 和 Range连用时,语法结构比较复杂
如果不习惯 Swift 的语法,可以将字符串转换成 NSString 再处理
let helloString = “我们一起飞”
(helloString as NSString).substringWithRange(NSMakeRange(2, 3))
使用 Range 的写法
// advancedBy(正数) 向右增加索引值
// advancedBy(负数) 向左减少索引值
let startIndex = str.startIndex.advancedBy(1)
let endIndex = str.endIndex.advancedBy(-1)

let subString3 = str.substringWithRange(startIndex..<endIndex)

print(subString3)

iOS 开发 — Swift 语法篇 (四) 循环

for 循环
OC 风格的循环
var sum = 0
for var i = 0; i < 10; i++ {
sum += i
}
print(sum)
for-in,0..<10 表示从0到9
sum = 0
for i in 0..<10 {
sum += i
}
print(sum)
范围 0…10 表示从0到10
sum = 0
for i in 0…10 {
sum += i
}
print(sum)
注意:..< 和 … 用于定义 Range 类型,左右都不要添加空格

格式: for 变量 in 范围 { // 代码 }

省略下标
_ 能够匹配任意类型
_ 表示忽略对应位置的值
for _ in 0…10 {
print(“hello”)
}

 

iOS 开发 — Swift 语法篇 (三) 控制流

if
Swift 中没有 C 语言中的非零即真概念
在逻辑判断时必须显示地指明具体的判断条件 true / false
if 语句条件的 () 可以省略
但是 {} 不能省略
let num = 200
if num < 10 {
print(“比 10 小”)
} else if num > 100 {
print(“比 100 大”)
} else {所有文章
print(“10 ~ 100 之间的数字”)
}
三目运算
Swift 中的 三目 运算保持了和 OC 一致的风格
x > 20 ? print(“大了”) : print(“小了”)

/**
`()` 表示执行
*/
x > 20 ? print(“真的大了”) : ()
适当地运用三目,能够让代码写得更加简洁

可选项判断
由于可选项的内容可能为 nil,而一旦为 nil 则不允许参与计算
因此在实际开发中,经常需要判断可选项的内容是否为 nil
单个可选项判断
let url = NSURL(string: “http://www.baidu.com”)

//: 方法1: 强行解包 – 缺陷,如果 url 为空,运行时会崩溃
let request = NSURLRequest(URL: url!)

//: 方法2: 首先判断 – 代码中仍然需要使用 `!` 强行解包
if url != nil {
let request = NSURLRequest(URL: url!)
}

//: 方法3: 使用 `if let`,这种方式,表明一旦进入 if 分支,u 就不在是可选项
if let u = url where u.host == “www.baidu.com” {
let request = NSURLRequest(URL: u)
}
可选项条件判断
//: 1> 初学 swift 一不小心就会让 if 的嵌套层次很深,让代码变得很丑陋
if let u = url {
if u.host == “www.baidu.com” {
let request = NSURLRequest(URL: u)
}
}

//: 2> 使用 where 关键字,
if let u = url where u.host == “www.baidu.com” {
let request = NSURLRequest(URL: u)
}
小结
if let 不能与使用 &&、|| 等条件判断
如果要增加条件,可以使用 where 子句
注意:where 子句没有智能提示
多个可选项判断
//: 3> 可以使用 `,` 同时判断多个可选项是否为空
let oName: String? = “张三”
let oNo: Int? = 100

if let name = oName {
if let no = oNo {
print(“姓名:” + name + ” 学号: ” + String(no))
}
}

if let name = oName, let no = oNo {
print(“姓名:” + name + ” 学号: ” + String(no))
}
判断之后对变量需要修改
let oName: String? = “张三”
let oNum: Int? = 18

if var name = oName, num = oNum {

name = “李四”
num = 1

print(name, num)
}
guard
guard 是与 if let 相反的语法,Swift 2.0 推出的
let oName: String? = “张三”
let oNum: Int? = 18

guard let name = oName else {
print(“name 为空”)
return
}

guard let num = oNum else {
print(“num 为空”)
return
}

// 代码执行至此,name & num 都是有值的
print(name)
print(num)
在程序编写时,条件检测之后的代码相对是比较复杂的
使用 guard 的好处
能够判断每一个值
在真正的代码逻辑部分,省略了一层嵌套
switch
switch 不再局限于整数
switch 可以针对任意数据类型进行判断
不再需要 break
每一个 case后面必须有可以执行的语句
要保证处理所有可能的情况,不然编译器直接报错,不处理的条件可以放在 default 分支中
每一个 case 中定义的变量仅在当前 case 中有效,而 OC 中需要使用 {}
let score = “优”

switch score {
case “优”:
let name = “学生”
print(name + “80~100分”)
case “良”: print(“70~80分”)
case “中”: print(“60~70分”)
case “差”: print(“不及格”)
default: break
}
switch 中同样能够赋值和使用 where 子句
let point = CGPoint(x: 10, y: 10)
switch point {
case let p where p.x == 0 && p.y == 0:
print(“中心点”)
case let p where p.x == 0:
print(“Y轴”)
case let p where p.y == 0:
print(“X轴”)
case let p where abs(p.x) == abs(p.y):
print(“对角线”)
default:
print(“其他”)
}
如果只希望进行条件判断,赋值部分可以省略
switch score {
case _ where score > 80: print(“优”)
case _ where score > 60: print(“及格”)
default: print(“其他”)
}

 

iOS 开发 — Swift 语法篇 (二) 可选项

Optional 是 Swift 的一大特色,也是 Swift 初学者*容易困惑的问题
定义变量时,如果指定是可选的,表示该变量可以有一个指定类型的值,也可以是 nil
定义变量时,在类型后面添加一个 ?,表示该变量是可选的
变量可选项的默认值是 nil
常量可选项没有默认值,主要用于在构造函数中给常量设置初始数值
// Optional 可能有两个值 (None / Some)
// 格式(1. 自动推导):var 变量名: Optional = 值
let x: Optional = 20
// 格式(2. 指定类型):var 变量
let y: Optional<Int> = 30
// 格式(3. 简化格式):var 变量名: 类型? = 值
let z: Int? = 10

// 可选值在参与计算前,必须`解包 unwarping`
// 只有`解包(unwrap)`后才能参与计算
// 在变量后添加一个 `!`,可以强行解包
// `?` 是用于定义的
// `!` 是用于解包的,程序员要对每一个 `!` 负责
print(x! + y! + z!)
如果 Optional 值是 nil,不允许参与计算
只有解包(unwrap)后才能参与计算
在变量后添加一个 !,可以强行解包
注意:必须要确保解包后的值不是 nil,否则会报错

// 常量可选项必须要设置初始值
let x: Int? //= 20
x = 20
// 变量可选项默认值是 nil
var y: Int? //= 10
y = 20

// unexpectedly found nil while unwrapping an Optional value
// 在对可选项解包时发现 nil,会报错!
if y == nil {
print(“y值为 nil”)
} else {
print(x! + y!)
}
常见错误
unexpectedly found nil while unwrapping an Optional value

翻译

在对可选项[解包]时发现 nil

?? 运算符
?? 运算符可以用于判断 变量/常量 的数值是否是 nil,如果是则使用后面的值替代
在使用 Swift 开发时,?? 能够简化代码的编写
// 常量可选项必须要设置初始值
var x: Int? //= 20
// x = 30
// 变量可选项默认值是 nil
var y: Int? //= 10
y = 20

print((x ?? 0) + (y ?? 0))
注意:?? 的优先级低,在使用时,应该注意使用 ()

var str: String? = “老王”

// 注意 `??` 的优先级低,在使用时,应该注意使用 `()`
print((str ?? “无名”) + ” 你好”)

 

iOS 开发 — Swift 语法篇 (一) 常量和变量

let 定义常量,一经赋值不允许再修改
var 定义变量,赋值之后仍然可以修改

// 定义常量并且直接设置数值
let x: Int = 10
// 常量数值一经设置,不能修改,以下代码会报错
// x = 30

// 使用 `: 类型`,仅仅只定义类型,而没有设置数值
let y: Int
// 常量有一次设置数值的机会,以下代码没有问题,因为 `y` 还没有被设置数值
y = 10

// 一旦设置了数值之后,则不能再次修改,以下代码会报错,因为 `y` 已经被设置了数值
// y = 50

print(x + y)

// 变量设置数值之后,可以继续修改数值
var z: Int
z = 100
z = 200

print(x + y + z)

自动推导
Swift 能够根据右边的代码,推导出变量的准确类型
通常在开发时,不需要指定变量的类型
如果要指定变量,可以在变量名后使用 :,然后跟上变量的类型
重要技巧:Option + Click 可以查看变量的类型

没有隐式转换!!!
Swift 对数据类型要求异常严格
任何时候,都不会做隐式转换
如果要对不同类型的数据进行计算,必须要显式的转换

// 注意:Int & Double 都是结构体,而不是基本数据类型
// 整数默认的类型是 Int
let x: Int = 200
// 小数的默认类型是 Double
let y: Double = 10.5

// Binary operator ‘+’ cannot be applied to operands of type ‘Int’ and ‘Double’
// 不同数据类型之间不能直接计算
// print(x + y)
// 如果要对不同类型的数据进行计算,必须要显式的转换
print(x + Int(y))
print(Double(x) + y)
let & var 的选择
应该尽量先选择常量,只有在必须修改时,才需要修改为 var
在 Xcode 7.0 中,如果没有修改变量,Xcode 会提示修改为 let

从分布式一致性谈到CAP理论、BASE理论

问题的提出

在计算机科学领域,分布式一致性是一个相当重要且被广泛探索与论证问题,首先来看三种业务场景。

1、火车站售票

假如说我们的终端用户是一位经常坐火车的旅行家,通常他是去车站的售票处购买车 票,然后拿着车票去检票口,再坐上火车,开始一段美好的旅行—-一切似乎都是那么和谐。想象一下,如果他选择的目的地是杭州,而某一趟开往杭州的火车 只剩下*后一张车票,可能在同一时刻,不同售票窗口的另一位乘客也购买了同一张车票。假如说售票系统没有进行一致性的保障,两人都购票成功了。而在检票口 检票的时候,其中一位乘客会被告知他的车票无效—-当然,现代的中国铁路售票系统已经很少出现这样的问题了。但在这个例子中我们可以看出,终端用户对 于系统的需求非常简单:

“请售票给我,如果没有余票了,请在售票的时候就告诉我票是无效的”

这就对购票系统提出了严格的一致性要求—-系统的数据(本例中指的就是那趟开往杭州的火车的余票数)无论在哪个售票窗口,每时每刻都必须是准确无误的!

2、银行转账

假如我们的终端用户是一位刚毕业的大学生,通常在拿到*个月工资的时候,都会选 择向家里汇款。当他来到银行柜台,完成转账操作后,银行的柜台服务员会友善地提醒他:”您的转账将在N个工作日后到账!”。此时这名毕业生有一定的沮丧, 会对那名柜台服务员叮嘱:”好吧,多久没关系,钱不要少就好了!”—-这也成为了几乎所有用户对于现代银行系统*基本的需求

3、网上购物

假如说我们的终端用户是一位网购达人,当他看见一件库存量为5的心仪商品,会迅速地确认购买,写下收货地址,然后下单—-然而,在下单的那个瞬间,系统可能会告知该用户:”库存量不足!”。此时*大部分消费者都会抱怨自己动作太慢,使得心爱的商品被其他人抢走了。

但其实有过网购系统开发经验的工程师一定明白,在商品详情页上显示的那个库存量,通常不是该商品的真实库存量,只有在真正下单购买的时候,系统才会检查该商品的真实库存量。但是,谁在意呢?

 

问题的解读

对于上面三个例子,相信大家一定看出来了,我们的终端用户在使用不同的计算机产品时对于数据一致性的需求是不一样的:

1、有些系统,既要快速地响应用户,同时还要保证系统的数据对于任意客户端都是真实可靠的,就像火车站售票系统

2、有些系统,需要为用户保证*对可靠的数据安全,虽然在数据一致性上存在延时,但*终务必保证严格的一致性,就像银行的转账系统

3、有些系统,虽然向用户展示了一些可以说是”错误”的数据,但是在整个系统使用过程中,一定会在某一个流程上对系统数据进行准确无误的检查,从而避免用户发生不必要的损失,就像网购系统

 

分布一致性的提出

在分布式系统中要解决的一个重要问题就是数据的复制。在我们的日常开发经验中,相 信很多开发人员都遇到过这样的问题:假设客户端C1将系统中的一个值K由V1更新为V2,但客户端C2无法立即读取到K的*新值,需要在一段时间之后才能 读取到。这很正常,因为数据库复制之间存在延时。

分布式系统对于数据的复制需求一般都来自于以下两个原因:

1、为了增加系统的可用性,以防止单点故障引起的系统不可用

2、提高系统的整体性能,通过负载均衡技术,能够让分布在不同地方的数据副本都能够为用户提供服务

数据复制在可用性和性能方面给分布式系统带来的巨大好处是不言而喻的,然而数据复制所带来的一致性挑战,也是每一个系统研发人员不得不面对的。

所谓分布一致性问题,是指在分布式环境中引入数据复制机制之后,不同数据节点之间 可能出现的,并无法依靠计算机应用程序自身解决的数据不一致的情况。简单讲,数据一致性就是指在对一个副本数据进行更新的时候,必须确保也能够更新其他的 副本,否则不同副本之间的数据将不一致。

那么如何解决这个问题?一种思路是”既然是由于延时动作引起的问题,那我可以将写入的动作阻塞,直到数据复制完成后,才完成写入动作”。 没错,这似乎能解决问题,而且有一些系统的架构也确实直接使用了这个思路。但这个思路在解决一致性问题的同时,又带来了新的问题:写入的性能。如果你的应 用场景有非常多的写请求,那么使用这个思路之后,后续的写请求都将会阻塞在前一个请求的写操作上,导致系统整体性能急剧下降。

总得来说,我们无法找到一种能够满足分布式系统所有系统属性的分布式一致性解决方案。因此,如何既保证数据的一致性,同时又不影响系统运行的性能,是每一个分布式系统都需要重点考虑和权衡的。于是,一致性级别由此诞生:

1、强一致性

这种一致性级别是*符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大

2、弱一致性

这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不久承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态

3、*终一致性

*终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。这里之所以将*终一致性单独提出来,是因为它是弱一致性中非常推崇的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型

 

分布式环境的各种问题

分布式系统体系结构从其出现之初就伴随着诸多的难题和挑战:

1、通信异常

从集中式向分布式演变的过程中,必然引入网络因素,由于网络本身的不可靠性,因此 也引入了额外的问题。分布式系统需要在各个节点之间进行网络通信,因此每次网络通信都会伴随着网络不可用的风险,网络光纤、路由器或是DNS等硬件设备或 是系统不可用都会导致*终分布式系统无法顺利完成一次网络通信。另外,即使分布式系统各个节点之间的网络通信能够正常进行,其延时也会大于单机操作。通常 我们认为现代计算机体系结构中,单机内存访问的延时在纳秒数量级(通常是10ns),而正常的一次网络通信的延迟在0.1~1ms左右(相当于内存访问延 时的105倍),如此巨大的延时差别,也会影响到消息的收发过程,因此消息丢失和消息延迟变得非常普遍

2、网络分区

当网络由于发生异常情况,导致分布式系统中部分节点之间的网络延时不断增大,*终导致组成分布式系统的所有节点中,只有部分节点之间能够正常通信,而另一些节点则不能—-我们将这个现象称为网络分区。当网络分区出现时,分布式系统会出现局部小集群,在*端情况下,这些局部小集群会独立完成原本需要整个分布式系统才能完成的功能,包括对数据的事物处理,这就对分布式一致性提出了非常大的挑战

3、三态

上面两点,我们已经了解到在分布式环境下,网络可能会出现各式各样的问题,因此分布式系统的每一次请求与响应,存在特有的三态概念,即成功、失败、超时。 在传统的单机系统中,应用程序在调用一个函数之后,能够得到一个非常明确的响应:成功或失败。而在分布式系统中,由于网络是不可靠的,虽然在*大部分情况 下,网络通信也能够接受到成功或失败的响应,当时当网络出现异常的情况下,就可能会出现超时现象,通常有以下两种情况:

(1)由于网络原因,该请求并没有被成功地发送到接收方,而是在发送过程中就发生了消息丢失现象

(2)该请求成功地被接收方接收后,进行了处理,但是在将响应反馈给发送方的过程中,发生了消息丢失现象

当出现这样的超时现象时,网络通信的发起方是无法确定当前请求是否被成功处理的

4、节点故障

节点故障则是分布式环境下另一个比较常见的问题,指的是组成分布式系统的服务器节点出现的宕机或”僵死”现象,通常根据经验来说,每个节点都有可能出现故障,并且每天都在发生

 

分布式事务

随着分布式计算的发展,事务在分布式计算领域也得到了广泛的应用。在单机数据库中,我们很容易能够实现一套满足ACID特性的事务处理系统,但在分布式数据库中,数据分散在各台不同的机器上,如何对这些数据进行分布式的事务处理具有非常大的挑战。

分布式事务是指事务的参与者、支持事物的服务器、资源服务器以及事物管理器分别位于分布式系统的不同节点上,通常一个分布式事务中会涉及对多个数据源或业务系统的操作。

可以设想一个*典型的分布式事务场景:一个跨银行的转账操作涉及调用两个异地的银 行服务,其中一个是本地银行提供的取款服务,另一个则是目标银行提供的存款服务,这两个服务本身是无状态并且相互独立的,共同构成了一个完整的分布式事务。如果从本地银行取款成功,但是因为某种原因存款服务失败了,那么就必须回滚到取款之前的状态,否则用户可能会发现自己的钱不翼而飞了。

从这个例子可以看到,一个分布式事务可以看做是多个分布式的操作序列组成的,例如 上面例子的取款服务和存款服务,通常可以把这一系列分布式的操作序列称为子事务。因此,分布式事务也可以被定义为一种嵌套型的事务,同时也就具有了 ACID事物特性。但由于在分布式事务中,各个子事务的执行是分布式的,因此要实现一种能够保证ACID特性的分布式事务处理系统就显得格外复杂。

 

CAP理论

一个经典的分布式系统理论。CAP理论告诉我们:一个分布式系统不可能同时满足一致性(C:Consistency)、可用性(A:Availability)和分区容错性(P:Partition tolerance)这三个基本需求,*多只能同时满足其中两项。

1、一致性

在分布式环境下,一致性是指数据在多个副本之间能否保持一致的特性。在一致性的需求下,当一个系统在数据一致的状态下执行更新操作后,应该保证系统的数据仍然处于一直的状态。

对于一个将数据副本分布在不同分布式节点上的系统来说,如果对*个节点的数据进 行了更新操作并且更新成功后,却没有使得第二个节点上的数据得到相应的更新,于是在对第二个节点的数据进行读取操作时,获取的依然是老数据(或称为脏数 据),这就是典型的分布式数据不一致的情况。在分布式系统中,如果能够做到针对一个数据项的更新操作执行成功后,所有的用户都可以读取到其*新的值,那么 这样的系统就被认为具有强一致性

2、可用性

可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。这里的重点是”有限时间内”和”返回结果”。

“有限时间内”是指,对于用户的一个操作请求,系统必须能够在指定的时间内返回对 应的处理结果,如果超过了这个时间范围,那么系统就被认为是不可用的。另外,”有限的时间内”是指系统设计之初就设计好的运行指标,通常不同系统之间有很 大的不同,无论如何,对于用户请求,系统必须存在一个合理的响应时间,否则用户便会对系统感到失望。

“返回结果”是可用性的另一个非常重要的指标,它要求系统在完成对用户请求的处理后,返回一个正常的响应结果。正常的响应结果通常能够明确地反映出队请求的处理结果,即成功或失败,而不是一个让用户感到困惑的返回结果。

3、分区容错性

分区容错性约束了一个分布式系统具有如下特性:分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务,除非是整个网络环境都发生了故障。

网络分区是指在分布式系统中,不同的节点分布在不同的子网络(机房或异地网络) 中,由于一些特殊的原因导致这些子网络出现网络不连通的状况,但各个子网络的内部网络是正常的,从而导致整个系统的网络环境被切分成了若干个孤立的区域。 需要注意的是,组成一个分布式系统的每个节点的加入与退出都可以看作是一个特殊的网络分区。

既然一个分布式系统无法同时满足一致性、可用性、分区容错性三个特点,所以我们就需要抛弃一样:

%title插图%num

用一张表格说明一下:

选    择 说    明
CA 放弃分区容错性,加强一致性和可用性,其实就是传统的单机数据库的选择
AP 放弃一致性(这里说的一致性是强一致性),追求分区容错性和可用性,这是很多分布式系统设计时的选择,例如很多NoSQL系统就是如此
CP 放弃可用性,追求一致性和分区容错性,基本不会选择,网络问题会直接让整个系统不可用

需要明确的一点是,对于一个分布式系统而言,分区容错性是一个*基本的要求。因为 既然是一个分布式系统,那么分布式系统中的组件必然需要被部署到不同的节点,否则也就无所谓分布式系统了,因此必然出现子网络。而对于分布式系统而言,网 络问题又是一个必定会出现的异常情况,因此分区容错性也就成为了一个分布式系统必然需要面对和解决的问题。因此系统架构师往往需要把精力花在如何根据业务 特点在C(一致性)和A(可用性)之间寻求平衡。

 

BASE理论

BASE是Basically Available(基本可用)、Soft state(软状态)和Eventually consistent(*终一致性)三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结, 是基于CAP定理逐步演化而来的。BASE理论的核心思想是:即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到*终一致性。接下来看一下BASE中的三要素:

1、基本可用

基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性—-注意,这*不等价于系统不可用。比如:

(1)响应时间上的损失。正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒

(2)系统功能上的损失:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面

2、软状态

软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时

3、*终一致性

*终一致性强调的是所有的数据副本,在经过一段时间的同步之后,*终都能够达到一个一致的状态。因此,*终一致性的本质是需要系统保证*终数据能够达到一致,而不需要实时保证系统数据的强一致性。

总的来说,BASE理论面向的是大型高可用可扩展的分布式系统,和传统的事物ACID特性是相反的,它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但*终达到一致状态。但同时,在实际的分布式场景中,不同业务单元和组件对数据一致性的要求是不同的,因此在具体的分布式系统架构设计过程中,ACID特性和BASE理论往往又会结合在一起。

转载自:https://www.cnblogs.com/szlbm/p/5588543.html

PowerDesigner逆向工程导入MYSQL数据库总结

转载自:https://www.cnblogs.com/mophy/p/5930000.html

PowerDesigner逆向工程导入MYSQL数据库总结

由于日常数据建模经常使用PowerDesigner,使用逆向工程能更加快速的生成模型提高效率,所以总结使用如下:

首先现在PowerDesigner,这里提供PD16.5版本链接: http://pan.baidu.com/s/1i4SyIRN 密码: fb2m

1.      安装MYSQL的ODBC驱动

Connector/ODBC 5.1.13 下载地址:

http://dev.mysql.com/downloads/connector/odbc/5.1.html

%title插图%num

选择win-64 MIS安装包,进行直接安装就可以了。

2.      配置OBDC驱动连接

选择控制面板->系统和安全->管理工具–>ODBC 数据源

%title插图%num

%title插图%num

 

%title插图%num

%title插图%num

%title插图%num

 

3.      打开PowerDesigner :

1)文件->新建新物理模型

%title插图%num

%title插图%num

2)数据库->connect to a Data Source

%title插图%num

 

填入基本信息

%title插图%num

4)开始逆向生成

%title插图%num

%title插图%num

%title插图%num

%title插图%num

确定后等待生成就好了。

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速