Delphi深度探索之使用Bold开发数据库应用(1)

Delphi深度探索之使用Bold开发数据库应用(1),第1张

介绍

下面我要介绍的Bold for Delphi就是是一套优秀的基于UML模型驱动的面向对象数据库开发框架 包括了几十个组件组件 以及 个以上的类 可以用来轻松地实现信息模型设计及基于信息模型的的应用程序

基础概念介绍

为了使大家对Bold for Delphi整个框架的使用有一个大概的了解 下面将演示如何用UML设计一个简单的模型并用Bold来完成 并包括如何用Bold快速实现一个简单的 *** 作界面

自打我和我老婆认识以后 就染上了她的臭毛病 比较喜欢乱花钱 没有节制 结果搞的自己常常是挣的不如花的多 老要借外债 后来痛定思痛 决定要对每月收支情况做预算 严格控制费用支出 为此写了还写了好多的财务小程序 下面要讲的这个例子程序就是一个常见的家庭小账本程序 它可以用来统计家庭中的收支情况 软件的功能要求如下

可以定义家庭中的各个人员的信息 可以输入收支情况 并同消费的人员关联起来 给出一定时期内消费的情况统计 作为未来家庭预算的依据

建立信息模型

在产品的需求分析阶段 我们首先要建立数据库程序的信息模型 一般来说信息模型主要是指基于ER图的实体关系模型 这是因为我们使用的数据库大部分都是关系型数据库 虽然有些数据库 比如Oracle有面向对象的特性 但不是很完善 一般很少使用 而关系型数据库有一个很大的问题就是无法直观的体现面向对象的思想 关系型的ER模型能够清晰地描述业务域的静态的数据视图 但你无法从模型获取实体的 *** 作及其相互之间的交互 同时 也很难在关系型数据库中简单地实现继承 重载 多态等等面向对象的技术 因此现代数据库开发方法所提倡的面向对象的编程思想无法简单 清晰 平滑地映射为关系型数据库中的表结构

统一建模语言(UML)是一种以可视化的方式建立软件系统框架 并进行文档化的语言 UML语言是对当今软件工程领域成熟设计实践的一个总结 并且已经被实践证明是可以成功地描述大型的复杂系统的 目前国内很多的大型公司已经开始在软件开发过程中使用UML作为一种标准的信息模型设计语言了 Bold for Delphi就是基于UML的 它内置了一套自己的UML建模工具 当然我们也可以使用Rose或者ModelMaker来进行UML设计

面向对象的UML类图则可以说是对ER模型的一个扩展 它对实体之间的关系以及相互之间的作用也进行了描述 ER模型只是对要进行保存的数据进行的模型化 而类图则包括了全部的类实体的属性以及它们的 *** 作和相互作用 它可以使我们对业务域问题有一个更精确的视图 通过使用各种类图技术可以更容易地 也更快速地建立正确的软件系统

基于Bold for Delphi的数据库开发革命性的一点就是允许我们直接把基于UML的类图映射为关系型数据库的存储 而无须手工的通过代码进行转换 要注意一点的是 Bold同其它建模工具如Together ModelMaker不同 它生成框架代码时只使用了UML中的类图 而Together等可以利用UML图中的类图 协作图等其它UML元素来生成代码框架 但是Together不负责生成对象模型对应的关系数据库模型

类模型

下面的这个类图就是我们的账本程序的一个简单类图

图中显示了两个类 人员信息类 Person 以及账目信息类AcctItem 人员类和账目类之间的连线描述了两个类之间的关系 关系包括一个标题PayAssoc揭示了两者之间的关系是支付的关系 每个属性 PayPerson 和 Pay 以及关系多重度因子 和 n 表明每个人可以完成多个账目的收支 而每个账目至少要有一个关联的人员 同时类图还描述了下面一些业务规则

一个人的信息要有名称 账目信息中包含收支金额大小 以及发生日期

上面的类图如果使用关系型数据库来实现的话 需要建立主从表 并将人员和账目之间的关联约束通过应用程序代码强制一些运行逻辑来完成 这时通常要通过补充详细的文档来描述需要强制的业务逻辑 如果没有详细的设计文档 实现代码时就很容易遗漏某些重要的商业规则 同时这些文档在整个的数据库开发的生命周期里面都需要人来手工地维护 难免会出现文档和模型不匹配的错误 而且文档的工作量比较大 而程序员数量又相对不足的话 程序员会觉得既要写代码又要写文档 无形中增加了很多工作量 难免会有抵触情绪 这些都会影响工作的效率

对于这样的问题 Bold则通过精确描述信息模型 无须详细规则描述文档可以将模型自动的转变为实现代码 商业规则在整个数据库开发生命周期内由Bold的类来维护 减少了文档的工作量和出错的可能

建立示例程序

首先 我们要安装Bold for Delphi Bold的一个月评估版可以从 boldsoft 获取 同时D 的架构版内置了Bold 这里我就不详细介绍申请和安装的过程了 安装好后Bold会在IDE的组件面板中添加很多组件 接下来我们就开始建立使用Bold的Delphi程序了

在Delphi中选File|New Application创建一个新的应用程序

保存窗体文件为MainForm pas保存工程文件为CMoney dpr

添加一个数据模块 设定数据模块的名字为DmMoney

将数据模块保存为CDataModule pas

