代码改变世界

最近架构随想

2014-07-28 08:19 by 圣殿骑士, 6108 阅读, 62 评论, 收藏, 编辑

今天新加坡放假,闲来无事就发一篇博客:一则总结归纳项目构架经验,审视并逐步提高自己;再者分享最近学习所得,希望各位能讨论并给些建议。六月三十日从原来公司离职,七月一日入职新公司,不知不觉已经快一个月了。最近忙于学习新的行业知识以及项目的重构设计,没有时间发博客,也没有时间回复邮件及博文评论,忘各位见谅!

今天发几张项目重构设计草图,如果大家对项目分层与文件夹结构比较感兴趣,可以参考几年前弦哥.Net项目分层与文件夹结构大全(最佳架子奖,吐槽奖,阴沟翻船奖揭晓),这次的架构方案基本是之前架构经验第一次在保险行业的使用,希望各位能积极探讨并给些意见!

整体方案:

根据个人经验,架构决定项目的成败以及高度,所以在编码之前一定要设计好项目的整体规划和架构。好的架构或者考虑比较全面到位的架构会极大的帮助团队,对项目起到灵魂的作用;糟糕的设计往往会把整个项目组带入泥潭或者恶性循环,对项目直接致命打击!

回归正题:

  • 整个架构分为Online(Web Application)和Offline(WPF Application)两部分。
  • Online(Web Application)需要支持不同的设备及浏览器,所以采用Bootstrap和ASP.NET MVC with Razor作为View,KnockoutJs作为MVVM框架。UI Designer设计好UI,然后由前端工程师绑定相应的UI Model到UI,后端工程师则负责相应的OOAD以及业务处理。
  • Offline(WPF  Application)需要在没有网络的情况下能正常工作,所以采用WPF  XALM作为View,MVVM Light作为MVVM框架。UI和后端的处理以及任务分配和Online(Web Application)基本一致。
  • Services :设置了Switch功能,可以配置是否使用WCF或者Web API或者直接调用Dll。
  • Domain Model:始终是应用程序的核心,必须投入大量精力,按照面向对象的分析和设计 (OOAD) 进行设计同时按照OOP进行开发。
  • Infrastructure:主要包括数据访问组件、通用权限框架、异常和日志处理组件、IOC/AOP功能、缓存机制,邮件,配置等基础或常用功能。
  • 行业知识:由于项目牵涉到具体的行业(保险业),所以在业务流程中创建了Insurance Engine,专门处理保险相关的基础功能。
  • 权限系统:由于整个项目比较庞大,再加上其他系统也需要用到同样的权限判断,所以创建了一个新的权限数据库,用来存储及处理权限相关的所有数据及规则,所有用户则来源于三个数据源(SQL Server, DB2和Active Directory)。
  • Unit Test:每一层都有单独的单元测试,方便项目功能自测,维护,重构,升级以及管理。28-7-2014 12-31-12 AM

组件之间的详细关系如下:

28-7-2014 12-27-11 AM

各层之间的执行顺序如下:

28-7-2014 12-34-29 AM

权限系统:

  • 用户来源于三个数据源(SQL Server, DB2和Active Directory)。
  • 现实世界和系统通过角色进行关联,现实世界的用户及组的变化尽量不要影响到系统。
  • 一个用户可以有多个角色,一个角色也分配给多个用户。
  • 权限分为功能权限和数据权限。
  • 权限系统要提供给几套系统使用,全部的接口通过Service的形式提供出来。

security

由于时间有限,设计可能存在诸多不足之处,如果大家有不同的意见或者建议,不妨在评论中指出,以便互相学习且共同提高!


作者:圣殿骑士
出处:http://www.cnblogs.com/KnightsWarrior/
关于作者:专注于微软平台项目架构、管理和企业解决方案。自认在面向对象及面向服务领域有一定的造诣,熟悉设计模式、TDD、极限编程、领域驱动、架构设计、敏捷开发和项目管理。现主要从事WinForm、ASP.NET、WPF、WCF、WF、Silverlight 、Biztalk、Windows Azure等云计算方面的项目开发、架构、管理和企业培训工作。如有问题或建议,请多多赐教!
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。如有问题,可以邮件:KnightsWarrior(at)msn(dot)com  微博:圣殿骑士微博  联系我,非常感谢。

