问题:
1、业务逻辑与数据库已分离的情况下,怎样保证每个方法访问到最适当的数据(不会造成数据库大数据量查询)
2、业务逻辑与数据库已分离的情况下,如何处理事务
三层结构下,数据访问层与业务逻辑分离。从对象关系角度看,业务逻辑层的对象依赖于数据访问层。.net平台提供了ado.net对数据库进行操作,connection对象提供了对database连接与transaction的功能。在分层结构下,数据访问层处理了对数据库的操作,实现了domain每一个对象与database的方法。例如对象Customer,提供CustomerDAO.Add(),CustomerDAO.Update()等等的方法,每一个方法都会引用独立的connection对象。业务层直接调用CustomerDAO的方法。connection对象对业务层是close状态,业务层不能访问到并且控制ado.net提供的transaction。在不破坏分层体系结构前提下一般有三种方式来实现。
System.Transaction:
.net提供的一个使用很简单的解决方法。System.Transaction允许对local和distributed数据库进行操作。使用System.Tansaction不用考虑是一个或者多个connection,一个或多个数据库。例如可以使用TransactionScope,举个例子,下面的code很直观,
using (TransactionScope scope = new TransactionScope())
{
SqlConnection connection1 = new SqlConnection(connectString1)
SqlConnection connection2 = new SqlConnection(connectString2)
scope.Complete();
}
有两个connection,System.Transaction会整合成一个tranaction来处理,那么我们只需要在业务层需要transaction的地方使用TransactionScope就可以了,很方便。虽然方便,但还是有不利的地方。因为System.Transaction会自动监测connection,如果只有一个,就直接使用ado.net的transaction,perfomance不会影响。但如果是上面的code,有两个以上的connection,System.Transaction会自动升级为distributed级别,这样performance会打了折扣。而且对于除sqlserver一些其他的数据库例如oracle,一直会是distributed级别。
这种方式只适合对于performance要求不是很高的项目。
Connection/Transaction参数传递给DAO:
这种方式的思路是DAO的对象每一个对象需要提供一个参数来接受是否需要transaction的信息。例如可以自定义一个MyTrans类,MyTrans类引用一个connection对象。
public class MyTrans
{
public IConnection connection;
public void beginTrans();
public void commitTrans();
}
这样一个包装过的类,就可以使业务层的对象对connection间接的进行操作,例如业务层类customer.Update()就可以这样实现。
using(MyTrans tran=new MyTrans)
{
tran.beginTrans();
CustomerDAO dao=new CustomerDAO(tran);
dao.Add();
tran.commitTrans();
}
这样实现,对开发的复杂度会增大,DAO需要每个类都要实现一个接受Trans的参数。这种方式适和那种有充足时间而且想亲自操作数据库的项目。
AOP实现Transaction:
这种方式可以参考Spring提供的AOP机制与Spring的Transation,Aop的内部实现是采用了反射原理,利用Typebuilder对Class的Methord进行重新编排,使在逻辑层的对象方法内部自动的加入Connection的transaction的操作。Spring提供了一个声明的方式,很方便快捷,而且由于使用的Ado.net进行操作,所以performance没有受到任何影响。如以下Code,只要简单的声明就可以了。
public class TestObjectManager : ITestObjectManager
{
// Fields/Properties ommited
[Transaction()]
public void SaveTwoTestObjects(TestObject to1, TestObject to2)
{
TestObjectDao.Create(to1.Name, to1.Age);
TestObjectDao.Create(to2.Name, to1.Age);
}
[Transaction()]
public void DeleteTwoTestObjects(string name1, string name2)
{
TestObjectDao.Delete(name1);
TestObjectDao.Delete(name2);
}
}
这种方式适合项目较大,需要快速开发,而且项目决策者愿意使用工具的项目。
System.Transaction:
.net提供的一个使用很简单的解决方法。System.Transaction允许对local和distributed数据库进行操作。使用System.Tansaction不用考虑是一个或者多个connection,一个或多个数据库。例如可以使用TransactionScope,举个例子,下面的code很直观,
using (TransactionScope scope = new TransactionScope())
{
SqlConnection connection1 = new SqlConnection(connectString1)
SqlConnection connection2 = new SqlConnection(connectString2)
scope.Complete();
}
有两个connection,System.Transaction会整合成一个tranaction来处理,那么我们只需要在业务层需要transaction的地方使用TransactionScope就可以了,很方便。虽然方便,但还是有不利的地方。因为System.Transaction会自动监测connection,如果只有一个,就直接使用ado.net的transaction,perfomance不会影响。但如果是上面的code,有两个以上的connection,System.Transaction会自动升级为distributed级别,这样performance会打了折扣。而且对于除sqlserver一些其他的数据库例如oracle,一直会是distributed级别。
这种方式只适合对于performance要求不是很高的项目。
Connection/Transaction参数传递给DAO:
这种方式的思路是DAO的对象每一个对象需要提供一个参数来接受是否需要transaction的信息。例如可以自定义一个MyTrans类,MyTrans类引用一个connection对象。
public class MyTrans
{
public IConnection connection;
public void beginTrans();
public void commitTrans();
}
这样一个包装过的类,就可以使业务层的对象对connection间接的进行操作,例如业务层类customer.Update()就可以这样实现。
using(MyTrans tran=new MyTrans)
{
tran.beginTrans();
CustomerDAO dao=new CustomerDAO(tran);
dao.Add();
tran.commitTrans();
}
这样实现,对开发的复杂度会增大,DAO需要每个类都要实现一个接受Trans的参数。这种方式适和那种有充足时间而且想亲自操作数据库的项目。
AOP实现Transaction:
这种方式可以参考Spring提供的AOP机制与Spring的Transation,Aop的内部实现是采用了反射原理,利用Typebuilder对Class的Methord进行重新编排,使在逻辑层的对象方法内部自动的加入Connection的transaction的操作。Spring提供了一个声明的方式,很方便快捷,而且由于使用的Ado.net进行操作,所以performance没有受到任何影响。如以下Code,只要简单的声明就可以了。
public class TestObjectManager : ITestObjectManager
{
// Fields/Properties ommited
[Transaction()]
public void SaveTwoTestObjects(TestObject to1, TestObject to2)
{
TestObjectDao.Create(to1.Name, to1.Age);
TestObjectDao.Create(to2.Name, to1.Age);
}
[Transaction()]
public void DeleteTwoTestObjects(string name1, string name2)
{
TestObjectDao.Delete(name1);
TestObjectDao.Delete(name2);
}
}
这种方式适合项目较大,需要快速开发,而且项目决策者愿意使用工具的项目。
3、事务处理应用Spring.net ,查询和报表应用PLSQL控制。