为了使用Bold来建立系统的信息模型 要进行下列 *** 作

从Bold Handles 组件页上选择BoldModal(命名为bmMoney) BoldSystemTypeInfoHandle(命名为bsthMoney)和BoldSystemHandle(命名为bshMoney)到数据模块中

设定bsthMoney的BoldModal属性为bmMoney

设定bshMoney的BoldSystemTypeInfoHandle 属性为bsthMoney

其中BoldModel组件将被用来保存模型 即类 类的关系 约束以及类型等 这些信息将在设计时作为字符串保存到Delphi的窗体和数据模块文件中 在运行时Bold将执行一些模型的中间转换过程 将模型转化为BoldSystemTypeInfoHandle控件所使用的格式 并选择实现可持续性的机制

在设计时储存在BoldModel组件中的信息模型可以被看做元数据 就象数据库的库表和字段结构一样的信息 而BoldSystemTypeInfoHandle组件则保存BoldSystemHandle所需要的运行时信息 这些信息是对UML模型的一种运行时的表达 这个组件是其他Bold组件的信息源 BoldSystemHandle组件则被用来表达整个系统的业务域元素 可以理解为对象空间 通过对象空间我们可以在运行时获得设计时元数据表达的对象的运行实例 目前用到的三个控件已经可以很好的应用在不需要保存数据的环境中了 但账目记录这类数据库程序必须要保存用户输入的信息 因此还需要添加支持数据可持久性的控件 这里为了快速演示的需要 我们使用XML文件作为存储介质 接下来要添加XML可持续控件到数据模块中

从Bold Persistence组件页上选择BoldPersistenceHandleFileXML控件(命名为bphxMoeny)添加到数据模块中

设定组件的BoldModel属性为bmMoney控件

设定bshMoney组件的PersistenceHandle属性为bphxMoeny组件

现在组件关系示意图如下

BoldPersistenceHandleFileXML组件将使我们的程序可以使用XML文件来保存和读取对象 这是一个使用很方便的控件 特别是在快速原型设计期间 因为在原型设计期间 模型经常会被改动 而重新生成数据库表是很费时间的 而XML文件可以使我们非常快的变更我们的模型设计 当模型基本稳定后 可以去掉这个控件 转而切换为其他使用关系型数据库进行存储的可持续性控件 这样的开发方式可以使我们不需要改动整个程序就能很容易地改变数据持续层的存储策略 也就是前面所说的 数据库平台无关设计

除了前面的一些基本的属性设置外 我们还要设定下列控件属性

组件 属性 值 说明 bsthMoney UseGeneratedCode false 是否使用bold生成类代码 这里暂时先不使用 稍后我们会进一步介绍 bphxMoeny FileName Data xml 指定保存数据的xml文件名 bshMoney AutoActivate true 告诉Bold控件在程序运行后马上打开xml文件用于数据存储

建立模型 下面的步骤是建立我们的模型 Bold for Delphi内置了一个树形的UML建模工具(应该说Bold美中不足的一点就是没有提供象Visio和Rose那样基于拖放的模型设计界面) 我们可以双击BoldModel(bmMoney)组件调出模型设计工具 bold UML模型编辑器(见下图)包含了应用程序模型信息 数据类型信息和关系数据库映射信息

模型编辑器支持下列实体类型

Model: 模型 全部业务域实体集合

Package: 包 整个模型的一个子集所包含的实体 可以将大模型分解为小模型来减少系统复杂度

Class:类 类似于Delphi的类的概念(Delphi的类可以从UML的类来生成) 但包含Object Pascal无法直接描述的类的信息和相互关系 Bold框架通过关联类和特殊的列表类封装了一些额外的功能使得我们可以很容易的处理复杂的类关系

Attribute: 属性 类似于Delphi中的property概念 然而在Bold中 这些属性可以在模型中直接保存而无需我们编写属性的Get Set方法

Operation: *** 作 等价于Delphi中的类的过程和函数

Association: 关联 代表了类之间的关系 关联可以使用类来表达 关联也可以有 *** 作和属性 在Bold中建立关联的复杂工作同样可以由框架来实现 我们无须编写代码来完成

Role: 角色 代表关联同类的连接

Data Type: 表示模型所支持的不同数据类型 它可以被扩展以支持用户自定义的数据类型

下图是不同实体类型在模型编辑器中是如何标识的

所有的实体类型都可以通过编辑器的右键菜单来创建和修改属性 同时我们选中实体节点后 实体和全局的选项会显示在右侧的编辑器中 其中重要的有

Name: 模型的名称

lishixinzhi/Article/program/Delphi/201311/24785

这不是很明显么?

OpenDatabase的定义中看到是两个参数,而且没有默认参数,你直接使用OpenDataBase(strConnect)当然是无法重载的,这样自然也无法调用。

至于VC60为什么能用,你再去查查VC60下的OpenDatabase()这个函数的定义。

VC2005开始,对VC60的很多函数都做了修改,形参不一样,甚至函数拼写不一样都是很正常的事情。

一、使用嵌入式关系型SQLite数据库存储数据