40
0
(请您对文章做出评价)
? 上一篇:关于新加坡IT薪酬
Add your comment

  1. #51楼[楼主] 圣殿骑士   2014-07-28 21:36
    @dotnet技术网
    引用我也有类似的想法,但真正开发起来,就非常麻烦,梦想很美好,现实很骨干。

    是的,很多时候实施起来比架构设计还难,不过类似项目经历多了就更容易一些了!
  2. #52楼[楼主] 圣殿骑士   2014-07-28 21:38
    @Da ge
    引用必须推荐,最好能有个demo让小伙伴们学习下

    DEMO还处在实施阶段!
  3. #53楼[楼主] 圣殿骑士   2014-07-28 21:40
    @春色园
    引用架构应该适应业务!!

    是的,这个架构就是适应业务和需求而画的,具体模块之间的划分还有几个图——用例图,类图,部署图等,由于与项目有关,没有公布出来。
  4. #54楼 jlzhou   2014-07-29 07:21
    期待代码示例 感谢
  5. #55楼 stoneniqiu   2014-07-29 08:14
    这样的项目 好想加入~~
  6. #56楼   2014-07-29 13:43
    请问一下你们单元测试用的什么框架
  7. #57楼 owlbcc   2014-07-29 14:32
    wpf的和mvc的两个viewmodel能不能合到一起?两个系统之间是不是差异还挺大的?
  8. #58楼 muki   2014-07-29 17:08
    架构太过于复杂了.
  9. #59楼 flyfish1986   2014-07-30 13:34
    来了!
  10. #60楼 HelloNet   2014-08-04 13:52
    看上去很牛逼的样子
  11. #61楼 Pansen   2014-08-05 08:58
    mark
  12. #62楼 高僧   2014-08-11 15:01
    楼主,上面这几图是用什么工具画的?

事务 锁 高并发下的解决方法

最近要做一个高并发的游戏后台网站,要在已有的后台对其系统进行优化,让我对高并发系统又有了一次比较深刻的认识。

 

对于高并发系统解决方法 

1 事务

事务级别的高低,决定了对于并发处理的效率。事务级别越高,处理并发的能力就越低,不过数据一致性也会越高。

事务有5个级别:

 

(一)未提交读

未提交读是最低的事务隔离级别,允许读取其他事务已经修改但未提交的数据行。SQL SERVER 当此事务等级进行尝试读取数据时,不会放置共享锁,直接读取数据,所以忽略已存在的互斥锁。换句话说,即使该资源已经受到了独占锁的保护,当使用未提交读隔离级别时,此数据还是可以被读取,加快查询速度,但是会读取到别人未修改的数据,所以此种读取被称为脏读。此种隔离级别适合不在乎数据变更的查询场景。此隔离级别与SELECT 语句搭配 NOLOCK 所起到的效果相同,一样的SQL语句在同一个事务中前后读取的数据有可能会不一样。

未提交读示例:

--1.--1.创建测试表

create table tbUnRead

(ID INT,

name nvarchar(20)

)

--2新增记录

insert tbUnRead 

select 1,'Tom'

union

select 2,'Jack'

--3开启事务,并进行更新

 

begin tran

update tbUnRead

set name='Jack_upd'

where ID=2

---4查询事务数量(由于没有回滚或提交事务)

SELECT @@TRANCOUNT

事务查询结果如下:

 

--5打开另一条连接,设置事务隔离级别为(未提交读)

set Transaction isolation level read uncommitted

--6查询数据,查询到的数据是修改之后的数据。

select * from tbUnRead where ID=2

如下图:

 

 

(二)已提交读

已提交读是SQL SERVER 默认的事务隔离级别。当事务正在读取数据时,SQL SERVER 会放置共享锁以防止其他事务修改数据,当数据读取完成之后,会自动释放共享锁,其他事务可以进行数据修改。因为共享锁会同时封锁封锁语句执行,所以在事务完成数据修改之前,是无法读取该事务正在修改的数据行。因此此隔离级别可以防止脏读。事务2修改数据,事务1要读取同一条记录,在事务2 提交之前,事务1无法读取,解决事务1可能前后读取数据不一致的问题。

 

