数据库中Schema和Database有什么区别

数据库中Schema和Database有什么区别,第1张

在mysql中创建一个schema好像就跟创建一个database是一样的效果,在sql

server和orcal数据库中好像又不一样

目前我只能理解,在mysql中

schema<==>database。

数据库中user和schema的关系

假如我们想了解数据库中的user和schema究竟是什么关系,首先必须了解一下数据库中user和schema到底是什么概念。

在sql

server2000中,由于架构的原因,user和schema总有一层隐含的关系,让我们很少意识到其实user和schema是两种完全不同的概念,不过在sql

server2005中这种架构被打破了,user和schema也被分开了。

首先我来做一个比喻,什么是database,什么是schema,什么是table,什么是列,什么是行,什么是user?我们可以可以把database看作是一个大仓库,仓库分了很多很多的房间,schema就是其中的房间,一个schema代表一个房间,table可以看作是每个schema中的床,table(床)就被放入每个房间中,不能放置在房间之外,那岂不是晚上睡觉无家可归了j。,然后床上可以放置很多物品,就好比table上可以放置很多列和行一样,数据库中存储数据的基本单元是table,现实中每个仓库放置物品的基本单位就是床,

user就是每个schema的主人,(所以schema包含的是object,而不是user),其实user是对应与数据库的(即user是每个对应数据库的主人),既然有 *** 作数据库(仓库)的权利,就肯定有 *** 作数据库中每个schema(房间)的权利,就是说每个数据库映射的user有每个schema(房间)的钥匙,换句话说,如果他是某个仓库的主人,那么这个仓库的使用权和仓库中的所有东西都是他的(包括房间),他有完全的 *** 作权,可以扔掉不用的东西从每个房间,也可以放置一些有用的东西到某一个房间,呵呵,和现实也太相似了吧。我还可以给user分配具体的权限,也就是他到某一个房间能做些什么,是只能看(read-only),还是可以像主人一样有所有的控制权(r/w),这个就要看这个user所对应的角色role了,至于分配权限的问题,我留在以后单独的blog中详述。比喻到这里,相信大家都清楚了吧。

首先,没有数据库是能够建立连接的,但这只是和mysql服务器相连,而不是和某个具体的数据库,所以,这样的连接,意义不大(不知道你用什么 *** 作mysql,所以没有给出具体连接字符串)

你如果建立好了连接,判断数据库是否存在就简单了

因为mysql中有一个数据库information_schema(这应该是你知道的),而这张数据库中有一张表schemata,是用来存储其他数据库信息的,你用

select

schema_name

from

schemata;

查询一下,所有的数据库就出来了。

ps

我不知道你用的什么和mysql相连的,所以,告诉你的都是通用的方法。如果有问题,再hi我

在MySQL中创建一个Schema好像就跟创建一个Database是一样的效果,在SQL Server和Orcal数据库中好像又不一样 目前我只能理解,在mysql中 schema<==>database。

数据库中User和Schema的关系

假如我们想了解数据库中的User和Schema究竟是什么关系,首先必须了解一下数据库中User和Schema到底是什么概念。

在SQL Server2000中,由于架构的原因,User和Schema总有一层隐含的关系,让我们很少意识到其实User和Schema是两种完全不同的概念,不过在SQL Server2005中这种架构被打破了,User和Schema也被分开了。

 

 首先我来做一个比喻,什么是Database,什么是Schema,什么是Table,什么是列,什么是行,什么是User?我们可以可以把

Database看作是一个大仓库,仓库分了很多很多的房间,Schema就是其中的房间,一个Schema代表一个房间,Table可以看作是每个

Schema中的床,Table(床)就被放入每个房间中,不能放置在房间之外,那岂不是晚上睡觉无家可归了J。,然后床上可以放置很多物品,就好比

Table上可以放置很多列和行一样,数据库中存储数据的基本单元是Table,现实中每个仓库放置物品的基本单位就是床,

