一般来说的废话,ASP.NET总是多用户访问的应用。这对IIS和ASP.NET不成问题,但是在默认情况下, XPO Data Layer 只创建一个数据库连接对象,那么当有2个用户同时访问数据库时,后一个用户则必须等待前一个用户的查询结束才能继续。
理论上我们可以为每一个Page甚至每一次用户访问都创建一个DataLayer,但创建DataLayer是一个相对昂贵的过程,这么做并不现实。如果能有一组数据库连接对象,并且让XPO自动选择第一个空闲的对象进行下一次查询则是个很棒的做法。
幸运的是,ThreadSafeDataLayer 已经可以处理一个被称为 DataStoreFork 的连接池。简单来说,我们可以创建一个 IDataStore object array,初始化一个DataStoreFork,然后用他们构造一个ThreadSafeDataLayer即可。
1 // C#
2 IDataStore GetDataStore() {
3 string connStr = ConfigurationManager.ConnectionStrings["PrimaryConnection"].ConnectionString;
4 SqlConnection conn = new SqlConnection(connStr);
5 IDataStore store = new MSSqlConnectionProvider(conn, AutoCreateOption.SchemaAlreadyExists);
6 return store;
7 }
8
9 IDataLayer GetDataLayer() {
10 ReflectionDictionary dict = new ReflectionDictionary();
11 dict.CollectClassInfos(typeof(Person).Assembly);
12
13 const int maxConnections = 3;
14 IDataStore[] stores = new IDataStore[maxConnections];
15 for(int i = 0; i < maxConnections; i++)
16 stores[i] = GetDataStore();
17
18 return new ThreadSafeDataLayer(dict, new DataStoreFork(stores));
19 }
2 IDataStore GetDataStore() {
3 string connStr = ConfigurationManager.ConnectionStrings["PrimaryConnection"].ConnectionString;
4 SqlConnection conn = new SqlConnection(connStr);
5 IDataStore store = new MSSqlConnectionProvider(conn, AutoCreateOption.SchemaAlreadyExists);
6 return store;
7 }
8
9 IDataLayer GetDataLayer() {
10 ReflectionDictionary dict = new ReflectionDictionary();
11 dict.CollectClassInfos(typeof(Person).Assembly);
12
13 const int maxConnections = 3;
14 IDataStore[] stores = new IDataStore[maxConnections];
15 for(int i = 0; i < maxConnections; i++)
16 stores[i] = GetDataStore();
17
18 return new ThreadSafeDataLayer(dict, new DataStoreFork(stores));
19 }
注意其中的maxConnections不应该超过数据库服务器的CPU核心数。
另外,在一般的ASP.NET项目里,这么做并不会带来可观测到的性能提升。如果遭遇性能问题,不应该马上采用这种做法,而应先排除其他地方的性能瓶颈。
DataStoreFork更适用于其他一些如Web Service等多用户并发访问的场合。
XPO to Database Connectivity: Mastering Fork Etiquette