在Android平台上,集成了一个嵌入式关系型数据库——SQLite,SQLite3支持NULL、INTEGER、REAL(浮点数字)、 TEXT(字符串文本)和BLOB(二进制对象)数据类型,虽然它支持的类型只有五种,但实际上sqlite3也接受varchar(n)、 char(n)、decimal(p,s) 等数据类型,只不过在运算或保存时会转成对应的五种数据类型。 SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么。例如:可以在Integer类型的字段中存放字符串,或者在布尔型字段中存放浮点数,或者在字符型字段中存放日期型值。 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数, 当向这种字段保存除整数以外的数据时,将会产生错误。 另外,在编写CREATE TABLE 语句时,你可以省略跟在字段名称后面的数据类型信息,如下面语句你可以省略name字段的类型信息:

CREATE TABLE person (personid integer primary key autoincrement, name varchar(20))

SQLite可以解析大部分标准SQL语句,如:

复制代码 代码如下:

查询语句:select from 表名 where 条件子句 group by 分组字句 having order by 排序子句

如: select from person

select from person order by id desc

select name from person group by name having count()>1

分页SQL与mysql类似,下面SQL语句获取5条记录,跳过前面3条记录

select from Account limit 5 offset 3 或者 select from Account limit 3,5

插入语句:insert into 表名(字段列表) values(值列表)。如: insert into person(name, age) values(‘传智',3)

更新语句:update 表名 set 字段名=值 where 条件子句。如:update person set name=‘传智‘ where id=10

删除语句:delete from 表名 where 条件子句。如:delete from person where id=10

二、使用SQLiteOpenHelper对数据库进行版本管理

我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安装在很多用户的手机上,如果应用使用到了SQLite数据库,我们必须在用户初次使用软件时创建出应用使用到的数据库表结构及添加一些初始化记录,另外在软件升级的时候,也需要对数据表结构进行更新。那么,我们如何才能实现在用户初次使用或升级软件时自动在用户的手机上创建出应用需要的数据库表呢?总不能让我们在每个需要安装此软件的手机上通过手工方式创建数据库表吧?因为这种需求是每个数据库应用都要面临的,所以在Android系统,为我们提供了一个名为SQLiteOpenHelper的抽象类,必须继承它才能使用,它是通过对数据库版本进行管理来实现前面提出的需求。

为了实现对数据库版本进行管理,SQLiteOpenHelper类提供了两个重要的方法,分别是onCreate(SQLiteDatabase db)和onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion),前者用于初次使用软件时生成数据库表,后者用于升级软件时更新数据库表结构。当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法获取用于 *** 作数据库的SQLiteDatabase实例的时候,如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法,onCreate()方法在初次生成数据库时才会被调用,在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据。onUpgrade()方法在数据库的版本发生变化时会被调用,一般在软件升级时才需改变版本号,而数据库的版本是由程序员控制的,假设数据库现在的版本是1,由于业务的变更,修改了数据库表结构,这时候就需要升级软件,升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2(有同学问设置为3行不行?当然可以,如果你愿意,设置为100也行),并且在 onUpgrade()方法里面实现表结构的更新。当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断,然后作出相应的表结构及数据更新。

getWritableDatabase()和 getReadableDatabase()方法都可以获取一个用于 *** 作数据库的SQLiteDatabase实例。但 getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用getWritableDatabase()打开数据库就会出错。getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。

注意:getWritableDatabase(),getReadableDatabase的区别是当数据库写满时,调用前者会报错,调用后者不会,所以如果不是更新数据库的话,最好调用后者来获得数据库连接。

代码:

复制代码 代码如下:

public class DatabaseHelper extends SQLiteOpenHelper {

//类没有实例化,是不能用作父类构造器的参数,必须声明为静态

private static final String name = "ljqdb"; //数据库名称

private static final int version = 1; //数据库版本

public DatabaseHelper(Context context) {

//第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类

super(context, name, null, version);

}

@Override

public void onCreate(SQLiteDatabase db) {

dbexecSQL("CREATE TABLE IF NOT EXISTS person (

personid integer primary key autoincrement, name varchar(20), age INTEGER)");

}

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

dbexecSQL(" ALTER TABLE person ADD phone VARCHAR(12) NULL "); //往表中增加一列

// DROP TABLE IF EXISTS person 删除表

}

}

在实际项目开发中,当数据库表结构发生更新时,应该避免用户存放于数据库中的数据丢失。

三、使用SQLiteDatabase *** 作SQLite数据库

Android提供了一个名为SQLiteDatabase的类,该类封装了一些 *** 作数据库的API,使用该类可以完成对数据进行添加(Create)、查询(Retrieve)、更新(Update)和删除(Delete) *** 作(这些 *** 作简称为CRUD)。对SQLiteDatabase的学习,我们应该重点掌握execSQL()和rawQuery()方法。execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句; rawQuery()方法用于执行select语句。

execSQL()方法的使用例子:

复制代码 代码如下:

SQLiteDatabase db = ;

dbexecSQL("insert into person(name, age) values('林计钦', 24)");

dbclose();

执行上面SQL语句会往person表中添加进一条记录,在实际应用中, 语句中的“林计钦”这些参数值会由用户输入界面提供,如果把用户输入的内容原样组拼到上面的insert语句, 当用户输入的内容含有单引号时,组拼出来的SQL语句就会存在语法错误。要解决这个问题需要对单引号进行转义,也就是把单引号转换成两个单引号。有些时候用户往往还会输入像“ & ”这些特殊SQL符号,为保证组拼好的SQL语句语法正确,必须对SQL语句中的这些特殊SQL符号都进行转义,显然,对每条SQL语句都做这样的处理工作是比较烦琐的。 SQLiteDatabase类提供了一个重载后的execSQL(String sql, Object[] bindArgs)方法,使用这个方法可以解决前面提到的问题,因为这个方法支持使用占位符参数()。使用例子如下:

复制代码 代码如下:

SQLiteDatabase db = ;

dbexecSQL("insert into person(name, age) values(,)", new Object[]{"传智播客", 4});

dbclose();

execSQL(String sql, Object[] bindArgs)方法的第一个参数为SQL语句,第二个参数为SQL语句中占位符参数的值,参数值在数组中的顺序要和占位符的位置对应。

SQLiteDatabase的rawQuery()用于执行select语句,使用例子如下:

复制代码 代码如下:

SQLiteDatabase db = ;

Cursor cursor = dbrawQuery("select from person", null);

while (cursormoveToNext()) {

int personid = cursorgetInt(0); //获取第一列的值,第一列的索引从0开始

String name = cursorgetString(1);//获取第二列的值

int age = cursorgetInt(2);//获取第三列的值

}

cursorclose();

dbclose();

rawQuery()方法的第一个参数为select语句;第二个参数为select语句中占位符参数的值,如果select语句没有使用占位符,该参数可以设置为null。带占位符参数的select语句使用例子如下:

复制代码 代码如下:

Cursor cursor = dbrawQuery("select from person where name like and age=", new String[]{"%林计钦%", "4"});

Cursor是结果集游标,用于对结果集进行随机访问,如果大家熟悉jdbc, 其实Cursor与JDBC中的ResultSet作用很相似。使用moveToNext()方法可以将游标从当前行移动到下一行,如果已经移过了结果集的最后一行,返回结果为false,否则为true。另外Cursor 还有常用的moveToPrevious()方法(用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true )、moveToFirst()方法(用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true )和moveToLast()方法(用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true ) 。

除了前面给大家介绍的execSQL()和rawQuery()方法, SQLiteDatabase还专门提供了对应于添加、删除、更新、查询的 *** 作方法: insert()、delete()、update()和query() 。这些方法实际上是给那些不太了解SQL语法的菜鸟使用的,对于熟悉SQL语法的程序员而言,直接使用execSQL()和rawQuery()方法执行SQL语句就能完成数据的添加、删除、更新、查询 *** 作。

本文将详细介绍如何使用Connection对象连接数据库。对于不同的NET数据提供者,ADONET采用不同的Connection对象连接数据库。这些Connection对象为我们屏蔽了具体的实现细节,并提供了一种统一的实现方法。

Connection类有四种:SqlConnection,OleDbConnection,OdbcConnection和OracleConnection。

SqlConnection类的对象连接SQL Server数据库;OracleConnection 类的对象连接Oracle数据库;

OleDbConnection类的对象连接支持OLE DB的数据库,如Access;而OdbcConnection类的对象连接任何支持ODBC的数据库。与数据库的所有通讯最终都是通过Connection对象来完成的。

SqlConnection类

Connection 用于与数据库“对话”,并由特定提供程序的类(如 SqlConnection)表示。尽管SqlConnection类是针对Sql Server的,但是这个类的许多属性、方法与事件和OleDbConnection及OdbcConnection等类相似。本章将重点讲解SqlConnection特定的属性与方法,其他的Connection类你可以参考相应的帮助文档。

注意:使用不同的Connection对象需要导入不同的命名空间。OleDbConnection的命名空间为SystemDataOleDb。SqlConnection的命名空间为SystemDataSqlClient。OdbcConnection的命名空间为SystemDataOdbc。OracleConnection的命名空间为SystemDataOracleClinet。

SqlConnection属性:

属性 说明

ConnectionString 其返回类型为string,获取或设置用于打开 SQL Server 数据库的字符串。

ConnectionTimeOut 其返回类型为int,获取在尝试建立连接时终止尝试并生成错误之前所等待的时间。

Database 其返回类型为string,获取当前数据库或连接打开后要使用的数据库的名称。

DataSource 其返回类型为string,获取要连接的 SQL Server 实例的名称。

State 其返回类型为ConnectionState,取得当前的连接状态:Broken、Closed、Connecting、Fetching或Open。

ServerVersion 其返回类型为string,获取包含客户端连接的 SQL Server 实例的版本的字符串。

PacketSize 获取用来与 SQL Server 的实例通信的网络数据包的大小(以字节为单位)。这个属性只适用于SqlConnection类型

SqlConnection方法:

方法 说明

Close() 其返回类型为void,关闭与数据库的连接。

CreateCommand() 其返回类型为SqlCommand,创建并返回一个与 SqlConnection 关联的 SqlCommand 对象。

Open() 其返回类型为void,用连接字符串属性指定的属性打开数据库连接

SqlConnection事件:

事件 说明

StateChange 当事件状态更改时发生。 (从 DbConnection 继承。)

InfoMessage 当 SQL Server 返回一个警告或信息性消息时发生。

提示:可以用事件让一个对象以某种方式通知另一对象产生某些事情。例如我们在Windows系统中选择“开始”菜单,一旦单击鼠标时,就发生了一个事件,通知 *** 作系统将“开始”菜单显示出来。

使用SqlConnection对象连接SQL Server数据库