User就是每个Schema的主人,(所以Schema包含的是Object,而不是User),其实User是对应与数据库的(即User是每个对应

数据库的主人),既然有 *** 作数据库(仓库)的权利,就肯定有 *** 作数据库中每个Schema(房间)的权利,就是说每个数据库映射的User有每个

Schema(房间)的钥匙,换句话说,如果他是某个仓库的主人,那么这个仓库的使用权和仓库中的所有东西都是他的(包括房间),他有完全的 *** 作权,可以

扔掉不用的东西从每个房间,也可以放置一些有用的东西到某一个房间,呵呵,和现实也太相似了吧。我还可以给User分配具体的权限,也就是他到某一个房间

能做些什么,是只能看(Read-Only),还是可以像主人一样有所有的控制权(R/W),这个就要看这个User所对应的角色Role了,至于分配权

限的问题,我留在以后单独的blog中详述。比喻到这里,相信大家都清楚了吧。

在SQL Server2000中,假如我们在某一个数据库中创建了用户Bosco,按么此时后台也为我们默认地创建了默认Schema Bosco。Schema的名字和User的名字相同,这也是我们分不清楚用户和Schema的原因。

 

 在SQL Server2005中,为了向后兼容,当你用sp_adduser 存储过程创建一个用户的时候,SQL

Server2005同时也创建了一个和用户名相同的Schema,然而这个存储过程是为了向后兼容才保留的,我们应该逐渐熟悉用新的DDL语言

Create User和Create Schema来 *** 作数据库。在SQL Server2005中,当我们用Create

User创建数据库用户时,我们可以为该用户指定一个已经存在的Schema作为默认Schema,如果我们不指定,则该用户所默认的Schema即为

dbo Schema,dbo

房间(Schema)好比一个大的公共房间,在当前登录用户没有默认Schema的前提下,如果你在大仓库中进行一些 *** 作,比如Create

Tabe,如果没有指定特定的房间(Schema),那么你的物品就只好放进公共的dbo房间(Schema)了。但是如果当前登录用户有默认的

Schema,那么所做的一切 *** 作都是在默认Schema上进行(比如当前登录用户为login1,该用户的默认Schema为login1,那么所做的

所有 *** 作都是在这个login1默认Schema上进行的。实验已经证明的确如此)。估计此时你会有一点晕,为什么呢?我刚才说dbo是一个

Schema,但是你可以在数据库中查看到,dbo同时也是一个user,晕了吧,呵呵。

在SQL Server2005中创建一个数据库的时候,会有一些Schema包括进去,被包括进去的Schema有:dbo,INFORMATION_SCHEMA, guest,sys等等(还有一些角色Schema,不提了,有晕了)。

 

 我在上文中已经提到了,在SQL Server2005中当用存储过程sp_adduser创建一个user时,同时SQL

Server2005也为我们创建了一个默认的和用户名相同的Schema,这个时候问题出来了,当我们create table

A时,如果没有特定的Schema做前缀,这个A表创建在了哪个Schema上,即进入了哪个房间?答案是:

1如果当前 *** 作数据库的用户(可以用Select current_user查出来)有默认的Schema(在创建用户的时候指定了),那么表A被创建在了默认的Schema上。

 

 2如果当前 *** 作数据库的用户没有默认的Schema(即在创建User的时候默认为空),但是有一个和用户名同名的Schema,那么表A照样被创建

在了dbo

Schema上,即使有一个和用户名同名的Schema存在,由于它不是该用户默认的Schema,所以创建表的时候是不会考虑的,当作一般的

Schema来处理,别看名字相同,可是没有任何关系哦。

3如果在创建表A的时候指定了特定的Schema做前缀,则表A被创建在了指定的 Schema上(有权限吗?)

 

 现在问题又出来了,在当前 *** 作数据库的用户(用select

current_user可以查看到,再次强调)没有默认Schema的前提下,当我们用Create table A语句时,A表会去寻找dbo