在SQL SERVER 2005以上版本中,如果设置READ_COMMITTED_SNAPSHOT为ON,则已提交读的事务全使用数据行版本控制的隔离下读取数据。读取操作不会获取正被读取的数据上的共享锁(S 锁),因此不会阻塞正在修改数据的事务。同时,由于减少了所获取的锁的数量,因此最大程度地降低了锁定资源的开销。使用行版本控制的已提交读隔离和快照隔离旨在提供副本数据的语句级或事务级读取一致性。

示例一:设置READ_COMMITTED_SNAPSHOT为OFF

--1.创建测试表

create table tbUnRead

(ID INT,

name nvarchar(20)

)

--2新增记录

insert tbUnRead 

select 1,'Tom'

union

select 2,'Jack'

--3开启事务,并进行更新

 

begin tran

update tbUnRead

set name='Jack_upd'

where ID=2

---4查询事务数量(由于没有回滚或提交事务)

SELECT @@TRANCOUNT

--5打开另一条连接,设置事务隔离级别为(已提交读)

set Transaction isolation level read committed

--6查询数据,由于当前事务没有提交,所以无法查询数据

select * from tbUnRead where ID=2

6查询数据的结果 如下图:

 

 

 

示例二:设置READ_COMMITTED_SNAPSHOT为ON

use master

go

---创建测试数据库

create database read_committed_SNAPSHOT_Test

go

---激活数据行版本控制

alter database read_committed_SNAPSHOT_Test  set read_committed_SNAPSHOT on

go

 

use read_committed_SNAPSHOT_Test

go

 

--1.创建测试表

create table tbReadLevel

(ID INT,

name nvarchar(20)

)

 

--2新增记录

insert tbReadLevel

select 1,'测试'

go

select ID,name as "修改前数据"  from tbReadLevel

如下图:

 

go

--3开启事务,并进行更新

 

begin tran

update tbReadLevel

set name='Jack_upd'

where ID=1

---4查询事务数量(由于没有回滚或提交事务)

SELECT @@TRANCOUNT

 

--5打开另一条连接,设置事务隔离级别为(已提交读)

--查询数据,查询到的数据是上一次提交的数据

select * from tbReadLevel where ID=1

 5的查询结果如下图:

 

(三)可重复读

可重复读事务隔离级别在事务过程中,所有的共享锁均保留到事务结束,而不是读取结束就释放,这与已提交读的行为截然不同,虽然在事务过程中,重复查询相同记录时不受其他事务的影响,但可能由于锁定数据过久,而导致其他人无法处理数据,影响并发率,更严重的可能提高发生死锁的机率。

  总之,如果使用可重复读隔离级别读取数据,数据读出之后,其他事务只能对此范围中的数据进行读取或新增,但不可以进行修改,直到读取事务完成。因此,使用此隔离级别需要谨慎小心,根据实际情况进行设置。事务1读取一条记录,在事务1提交前,事务2无法对这条记录进行改。

 

示例:

 

--1.创建测试表

create table tbUnRead

(ID INT,

name nvarchar(20)

)

--2新增记录

insert tbUnRead 

select 1,'Tom'

union

select 2,'Jack'

 

--3设置事务隔离级别为(可重复读)

set Transaction isolation level REPEATABLE READ

--4开启事务,并进行更新

begin tran

 

--5查询数据

select * from tbUnRead where ID=2

---6查询事务数量(没有回滚或提交事务)

SELECT @@TRANCOUNT

5与6的执行结果如下图

 

---7开启另一条连接,查询数据与修改数据 

---事务虽然没有完成,但可以查询到之前的数据

select * from tbUnRead where ID=2

Go

---8,修改数据,由于事务没有完成,所以无法进行修改

update tbUnRead

set name='Jack_upd'

where ID=2

go

--7、8的执行结果如下,可以查询数据,但无法更新数据,如下图。

 

 

 

(四)快照