我们可以用SqlConnection()构造函数生成一个新的SqlConnection对象。这个函数是重载的,即我们可以调用构造函数的不同版本。SqlConnection()的构造函数如下表所示:

构造函数 说明

SqlConnection () 初始化 SqlConnection 类的新实例。

SqlConnection (String) 如果给定包含连接字符串的字符串,则初始化 SqlConnection 类的新实例。

假设我们导入了SystemDataSqlClient命名空间,则可以用下列语句生成新的SqlConnection对象:

SqlConnection mySqlConnection = new SqlConnection();

程序代码说明:在上述语法范例的程序代码中,我们通过使用“new“关键字生成了一个新的SqlConnection对象,并且将其命名为mySqlConnection。

现在我们就可以使用如下两种方式连接数据库,即采用集成的Windows验证和使用Sql Server身份验证进行数据库的登录。

集成的Windows身份验证语法范例

string connectionString="server=localhost;database=Northwind;

integrated security=SSPI";

程序代码说明:在上述语法范例的程序代码中,我们设置了一个针对Sql Server数据库的连接字符串。其中server表示运行Sql Server的计算机名,由于在本书中,ASPNET程序和数据库系统是位于同一台计算机的,所以我们可以用localhost取代当前的计算机名。database表示所使用的数据库名,这里设置为Sql Server自带的一个示例数据库--Northwind。由于我们希望采用集成的Windows验证方式,所以设置 integrated security为SSPI即可。

Sql Server 2005中的Windows身份验证模式如下:

注意:在使用集成的Windows验证方式时,并不需要我们输入用户名和口令,而是把登录Windows时输入的用户名和口令传递到Sql Server。然后Sql Server检查用户清单,检查其是否具有访问数据库的权限。而且数据库连接字符串是不区分大小写的。

采用Sql Server身份验证的语法范例

string connectionString = "server=localhost;database=Northwind;uid=sa;pwd=sa";

程序代码说明:在上述语法范例的程序代码中,采用了使用已知的用户名和密码验证进行数据库的登录。uid为指定的数据库用户名,pwd为指定的用户口令。为了安全起见,一般不要在代码中包括用户名和口令,你可以采用前面的集成的Windows验证方式或者对WebConfig文件中的连接字符串加密的方式提高程序的安全性。

Sql Server 2005中的Sql Server身份验证模式如下:

如果你使用其他的数据提供者的话,所产生的连接字符串也具有相类似的形式。例如我们希望以OLE DB的方式连接到一个Oracle数据库,其连接字符串如下:

string connectionString = "data source=localhost;initial catalog=Sales;

use id=sa;password=;provider=MSDAORA";

程序代码说明:在上述语法范例的程序代码中,通过专门针对Oracle数据库的OLE DB提供程序,实现数据库的连接。data source 表示运行Oracle数据库的计算机名,initial catalog表示所使用的数据库名。provider表示使用的OLE DB提供程序为MSDAORA。

Access数据库的连接字符串的形式如下:

string connectionString = "provider=MicrosoftJetOLEDB40;

@”data source=c:\DataSource\Northwindmdb”;

程序代码说明:在上述语法范例的程序代码中,通过专门针对Access数据库的OLE DB提供程序,实现数据库的连接。这使用的的OLE DB提供程序为MicrosoftJetOLEDB40,并且数据库存放在c:\DataSource目录下,其数据库文件为Northwindmdb。

现在我们就可以将数据库连接字符串传人SqlConnection()构造函数,例如:

string connectionString = "server=localhost;database=Northwind;uid=sa;pwd=sa";

SqlConnection mySqlConnection = new SqlConnection(connectionString);

或者写成

SqlConnection mySqlConnection =new SqlConnection(

"server=localhost;database=Northwind;uid=sa;pwd=sa");

在前面的范例中,通过使用“new“关键字生成了一个新的SqlConnection对象。因此我们也可以设置该对象的ConnectionString属性,为其指定一个数据库连接字符串。这和将数据库连接字符串传人SqlConnection()构造函数的功能是一样的。

SqlConnection mySqlConnection = new SqlConnection();

mySqlConnectionConnectionString = "server=localhost;database=Northwind;uid=sa;pwd=sa";

注意:只能在关闭Connection对象时设置ConnectionString属性。

打开和关闭数据库连接

生成Connection对象并将其设置ConnectionString属性设置为数据库连接的相应细节之后,就可以打开数据库连接。为此可以调用Connection对象的Open()方法。其方法如下:

mySqlConnectionOpen();

完成数据库的连接之后,我们可以调用Connection对象的Close()方法关闭数据库连接。例如:

mySqlConnectionClose();

下面是一个显示如何用SqlConnection对象连接Sql Server Northwind数据库的实例程序,并且显示该SqlConnection对象的一些属性。

范例程序代码如下:

01 public partial class _Default : SystemWebUIPage