Schema,并试图创建在dbo Schema上,但是如果创建A表的用户只有对dbo

Schema的只读权限,而没有写的权限呢?这个时候A表既不是建立不成功,这个就是我以后会提及到的Login,User,

Role和Schema四者之间的关系。在这里,为了避免混淆和提高 *** 作数据库的速度(在少量数据范围内,对我们肉眼来说几乎看不到差异),我们最好每次

在 *** 作数据库对象的时候都显式地指定特定的Schema最为前缀。

现在如果登录的用户为Sue,该用户有一个默认Schema也为Sue,那么如果现在有一条查询语句为Select from mytable, 那么搜寻每个房间(Schema)的顺序是怎样的呢?顺序如下:

1 首先搜寻sysmytable (Sys Schema)

2 然后搜寻Suemytable (Default Schema)

3 最后搜寻 dbomytable (Dbo Schema)

执行的顺序大家既然清楚了,那么以后在查询数据库表中的数据时,最好指定特定的Schema前缀,这样子,数据库就不用去扫描Sys Schem

运用DBUnit进行高效单元测试

译者注:最近对DBUnit比较感兴趣,看到这篇文章就翻译出来和大家共享,不过我也是New

Hand,所以翻译不好的地方请大家指正。我的MSN:zhlihui@hotmailcom,如果大家有什么好的资源和经验欢迎和我交流

引入DBUnit

现实系统中通常会有一些具有外部依赖性的对象,这些对象和数据库或者其他对象存在诸多关联。如果我们对这样的对象编写单元和组件级测试的话,可以想象将是非常麻烦的一件事因为这种外部依赖性的存在,使的我们很难将对象孤立出来进行测试。经常提及的白盒测试法,基本上就是通过控制对象的外部依赖性来达到隔离对象的目的,使的可以 *** 作这些对象的状态和相关行为。

运用 模拟对象(mock objects)

或者stubs,就是一个控制对象外部依赖性的解决方案。通过隔离那些关联的数据库访问类,象JDBC的相关 *** 作类,对于控制对象外部依赖性将是很有效的。但模拟对象的解决方案对一些特殊的应用系统架构就显得力不从心了,象那些运用了EJB的CMP(container-managed

persistence)或者 JDO(java Data

Objects)的应用系统架构,在这些架构里,数据库的访问对象是在最底层的而且很隐蔽。

由Manuel Laflamme

编写的开放源代码的DBUnit架构体系,对于控制系统内部的数据库依赖性提供了一个非常不错的解决方案。他允许程序员在整个的测试过程中自由的管理控制数据库的状态,这很重要。利用DBUnit,在测试之前,我们可以给目标数据库植入我们需要的数据集,而且,在测试完毕后,数据库完全能够回溯到测试前的状态。

在很多成功的软件项目中,测试自动化往往是关键的层面。DBUnit允许开发人员创建测试用例代码,在这些测试用例的生命周期内我们可以很好的控制数据库的状态。而且,这些测试用例是很容易实现自动化的。这样在测试过程中我们无须对它进行人工的干预,为人工干预造成的后果而担心就更没必要了。

简单介绍

配置使用DBUnit的第一步我们首先需要知道如何生成数据库schema,这个文件是XML格式的,其中包括了数据库的表及相关数据信息。

例如,这里有一个数据库表employee

,我们可以用SQL的形式这样将他表示出来。

而且,我们可以看到,一个简单的数据集可以这样表示

在DBUnit中,上面这个表和抽样数据信息可以用XML文件的形式这样表示:

<EMPLOYEE employee_uid='1'

start_date='2001-11-01'

first_name='Andrew'

ssn='xxx-xx-xxxx'

last_name='Glover' />

这个生成的XML格式的文件可以作为系统所需的所有种子文件(seed

files)的样本模版

