- Rolph Johnson认为:架构是一种主观上的东西,是专家级的项目开发人员对系统设计的一些可共享的理解
- 架构中包括一些决定,开发者希望这些决定能尽早作出,因为在开发者看来它们是难以改变的。
- 如果你发现某些决定不像你想象中的那么难以改变,那么它就不再与架构相关
- 理解: B/S (SmartClient、C/S) 架构, DotNet 架构, J2EE架构
企业应用的特点
- 涉及到持久化数据
- 很多人同时访问数据
- 含有大量操作数据的用户界面
- 与散布在企业内部或周围的其他的应用集成
- 各种异构系统的概念含有不一致性
- 业务逻辑通常是最没有逻辑的东西
- 企业应用并非都是大型的,但可能都为企业提供巨大的价值
· 性能:很多时候,增加更多的服务器比增加更多的程序员便宜;如果增加服务器对性能的提升较大,则说明应用的伸缩性好
· 分层:上层是用下层定义的各种服务,而下层对上层一无所知;分层的缺陷是不能封装所有的东西,因此可能带来级联更改,过多的曾影响性能;Layer和Tier的区别是Tier可能更多的意味物理上的分离
Brown分层模型
表现层>>控制层>>领域层>>数据映射层>>数据源层
Core J2EE分层模型
客户层>>表现层>>业务层>>集成层>>资源层
MS DNA分层模型
表现层>>业务逻辑层>>数据访问层
Marinescu分层模型
表现层>>应用层>>服务层>>领域层>>持久层
· 领域模型:使用不同职责的对象来联合解决业务问题,而不是通过事务脚本来处理数据
· 阻抗不匹配:对象模型和关系型数据库之间的不匹配,通常通过对象-关系映射(ORM)解决
· 软件事务的四个特性
1. 原子性:要么全部成功,要么全部会滚
2. 一致性:事务开始和完成时,资源都不应该被破坏
3. 隔离性:事务成功完成之前,其影响不应该被看到
4. 持久性:事务不会因为任何崩溃而丢失更改
· 事务的隔离级别(由高而低)
1. 可串行化:完全隔离,并发执行的结果与以某种顺序依次执行的结果相同
2. 可重复读:允许幻读,更新者向集合中插入了一些元素而读的人只能看到其中一部分
3. 读已提交:允许不可重复读,所有已经提交的数据都可以读
4. 读未提交:允许脏读,允许读未提交的数据
· 会话状态:无状态对象是一种不良设计;用无状态的服务器可以实现有状态的会话;如果有很多会话空闲,可以考虑用数据库存储会话;如果需要频繁访问会话,则应该使用服务器会话
· 分布策略:分布对象的第一定律:不要使用分布对象;分布对象的第二定律:节约使用分布对象
领域逻辑模式分为 事物脚本、领域模型、表模块和服务层四种模式很多设计者喜欢把业务逻辑分成两类:领域逻辑和应用逻辑,前者只与问题领域有关、而后者有时被称为工作流逻辑
1. 事物脚本
通过使用SQL语句或者存储过程返回记录集,记录集在系统的各层之间传递,在必要的时候可以通过更新记录集、使用SQL语句或者存储过程的方式更新数据库
事物脚本胜在简单,通常应用在小型的项目和系统中,但业务逻辑越来越复杂,使用这一模式就越来越难以保持良好设计,因为在程序里面充斥了大量的SQL语句和命令,一旦数据结构发生更改或者需要对系统进行修改,可能会出现许多难以发现的问题
2. 领域模型
领域模型是合并了行为和数据的领域的对象模型,领域模型创建了一张由互联对象组成的网,其中的每个对象都代表着某个有意义的个体,可能大到一个公司或者小到订单的一行
简单领域可以使用活动记录,即简单的单条数据记录和单个对象对应的模式,一个对象对应数据库中的一个表
复杂领域模型需要使用数据映射器,它可能使用继承、策略或者其他的设计模式,是一张由互联的细粒度对象组成的复杂网络,我们经常会看到:多个类通过交互来完成很简单的任务
在面向对象技术中,通过从一个对象到另一个对象的连续传递可以把行为传递给最有资格处理的对象,它同时消除了很多条件判断行为
领域模型的要点在于隐藏数据库的存在
3. 表模块
表模块是处理某一数据库表或视图中所有行的业务逻辑的一个实例
表模块通过强类型或弱类型的数据集与对象结合使用,使用主键查询数据,是.Net中使用的很多的一种模式,主要使用主键、半对象化的操作数据---之所以说是半结构化,是因为所用的对象基本上只具有行为,通过传入参数执行特定的操作或者查询记录集,而几乎不承载任何数据
在.net中,这种模式因为其容易和UI进行绑定和交互,所以倍受欢迎
4. 服务层
通过一个服务层来定义应用程序边界,在服务层中建立一组可用的操作的集合,并在每个操作内部协调应用程序的响应
服务层是一种组织业务逻辑的模式,有点类似于业务外观;WEB SERVICE通常担任着服务层的角色
服务层可以通过领域外观方法和操作脚本方法实现,领域外观方法中,服务层以领域模型之上的瘦外观集合方式出现,负责实现外观的类中不不包含业务逻辑;而在操作脚本方法中 ,服务层由一组相对复杂的类组成,这些类直接实现应用逻辑,但将领域逻辑委托给封装好的领域对象类
服务层的类的接口是粗粒度的,适合于远程调用。但是,在开始时,我们应该仅设计一个本地调用的服务层,在需要远程调用时,再在服务层上增加一个远程外观。
并发管理的正确目标是尽量增加对数据的正确访问,同时减少冲突
离线并发模式有两种:使用乐观离线锁、使用悲观离线锁
离线锁可以理解为一种非服务器管理的锁,或者说是自管理的锁,应用在适当的地方注册锁,获取数据,然后离线,并对数据进行离线的操作;其他的应用通过检测已经注册的锁来决定是否进行并发操作
1. 悲观离线锁
悲观离线锁假设会话冲突的可能性很大,从而对系统的并发进性进行限制
在对不一致读的要求不高时,第一选择是使用独占写锁(不可以再添加任何读锁,当然写锁也不能);如必须读出最新数据,而不在乎是否要修改,则应使用独占读锁(不可以再添加任何写锁,但读锁是允许的)。结合以上两种,提供互斥读锁的限制,又有互斥写锁的并发性的锁称为 读/写锁---读/写锁互斥不能同时加,但并发的读锁是允许的
构建悲观离线锁的步骤:决定使用哪种锁>>构建一个锁管理对象>>定义业务事务使用锁的过程
让锁管理对象在锁不可用时抛出异常而不是等待锁释放,可以免除死锁
悲观离线锁作为乐观离线锁的补充,只在真正需要的时候才应该使用
2. 乐观离线锁
乐观离线锁假设会话冲突的可能性很小,从而使得多用户对一份数据进行处理成为可能
通过冲突检测和事务会滚来防止并发事务中的冲突
本质就是通过将会话中的版本号与当前记录数据的版本号相比较,事务成功提交以后版本号增加;或者在更新的SQL语句中包含对所有字段的检查,可以不需要为数据库增加版本字段,但可能导致性能损失
乐观离线锁必须自定检查以防止不一致读
一个高效的合并策略能使乐观离线锁变得非常强大,当冲突发生时,合并策略可以合并更改并重新提交