投递文章投递文章 投稿指南投稿指南 RSS订阅RSS订阅

SmartPublisher设计之旅 — 数据库访问层设计

来源:cnBLOGs 发布时间:2008-01-11 收藏 投稿 字体:【

数据库访问技术概述

      在软件开发中,数据库编程是非常常见的工作。从数据库技术诞生到现在,已经有数十年的历史。从最初的磁盘文件(也称文件数据库)开始,数据库的发展非常迅猛。目前市场上比较常见的关系型数据有SQL Server、Oracle、DB2、Informix、Sybase、MySQL、Access等。各种数据都自己独特的优势和特点。最初,不同的数据库厂商提供了不同的访问接口,开发人员必须熟悉根据不同数据采用不同的访问技术。后来,数据库中间件的出现为开发人员带来新的开发体验,如ODBC、OLEDB、ADO等。

      现在,我们简单看一下主流数据访问技术:
       1)   JDBC(Java Database Connectivity:Java 数据库连接),JDBC是JAVA环境下的数据访问技术,有四种类型:
       ·JDBC-ODBC桥。由SUN公司提供的,是jdk提供的的标准api. 这种类型的驱动实际是把所有jdbc的调用传递给odbc
       ·本地API驱动。把JDBC调用转变为数据库的标准调用再去访问数据库。
       ·网络协议驱动。使用纯 JAVA 客户机,并使用独立于数据库的协议与中间件服务器通信,然后中间件服务器将客户机请求传给数据源。
       ·本地协议驱动。用纯JAVA编写,实现针对特定数据源的网络协议,客户机直接连接至数据源。

      2 )  微软相关数据访问技术
      ·ODBC(Open Database Connectivity):是第一个使用SQL访问各种关系数据库的数据访问技术。使用ODBC,应用程序能够可以操纵不同类型的数据库,而开发人员需要根据不同数据访问不同的ODBC 驱动就可以。
      ·DAO(Data Access Objects):DAO是微软提供给 Visual Basic 开发人员的一种简单的数据访问方法,用于操纵 Access 数据库。
      ·RDO(Remote Data Object):在使用 DAO 访问关系型数据库的时候,JET 引擎需要在DAO和ODBC 之间进行转化,导致了性能的下降。
      ·OLE DB:是为各种关系型数据提供的一种应用和数据源之间的无缝连接的基于COM的数据库访问技术。
      ·ADO:基于 OLE DB 之上,ADO 更简单、更高级,同时消除了 OLE DB 的多种弊端,是微软技术发展的趋势。
      ·ADO.NET:微软在.NET 框架中提出的全新的数据访问模型。
 
ADO.NET访问数据库

      ADO.NET2.0访问数据库可以采用以下方式:
      1) System.Data.Odbc,通过ODBC数据源访问数据库,可以访问各种关系型数据库,但是需要配置ODBC数据源;
      2) System.Data.OleDb,通过不同数据库驱动程序访问,可以访问各种关系型数据库;
      3) System.Data.SqlClient,MS为专门访问SQL Server提供;
      4) System.Data.OracleClient,MS为专门访问Oracle提供。

SmartPublisher数据库访问层设计

      在SmartPublisher软件需求中,要求本软件对不同关系型数据库的支持能力。而ADO.NET针对不同的数据有不同的访问方式。根据面向对象程序设计的思想,我们应该把不同数据库访问抽象成独立的访问类。我们先考虑支持SQL Server和Oracle。实现如下:

public class SqlDBOperator
{
    //操作SQL Server数据库
}
public class OracleDBOperator
{
    //操作Oracle数据库
}
         在软件开发过程中,应用程序对数据库的操作过程不外乎为:先连接数据,然后数据表操作,最后关闭数据库,即其基本操作是相同的。所以,我们可以把对数据库的操作抽象(抽出象的部分即为抽象)出来,即定义一个父类,此处为抽象类,并在该类中提供数据访问的常用方法。如下:

public abstract class DBOperator
{
    //连接数据库
     //操作数据表
     //关闭数据库
}
    然后根据不同的数据库由SqlDBOperator、OracleDBOperator等具体访问类override父类DBOperator中的方法。为了使数据访问支持事务处理,这里还提供事务处理的有关方法。另外,我们需要控制应用程序对数据库的连接数,以防止数据库连接池溢出。

   下面请看具体实现代码。

抽象类
using System;
using System.Data;

namespace PublisherDB
{
    public abstract class DBOperator
    {
        public abstract IDbConnection Connection { get;}
        public abstract void Open(); //打开数据库连接
        public abstract void Close();//关闭数据库连接
        public abstract void BeginTrans();//启动事务
        public abstract void CommitTrans();//提交事务
        public abstract void RollbackTrans();//回滚事务
        public abstract void ExecuteSQL(string sql);//执行写操作SQL语句,如INSERT UPDATE DELETE
        public abstract object ExecuteSQLForObject(string sql);//执行读操作SQL语句,返回单个值
        public abstract DataSet ExecuteSQLForDataSet(string sql););//执行读操作SQL语句,返回DataSet
    }
}


SQL Server访问类
Code
using System;
using System.Data;
using System.Data.SqlClient;