为相互关联的测试场景创建多个种子文件是一个很有效的策略,就象通过不同的数据库文件来区分隔离数据库状态是一个道理。多种子文件策略可以将我们的测试目标锁定到较小的范围,目标数据可以只针对数据库的表,而不是整个数据库。

为了给目标数据库植入不同的职员记录,我们需要的XML数据文件如下所示:

<xml version='10' encoding='UTF-8'>

<dataset>

<EMPLOYEE employee_uid='1'

start_date='2001-01-01'

first_name='Drew' ssn='000-29-2030'

last_name='Smith' />

<EMPLOYEE employee_uid='2'

start_date='2002-04-04'

first_name='Nick' ssn='000-90-0000'

last_name='Marquiss' />

<EMPLOYEE employee_uid='3'

start_date='2003-06-03'

first_name='Jose' ssn='000-67-0000'

last_name='Whitson' />

</dataset>

现在,要让DBUnit和我们所需的数据库schema一起工作了,对于程序员来说,我们使用DBUnit进行测试可以有两种选择:通过直接编码方式进行测试或者与Ant结合

编码方式

DBUnit框架提供了一个基本的抽象测试用例类,叫做DatabaseTestCase,它是JUnit框架中的基础类TestCase的子类。如果我们使用这个类必须首先实现两个钩子方法(hook

methods):getConnection()和getDataSet()

方法getConnection()需要返回一个IDatabaseConnection类型的对象,这个对象是一个基于普通JDBC连接的包装类。例如,下面的代码段演示了在MySQL数据库环境下,IDatabaseConnection类型连接对象的创建方法。

protected IDatabaseConnection getConnection()

throws Exception {

Class driverClass = ClassforName("orggjtmmmysqlDriver");

Connection jdbcConnection = DriverManagergetConnection(

"jdbc:mysql://127001/hr", "hr", "hr");

return new DatabaseConnection(jdbcConnection);

}

方法getDataSet()返回一个IDataSet类型对象,其实,说白了,他就是我们先前提到的XML数据的种子文件的另一种表现形式。

protected IDataSet getDataSet() throws Exception {

return new FlatXmlDataSet(

new

FileInputStream("hr-seedxml"));

}

有了这两个基本的方法以后,DBUnit就可以按照它预先缺省的行为工作了。DatabaseTestCase类提供了两个fixture(我叫它固件,不知仁兄同意否?)方法来控制测试前和测试后的数据库状态。这两个方法就是:

getSetUpOperation() 和 getTearDownOperation()

一种高效的实施方案就是让getSetUpOperation()方法执行REFRESH *** 作,通过这个 *** 作,我们可以用种子文件中的数据去更新目标数据库里的数据。接下来,就是getTearDownOperation(),让他去执行一个NONE *** 作,也就是什么也不执行。

protected DatabaseOperation getSetUpOperation()

throws

Exception {

return DatabaseOperationREFRESH;

}

protected DatabaseOperation getTearDownOperation()

throws

Exception {

return DatabaseOperationNONE;

}

还有一种有效的方法就是在getSetUpOperation()方法中执行CLEAN_INSERT *** 作,这样首先会将目标数据库中与我们提供的种子文件一致的数据删除,然后将我们提供的数据插入到数据库中。这个实施顺序保证了我们对数据库的精确控制。

代码样例

在一个基于J2EE的人力资源系统中,我们很希望对某个数据 *** 作周期实现测试自动化,这个 *** 作周期包括职员的新增,检索,更新和删除。远程接口定义了下列的业务方法(为了简洁清楚,省略了方法中的throws子句)

//译者注:这里的EmployeeValueObject类型对象,译者认为是代表职员实体信息的对象。

public void createEmployee( EmployeeValueObject emplVo )

public EmployeeValueObject getEmployeeBySocialSecNum( String ssn )

public void updateEmployee( EmployeeValueObject emplVo )

public void deleteEmployee( EmployeeValueObject emplVo )