02 {

03 protected void Page_Load(object sender, EventArgs e)

04 {

05 //建立数据库连接字符串

06 string connectionString = "server=localhost;database=Northwind;

07 integrated security=SSPI";

08 //将连接字符串传入SqlConnection对象的构造函数中

09 SqlConnection mySqlConnection = new SqlConnection(connectionString);

10 try

11 {

12 //打开连接

13 mySqlConnectionOpen();

14 //利用label控件显示mySqlConnection对象的ConnectionString属性

15 lblInfoText = "<b>mySqlConnection对象的ConnectionString属性为:<b>" +

16 mySqlConnectionConnectionString + "<br>";

17 lblInfoText += "<b>mySqlConnection对象的ConnectionTimeout属性为<b>" +

18 mySqlConnectionConnectionTimeout + "<br>";

19 lblInfoText += "<b>mySqlConnection对象的Database属性为<b>" +

20 mySqlConnectionDatabase + "<br>";

21 lblInfoText += "<b>mySqlConnection对象的DataSource属性为<b>" +

22 mySqlConnectionDataSource + "<br>";

23 lblInfoText += "<b>mySqlConnection对象的PacketSize属性为<b>" +

24 mySqlConnectionPacketSize + "<br>";

25 lblInfoText += "<b>mySqlConnection对象的ServerVersion属性为<b>" +

26 mySqlConnectionServerVersion + "<br>";

27 lblInfoText += "<b>mySqlConnection对象的当前状态为<b>" +

28 mySqlConnectionState + "<br>";

29 }

30 catch (Exception err)

31 {

32 lblInfoText = "读取数据库出错";

33 lblInfoText += errMessage;

34 }

35 finally

36 {

37 //关闭与数据库的连接

38 mySqlConnectionClose();

39 lblInfoText += "<br><b>关闭连接后的mySqlConnection对象的状态为:</b>";

40 lblInfoText += mySqlConnectionStateToString();

41 }

42 }

43 }

程序代码说明:在上述范例的程序代码中,我们利用try catch finally对数据库连接进行异常处理。当无法连接数据库时将抛出异常,并显示出错信息,见catch代码块所示。在此程序中,无论是否发生异常,都可以通过finally区块关闭数据库的连接,从而节省计算机资源,提高了程序的效率和可扩展性。

执行结果:

当然,我们还可以采用一种更加简便的方法来实现上述程序的功能。这就是将SqlConnection对象包含到using区块中,这样程序会自动调用Dispose()方法释放SqlConnection对象所占用的系统资源,无需再使用SqlConnection对象的Close()方法。

范例程序代码如下:

01 public partial class _Default : SystemWebUIPage

02 {

03 protected void Page_Load(object sender, EventArgs e)

04 {

05 string connectionString = "server=localhost;database=Northwind;

06 integrated security=SSPI";

07 SqlConnection mySqlConnection = new SqlConnection(connectionString);

08 using (mySqlConnection)

09 {

10 mySqlConnectionOpen();

11 lblInfoText = "<b>mySqlConnection对象的ConnectionString属性为:<b>" +

12 mySqlConnectionConnectionString + "<br>";

13 lblInfoText += "<b>mySqlConnection对象的ConnectionTimeout属性为<b>" +

14 mySqlConnectionConnectionTimeout + "<br>";

15 lblInfoText += "<b>mySqlConnection对象的Database属性为<b>" +

16 mySqlConnectionDatabase + "<br>";

17 lblInfoText += "<b>mySqlConnection对象的DataSource属性为<b>" +

18 mySqlConnectionDataSource + "<br>";

19 lblInfoText += "<b>mySqlConnection对象的PacketSize属性为<b>" +

20 mySqlConnectionPacketSize + "<br>";

21 lblInfoText += "<b>mySqlConnection对象的ServerVersion属性为<b>" +

22 mySqlConnectionServerVersion + "<br>";

23 lblInfoText += "<b>mySqlConnection对象的当前状态为<b>"+

24 mySqlConnectionState + "<br>";

25 }

26 lblInfoText += "<br><b>关闭连接后的mySqlConnection对象的状态为:</b>";

27 lblInfoText += mySqlConnectionStateToString();

28 }

29 }

程序代码说明:在上述范例的程序代码中,采用using(mySqlConnection)的形式使得代码更加简洁,并且其最大的优点就是无需编写finally区块代码,可以自动关闭与数据库的连接。

连接池

打开与关闭数据库都是比较耗时的。为此,ADONET自动将数据库连接存放在连接池中。连接池可以大幅度提高程序的性能和效率,因为我们不必等待建立全新的数据库连接过程,而是直接利用现成的数据库连接。注意,利用Close()方法关闭连接时,并不是实际关闭连接,而是将连接标为未用,放在连接池中,准备下一次复用。

如果在连接字符串中提供相同的细节,即相同的数据库,用户名,密码等等,则可以直接取得并返回池中的连接。然后可以用这个连接访问数据库。

使用SqlConnection对象时,可以在连接字符串中指定max pool size,表示连接池允许的最大连接数(默认为100),也可以指定min pool size表示连接池允许的最小连接数(默认为0)。下面的代码指定了SqlConnection对象的max pool size为10,min pool size为5。