快照隔离级别是SQL SERVER 2005之后版本新增的隔离级别,开启之后,允许事务过程中读取操作不受异动影响,事务中任一语句所读取的数据,均予事务激活时,就已经完成提交,符合事务一致性的数据行版本。所以只能查核事务激活之前已经完成提交的数据,也就是说可以查询已经完成提交的数据行快照集,但看不见已激活的事务正在进行修改的数据行。当使用快照隔离级别读取数据时不会要求对数据进行锁定,如果所读取的记录正在被某事务进行修改,它也会读取此记录之前已经提交的数据。故当某记录被事务进行修改时,SQL SERVER的TEMPDB数据库会存储最近提交的数据行,以供快照隔离级别的事务读取数据时使用。将Allow_SNAPSHOT_isolation设为ON,事务就会设置快照隔离级别。

 

use master

go

---创建测试数据库(快照)

create database SNAPSHOT_Test

go

---激活数据行版本控制

alter database SNAPSHOT_Test  set Allow_SNAPSHOT_isolation on

go

 

use SNAPSHOT_Test

go

 

--1.创建测试表

create table tbReadLevel

(ID INT,

name nvarchar(20)

)

 

--2新增记录

insert tbReadLevel

select 1,'测试'

union

select 2,'快照测试'

go

select ID,name as "修改前数据"

from tbReadLevel

go

--3开启事务,并进行更新

begin tran

update tbReadLevel

set name='Jack_upd_快照'

where ID=1

---4查询事务数量(没有回滚或提交事务)

SELECT @@TRANCOUNT

--2、4的执行结果,如下图。

 

--5打开另一条连接,设置事务隔离级别为(快照)

set Transaction isolation level SNAPSHOT

--6查询数据,查询的数据是上一次提交的数据

select * from tbReadLevel where ID=1

 

 

(五)可序列化

可序列化是事务隔离级别中最高的级别,为最严谨的隔离级别,因为它会锁定整个范围的索引键,使事务与其他事务完全隔离。在现行事务完成之前,其他事务不能插入新的数据行,其索引键值存在于现行事务所读取的索引键范围之中。此隔离级别与Select 搭配holdlock效果一样。

示例:

--1.创建测试表

create table tbUnRead

(ID INT,

name nvarchar(20)

)

--2新增记录

insert tbUnRead 

select 1,'Tom'

union

select 2,'Jack'

--3设置事务隔离级别为(可序列化)

 

set Transaction isolation level SERIALIZABLE

--5开启事务,并进行更新

begin tran

select * from tbUnRead where ID=2

---6查询事务数量(没有回滚或提交事务)

SELECT @@TRANCOUNT

5、6执行结果如下图。

 

---7,开启另一条连接,查询数据,可以查询到之前的数据

select * from tbUnRead where ID=2

 

---8,修改数据,无法修改数据

update tbUnRead

set name='Jack_upd'

where ID=2

 

--新增数据,无法插入数据

insert tbUnRead 

select 3,'May'

 

2 锁

锁有乐观锁和悲观锁

2.1乐观锁实现方法有两种

2.1.1加入时间戳

2.1.2 在UPDATE数据前对数据进行比对

Set @money=Select money from account where accountId=1

Update account set money =2000 where accountId=1 and money=@money

 

这就实现了一个最简单的乐观锁,在update之前对拿到的数据进行判断或者加入时间搓机制

2.2 悲观锁

在事务一开始就对你后面要修改的记录锁定

Select * from account with (UPDLOCK)  where accountId=1

一但锁住,accountId=1 这一个记录 在此事务结束前,别人都无法对其进行修改或读取,要等待此事务结束。

使用悲观锁,千万不要用以下语句

Select top 1 * from account with (UPDLOCK)  

这样会锁住account整个表,其他事务都无法对此表进行读取或者修改

在并发量不大的时候可以使用悲观锁,一但我要修改某条记录,我就锁住它,直到我整个事务完成。

并发量比较大的还是要使用乐观锁,但是要有失败处理机制。

 

posted @ 2015-06-11 18:17  hudasm  阅读(1773)  评论(0编辑  收藏  举报