测试getEmployeeBySocialSecNum()方法

需要植入一条数据到目标数据库中,另外,测试deleteEmployee()方法和updateEmployee()方法时,同样也是在先前植入的这条记录的基础上进行。最后,测试类会首先利用createEmployee()方法创建一条记录,同时我们需要校验执行这个方法时,是否会有异常发生。

下面这个DBUnit种子文件,叫做"employee_hr_seedxml",下面将用到这个文件。

<xml version='10' encoding='UTF-8'>

<dataset>

<EMPLOYEE employee_uid='1'

start_date='2001-01-01'

first_name='Drew' ssn='333-29-9999'

last_name='Smith' />

<EMPLOYEE employee_uid='2'

start_date='2002-04-04'

first_name='Nick' ssn='222-90-1111'

last_name='Marquiss' />

<EMPLOYEE employee_uid='3'

start_date='2003-06-03'

first_name='Jose' ssn='111-67-2222'

last_name='Whitson' />

</dataset>

测试类 EmployeeSessionFacadeTest

,需要扩展DBUnit的基础类DatabaseTestCase并且必须提供对getConnection()和getDataSet()方法的实现,在getConnection()方法中将获得与EJB容器初始化时一样的数据库实例,getDataSet()方法负责读取上面提及的employee_hr_seedxml文件的数据。

测试方法相当简单,因为DBUnit已经为我们处理了复杂的数据库生命周期任务。为了测试getEmployeeBySocialSecNum()方法,只需要简单的传递一个存在于种子文件中的社保代码号即可,比如

"333-29-9999"

//译者注:EmployeeFacade 类型对象,译者认为是代表底层数据库数据的映射体

public void testFindBySSN() throws Exception{

EmployeeFacade facade = //obtain somehow

EmployeeValueObject vo =

facadegetEmployeeBySocialSecNum("333-29-9999");

TestCaseassertNotNull("vo shouldn't be null", vo);

TestCaseassertEquals("should be Drew",

"Drew", vogetFirstName());

TestCaseassertEquals("should be Smith",

"Smith", vogetLastName());

}

为了确保 *** 作周期中的创建职员方法createEmployee()没有问题,我们只需简单的执行一下这个方法,然后校验一下看有没有异常抛出,另外,下一步我们要做的就是在这条新增的记录上进行查找 *** 作,看是否可以找到刚创建的记录。

public void testEmployeeCreate() throws Exception{

EmployeeValueObject empVo = new EmployeeValueObject();

empVosetFirstName("Noah");

empVosetLastName("Awan");

empVosetSSN("564-55-5555");

EmployeeFacade empFacade = //obtain from somewhere

empFacadecreateEmployee(empVo);

//perform a find by ssn to ensure existence

}

测试updateEmployee()方法包括四步,首先查找我们需要被更新的那条记录,然后更新它,紧接着,重新查找这条记录,确认更新 *** 作是否有效。

public void testUpdateEmployee() throws Exception{

EmployeeFacade facade =//obtain facade

EmployeeValueObject vo =

facadegetEmployeeBySocialSecNum("111-67-2222");

TestCaseassertNotNull("vo was null", vo);

TestCaseassertEquals("first name should be Jose", "Jose",

vogetFirstName());

vosetFirstName("Ramon");

facadeupdateEmployee(vo);

EmployeeValueObject newVo =

facadegetEmployeeBySocialSecNum("111-67-2222");

TestCaseassertNotNull("vo was null", newVo);

TestCaseassertEquals("name should be Ramon", "Ramon",

newVogetFirstName());

}

确保数据 *** 作周期中的删除 *** 作deleteEmployee()的方法和testUpdateEmployee()方法基本类似。

它分为三步:首先查找一个已存在的记录实体,然后移除,最后再对相同的记录进行查找,确认这条记录没有被查到。