SqlConnection mySqlConnection = new SqlConnection("server=localhost;database=Northwind;

integrated security=SSPI;"+"max pool size=10;min pool size=5");

程序代码说明:在上述范例的程序代码中,程序最初在池中生成5个SqlConnection对象。池中可以存储最多10个SqlConnection对象。如果要打开新的SqlConnection对象时,池中的对象全部都在使用中,则请求要等待一个SqlConnection对象关闭,然后才可以使用新的SqlConnection对象。如果请求等待时间超过ConnectionTimeout属性指定的秒数,则会抛出异常。

下面通过一个程序来显示连接池的性能优势。在应用此程序过程我们要先引用SystemDataSqlClinet和SystemText命名空间。

范例程序代码如下:

01 public partial class _Default : SystemWebUIPage

02 {

03 protected void Page_Load(object sender, EventArgs e)

04 {

05 //设置连接池的最大连接数为5,最小为1

06 SqlConnection mySqlConnection =new SqlConnection(

07 "server=localhost;database=Northwind;integrated security=SSPI;"+

08 "max pool size=5;min pool size=1");

09 //新建一个StringBuilder对象

10 StringBuilder htmStr = new StringBuilder("");

11 for (int count = 1; count <= 5; count++)

12 {

13 //使用Append()方法追加字符串到StringBuilder对象的结尾处

14 htmStrAppend("连接对象 "+count);

15 htmStrAppend("<br>");

16 //设置一个连接的开始时间

17 DateTime start = DateTimeNow;

18 mySqlConnectionOpen();

19 //连接所用的时间

20 TimeSpan timeTaken = DateTimeNow - start;

21 htmStrAppend("连接时间为 "+timeTakenMilliseconds+"毫秒");

22 htmStrAppend("<br>");

23 htmStrAppend("mySqlConnection对象的状态为" + mySqlConnectionState);

24 htmStrAppend("<br>");

25 mySqlConnectionClose();

26 }

27 //将StringBuilder对象的包含的字符串在label控件中显示出来

28 lblInfoText = htmStrToString();

29 }

30 }

程序代码说明:在上述范例的程序代码中,我们将在连接池中重复5次打开一个SqlConnection对象,DateTimeNow表示当前的时间。timeTaken表示从连接开始到打开连接所用的时间间隔。可以看出,打开第一个连接的时间比打开后续连接的时间要长,因为第一个连接要实际连接数据库。被关闭之后,这个连接存放在连接池中。再次打开连接时,只要从池中直接读取即可,速度非常快。

提示:String 对象是不可改变的。每次使用 SystemString 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 SystemTextStringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。Append 方法可用来将文本或对象的字符串表示形式添加到由当前 StringBuilder 对象表示的字符串的结尾处。

在ASPNET 20中,使用了一种在运行时解析为连接字符串值的新的声明性表达式语法,按名称引用数据库连接字符串。连接字符串本身存储在 Webconfig 文件中的 <connectionStrings> 配置节下面,以便易于在单个位置为应用程序中的所有页进行维护。

范例程序代码如下:

<xml version="10">

<configuration>

<connectionStrings>

<add name="Pubs" connectionString="Server=localhost;

Integrated Security=True;Database=pubs;Persist Security Info=True"

providerName="SystemDataSqlClient" />

<add name="Northwind" connectionString="Server=localhost;

Integrated Security=True;Database=Northwind;Persist Security Info=True"

providerName="SystemDataSqlClient" />

</connectionStrings>

<systemweb>

<pages styleSheetTheme="Default"/>

</systemweb>

</configuration>

程序代码说明:在上述范例的程序代码中,我们在WebConfig文件中的<connectionStrings> 配置节点下面设置了两个数据库连接字符串,分别指向pubs和Northwind两个示例数据库。注意,在20中引进了数据源控件,例如SqlDataSource 控件,我们可以将SqlDataSource 控件的 ConnectionString 属性被设置为表达式 <%$ ConnectionStrings:Pubs %>,该表达式在运行时由 ASPNET 分析器解析为连接字符串。还可以为SqlDataSource 的 ProviderName 属性指定一个表达式,例如 <%$ ConnectionStrings:PubsProviderName %>。其具体的用法和新特征将在以后的章节进行详细的介绍。现在有个基础的了解即可。

当然,我们也可以用下面的方式从配置文件直接读取数据库连接字符串。首先我们需要引用using SystemWebConfiguration命名空间,该命名空间包含用于设置 ASPNET 配置的类。

string connectionString =ConfigurationManagerConnectionStrings["Northwind"]ConnectionString;

程序代码说明:在上述范例的程序代码中,我们可以利用ConnectionStrings["Northwind"]读取相应的Northwind字符串。同理以可以利用ConnectionStrings["Pubs"]读取相应的Pubs字符串。

package comdao;import javasql;import javaxnamingContext;

import javaxnamingInitialContext;

import javaxnamingNamingException;

import javaxsqlDataSource;public class BaseDao {

/

创建数据库连接及关闭

/

// 打开连接

public static Connection getConnection() {

Connection con = null; / oracl 的连接 /

// try { // ClassforName("oraclejdbcdriverOracleDriver");

// con = DriverManagergetConnection(

// "jdbc:oracle:thin:@127001:1521:orcl", "bbs", "sa");

// } catch (ClassNotFoundException e) {

// eprintStackTrace();

// } catch (SQLException e) {

// eprintStackTrace();

// }

/ sqlerver 的连接 /

try {

ClassforName("commicrosoftsqlserverjdbcSQLServerDriver");

con = DriverManagergetConnection(

"jdbc:sqlserver://127001:1433;databasename=bbs", "sa",

"zhou");

} catch (ClassNotFoundException e) {

eprintStackTrace();

} catch (SQLException e) {

eprintStackTrace();

}

//

return con;

} // 关闭

public static void closeAll(Connection connection,

PreparedStatement pStatement, ResultSet res) {

try {

if (connection != null && (!connectionisClosed())) {

connectionclose();

}

if (res != null) {

resclose();

res = null;

}

if (pStatement != null) {

pStatementclose();

pStatement = null;

}

} catch (Exception e) {

eprintStackTrace();

}

}

}

对数据库增删改查package comdao;import javasqlConnection;

import javasqlPreparedStatement;

import javasqlResultSet;

import javasqlSQLException;

import javautilArrayList;

import javautilList;import comentityNews;public class NewsDao {

Connection con = null;

PreparedStatement pstmt = null;

ResultSet rs = null;

/

添加新闻

@param news

@return

/

public boolean newsAdd(News news){

boolean result=false;

String sql="insert into news values(,)";

con=BaseDaogetConnection();

try {

pstmt=conprepareStatement(sql);

pstmtsetString(1, newsgetContent());

pstmtsetString(2, FormatTimenewTime());

int i = 0;

i = pstmtexecuteUpdate();

if (i > 0)

result = true;

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

}

return result;

}

/

修改新闻

@param news

@return

/

public boolean updateNews(News news){

boolean result=false;

con=BaseDaogetConnection();

try {

pstmt=conprepareStatement("update news set content= ,writedate= where newsid=");

pstmtsetString(1, newsgetContent());

pstmtsetString(2, FormatTimenewTime());

pstmtsetInt(3, newsgetNewsID());

int i = 0;

i = pstmtexecuteUpdate();

if (i > 0)

result = true;

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

}

return result;

}

/

删除新闻

@param news

@return

/

public boolean deleteNews(News news){

boolean result=false;

String sql=Stringformat("delete from news where newsid=%d", newsgetNewsID());

con=BaseDaogetConnection();

try {

pstmt=conprepareStatement(sql);

int i = 0;

i = pstmtexecuteUpdate();

if (i > 0)

result = true;

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

}

return result;

}

/

删除新闻 重载

@param newsId

@return

/

public boolean deleteNews(int newsId){

boolean result=false;

String sql=Stringformat("delete from news where newsid=%d", newsId);

con=BaseDaogetConnection();

try {

pstmt=conprepareStatement(sql);

int i = 0;

i = pstmtexecuteUpdate();

if (i > 0)

result = true;

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

}

return result;

}

/

查询所有的新闻

@return

/

public List<News> selectAllNews(){

List<News> list=new ArrayList<News>();

String sql="select from Users";

con=BaseDaogetConnection();

try {

pstmt=conprepareStatement(sql);

rs=pstmtexecuteQuery();

while(rsnext()){

News news=new News();

newssetNewsID(rsgetInt(1));

newssetContent(rsgetString(2));

newssetWriteDate(rsgetString(3));

listadd(news);

}

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

} finally {

BaseDaocloseAll(rs, pstmt, con);

}

return list;

}

/

查询单个

@return

/

public News selectOneNews(){

News news=new News();

con=BaseDaogetConnection();

try {

pstmt=conprepareStatement("select top 1 from news order by newsid desc");

rs=pstmtexecuteQuery();

while(rsnext()){

newssetNewsID(rsgetInt(1));

newssetContent(rsgetString(2));

newssetWriteDate(rsgetString(3));

}

} catch (SQLException e) {

// TODO Auto-generated catch block

eprintStackTrace();

} finally {

BaseDaocloseAll(rs, pstmt, con);

}

return news;

}

}

实体类package comentity;import javaioSerializable;

public class News implements Serializable{

private int newsID;

private String content;

private String writeDate; public News() {

super();

// TODO Auto-generated constructor stub

} public News(String content, String writeDate) {

super();

thiscontent = content;

thiswriteDate = writeDate;

} public News(int newsID, String content, String writeDate) {

super();

thisnewsID = newsID;

thiscontent = content;

thiswriteDate = writeDate;

} public int getNewsID() {

return newsID;

} public void setNewsID(int newsID) {

thisnewsID = newsID;

} public String getContent() {

return content;

} public void setContent(String content) {

thiscontent = content;

} public String getWriteDate() {

return writeDate;

} public void setWriteDate(String writeDate) {

thiswriteDate = writeDate;

}

}

VFP(Visual FoxPro)是一种强大的关系型数据库管理系统,它支持多种数据模型,包括层次模型、网络模型和关系模型等。其中,最常用的数据模型是关系模型,也称为表格模型。在关系模型中,数据被存储在表格中,每个表格包含若干个字段,每个字段都有一个特定的数据类型。表格之间的关系可以通过外键来建立,从而构成一个关系数据库。

在VFP中,还支持对象模型、面向对象模型、XML模型等多种数据模型。对象模型是一种以对象为中心的模型,每个对象都有自己的属性和方法,它们可以通过继承和多态等机制进行扩展和重载。面向对象模型则是一种更加强大的对象模型,它不仅包括对象的属性和方法,还包括对象之间的关系和行为。XML模型则是一种基于XML(可扩展标记语言)的数据模型,它可以将数据以文本的形式进行存储和传输,具有很好的可扩展性和跨平台性。

综上所述,VFP支持多种数据模型,每种数据模型都有其独特的优势和适用场景,可以根据实际需求选择合适的数据模型来构建数据库。

以上就是关于Delphi深度探索之使用Bold开发数据库应用(1)全部的内容,包括:Delphi深度探索之使用Bold开发数据库应用(1)、VC中打开数据库的问题、android sqlite数据库的更新等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9712917.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存