namespace PublisherDB
{
    public class SqlDBOperator : DBOperator
    {
        private SqlTransaction transaction;
        private bool inTransaction = false;

        private SqlConnection conn;
        public override IDbConnection Connection
        {
            get { return this.conn; }
        }

        public SqlDBOperator(string strConnection)
        {
            this.conn = new SqlConnection(strConnection);
            DBConfig.PooledConnectionCount++;
        }
        public override void Open()
        {
            if (conn.State.ToString().ToUpper() != "OPEN")
                this.conn.Open();
        }
        public override void Close()
        {
            if (conn.State.ToString().ToUpper() == "OPEN")
            {
                this.conn.Close();
                DBConfig.PooledConnectionCount--;
            }
        }
        public override void BeginTrans()
        {
            transaction = conn.BeginTransaction();
            inTransaction = true;
        }
        public override void CommitTrans()
        {
            transaction.Commit();
            inTransaction = false;
        }
        public override void RollbackTrans()
        {
            transaction.Rollback();
            inTransaction = false;
        }
        public override void ExecuteSQL(string sql)
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = this.conn;

            if (inTransaction)
                cmd.Transaction = transaction;

            cmd.CommandText = sql;
            cmd.ExecuteNonQuery();
        }
        public override object ExecuteSQLForObject(string sql)
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = this.conn;

            if (inTransaction)
                cmd.Transaction = transaction;

            object obj = cmd.ExecuteScalar();
            if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))
            {
                return null;
            }
            else
            {
                return obj;
            }
        }
        public override DataSet ExecuteSQLForDataSet(string sql)
        {
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = this.conn;

            if (inTransaction)
                cmd.Transaction = transaction;

            DataSet ds = new DataSet();
            SqlDataAdapter ad = new SqlDataAdapter();
            cmd.CommandText = sql;
            ad.SelectCommand = cmd;
            ad.Fill(ds);

            return ds;
        }
    }
}


Oracle访问类
using System;
using System.Data;
using System.Data.OracleClient;

namespace PublisherDB
{
    public class OracleDBOperator : DBOperator
    {
        private OracleTransaction transaction;
        private bool inTransaction = false;

        private OracleConnection conn;
        public override IDbConnection Connection
        {
            get { return this.conn; }
        }

        public OracleDBOperator(string strConnection)
        {
            this.conn = new OracleConnection(strConnection);
            DBConfig.PooledConnectionCount++;
        }
        public override void Open()
        {
            if (conn.State.ToString().ToUpper() != "OPEN")
                this.conn.Open();
        }
        public override void Close()
        {
            if (conn.State.ToString().ToUpper() == "OPEN")
            {
                this.conn.Close();
                DBConfig.PooledConnectionCount--;
            }
        }
        public override void BeginTrans()
        {
            transaction = conn.BeginTransaction();
            inTransaction = true;
        }
        public override void CommitTrans()
        {
            transaction.Commit();
            inTransaction = false;
        }
        public override void RollbackTrans()
        {
            transaction.Rollback();
            inTransaction = false;
        }
        public override void ExecuteSQL(string sql)
        {
            OracleCommand cmd = new OracleCommand();
            cmd.Connection = this.conn;

            if (inTransaction)
                cmd.Transaction = transaction;

            cmd.CommandText = sql;
            cmd.ExecuteNonQuery();
        }
        public override object ExecuteSQLForObject(string sql)
        {
            OracleCommand cmd = new OracleCommand();
            cmd.Connection = this.conn;

            if (inTransaction)
                cmd.Transaction = transaction;

            object obj = cmd.ExecuteScalar();
            if ((Object.Equals(obj, null)) || (Object.Equals(obj, System.DBNull.Value)))
            {
                return null;
            }
            else
            {
                return obj;
            }
        }
        public override DataSet ExecuteSQLForDataSet(string sql)
        {
            OracleCommand cmd = new OracleCommand();
            cmd.Connection = this.conn;

            if (inTransaction)
                cmd.Transaction = transaction;

            DataSet ds = new DataSet();
            OracleDataAdapter ad = new OracleDataAdapter();
            cmd.CommandText = sql;
            ad.SelectCommand = cmd;
            ad.Fill(ds);

            return ds;
        }
    }
}
在上面访问类中,通过DBConfig.PooledConnectionCount记录数据库连接数,DBConfig是一个配置类文件。

namespace PublisherDB
{
   public class DBConfig
   {
      public static int PooledConnectionCount = 0; //连接数
       public static string DBType="SQLSERVER";//数据库类型,形如SQLSERVER\ORACLE\OTHER.
   }
}

         DBOperator的引入,通过类的继承机制,使两种数据库访问彻底分离。如果增加其他数据库如MySQL的访问,只需要增加OleDBOperator访问类,并且继承DBOperator类,不需要对上述代码进行修改(开放-封闭原则)。

最新评论:
评论内容:请自觉遵守互联网相关政策法规。
用户名: 密码: 匿名 注册
热门文章
随机推荐
About iTtang - 联系方法  - 专题列表 - 友情链接  -  高级搜索   -  帮助中心  -