public void testDeleteEmployee() throws Exception{

EmployeeFacade facade = //obtain facade

EmployeeValueObject vo = facadegetEmployeeBySocialSecNum("222-90-1111");

TestCaseassertNotNull("vo was null", vo);

facadedeleteEmployee(vo);

try{

EmployeeValueObject newVo =

facadegetEmployeeBySocialSecNum("222-90-1111");

TestCasefail("returned removed employee");

}catch(Exception e){

//ignore

}

}

上述这些测试代码很简单也很容易理解因为这些代码唯一的职责就是测试,已经完全从系统程序代码中独立出来,这使测试变的简单。并且,这些测试用例的自动化也很容易实现。

与Ant的结合

相对于扩展DBUnit中的基础类DatabaseTestCase,DBUnit框架中自带Ant功能,允许我们可以在Ant的buildxml文件中控制数据库的状态这个功能是相当强大的,因为对于作成的诸多测试用例,它提供了一个相当简洁的解决方案。比如。在Ant中运行JUnit测试,就象下面定义一个任务一样简单明了。

<junit printsummary="yes" haltonfailure="yes">

<formatter type="xml"/>

<batchtest fork="yes"

todir="${reportstests}">

<fileset dir="${srctests}">

<include name="/Testjava"/>

</fileset>

</batchtest>

</junit>

DBUnit任务过程中,为了在Junit任务前后控制数据库的状态,我们需要创建一个"setup" *** 作,在这个 *** 作中种子文件中的数据内容会被插入的数据库中。

<taskdef name="dbunit"

classname="orgdbunitantDbUnitTask"/>

<dbunit driver=" orggjtmmmysqlDriver "

url=" jdbc:mysql://127001/hr "

userid="hr"

password="hr">

<operation type="INSERT"

src="seedFilexml"/>

</dbunit>

然后,还需要一个"tear

down" *** 作,在这个 *** 作中,"setup" *** 作插入的记录被从目标数据库中删除了。

<dbunit driver=" orggjtmmmysqlDriver "

url=" jdbc:mysql://127001/hr "

userid="hr"

password="hr">

<operation type="DELETE"

src="seedFilexml"/>

</dbunit>

用上面的代码来包装JUnit任务,能够在批量测试前有效的装载数据到目标数据库中,并且在测试结束后,将已装载的全部数据删除。

<taskdef name="dbunit"

classname="orgdbunitantDbUnitTask"/>

<!-- set up operation -->

<dbunit driver=" orggjtmmmysqlDriver "

url=" jdbc:mysql://127001/hr "

userid="hr"

password="hr">

<operation type="INSERT"

src="seedFilexml"/>

</dbunit>

<!-- run all tests in the source tree -->

<junit printsummary="yes" haltonfailure="yes">

<formatter type="xml"/>

<batchtest fork="yes" todir="${reportstests}">

<fileset dir="${srctests}">

<include name="/Testjava"/>

</fileset>

</batchtest>

</junit>

<!-- tear down operation -->

<dbunit driver=" orggjtmmmysqlDriver "

url=" jdbc:mysql://127001/hr "

userid="hr"

password="hr">

<operation type="DELETE"

src="seedFilexml"/>

</dbunit>

结论

能够在测试周期内管理数据库的状态,DBUnit框架的这个功能特性使得测试用例代码的创建和应用的周期大大缩短。而且,通过控制数据库这个主要的依赖对象,使的利用DBUnit框架的的测试更容易自动化。

DBUnit精妙的设计,使的学习使用它变得很简单。在你的测试方案中,如果你能够正确的使用它,那么带来的将是代码稳定性方面的大幅度增强,当然还会使你的开发团队信心倍增。

以上就是关于数据库中Schema和Database有什么区别全部的内容,包括:数据库中Schema和Database有什么区别、php *** 作MySQL数据库判断多个数据表是否存在,不存在就创建要怎么写呢、数据库中Schema和Database有什么区别等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

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

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

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

发表评论

登录后才能评论

评论列表(0条)

保存