楼主: ccwlm741212

[精华] Ms SQL常见问题收集整理集(不断收集中...)

[复制链接]
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
61#
 楼主| 发表于 2003-12-15 13:25 | 只看该作者
【 SQL Server安全规划全攻略(转载) 】  
[ 作者:佚名    转贴自:本站原创    点击数:6    更新时间:2003-12-12    文章录入:电脑教程 ]

在改进SQL Server 7.0系列所实现的安全机制的过程中,Microsoft建立了一种既灵活又强大的安全管理机制,它能够对用户访问SQL Server服务器系统和数据库的安全进行全面地管理。按照本文介绍的步骤,你可以为SQL Server 7.0(或2000)构造出一个灵活的、可管理的安全策略,而且它的安全性经得起考验。
一、验证方法选择
本文对验证(authentication)和授权(authorization)这两个概念作不同的解释。验证是指检验用户的身份标识;授权是指允许用户做些什么。在本文的讨论中,验证过程在用户登录SQL Server的时候出现,授权过程在用户试图访问数据或执行命令的时候出现。

构造安全策略的第一个步骤是确定SQL Server用哪种方式验证用户。SQL Server的验证是把一组帐户、密码与Master数据库Sysxlogins表中的一个清单进行匹配。Windows NT/2000的验证是请求域控制器检查用户身份的合法性。一般地,如果服务器可以访问域控制器,我们应该使用Windows NT/2000验证。域控制器可以是Win2K服务器,也可以是NT服务器。无论在哪种情况下,SQL Server都接收到一个访问标记(Access Token)。访问标记是在验证过程中构造出来的一个特殊列表,其中包含了用户的SID(安全标识号)以及一系列用户所在组的SID。正如本文后面所介绍的,SQL Server以这些SID为基础授予访问权限。注意,操作系统如何构造访问标记并不重要,SQL Server只使用访问标记中的SID。也就是说,不论你使用SQL Server 2000、SQL Server 7.0、Win2K还是NT进行验证都无关紧要,结果都一样。

如果使用SQL Server验证的登录,它最大的好处是很容易通过Enterprise Manager实现,最大的缺点在于SQL Server验证的登录只对特定的服务器有效,也就是说,在一个多服务器的环境中管理比较困难。使用SQL Server进行验证的第二个重要的缺点是,对于每一个数据库,我们必须分别地为它管理权限。如果某个用户对两个数据库有相同的权限要求,我们必须手工设置两个数据库的权限,或者编写脚本设置权限。如果用户数量较少,比如25个以下,而且这些用户的权限变化不是很频繁,SQL Server验证的登录或许适用。但是,在几乎所有的其他情况下(有一些例外情况,例如直接管理安全问题的应用),这种登录方式的管理负担将超过它的优点。

二、Web环境中的验证
即使最好的安全策略也常常在一种情形前屈服,这种情形就是在Web应用中使用SQL Server的数据。在这种情形下,进行验证的典型方法是把一组SQL Server登录名称和密码嵌入到Web服务器上运行的程序,比如ASP页面或者CGI脚本;然后,由Web服务器负责验证用户,应用程序则使用它自己的登录帐户(或者是系统管理员sa帐户,或者为了方便起见,使用Sysadmin服务器角色中的登录帐户)为用户访问数据。

这种安排有几个缺点,其中最重要的包括:它不具备对用户在服务器上的活动进行审核的能力,完全依赖于Web应用程序实现用户验证,当SQL Server需要限定用户权限时不同的用户之间不易区别。如果你使用的是IIS 5.0或者IIS 4.0,你可以用四种方法验证用户。第一种方法是为每一个网站和每一个虚拟目录创建一个匿名用户的NT帐户。此后,所有应用程序登录SQL Server时都使用该安全环境。我们可以通过授予NT匿名帐户合适的权限,改进审核和验证功能。

第二种方法是让所有网站使用Basic验证。此时,只有当用户在对话框中输入了合法的帐户和密码,IIS才会允许他们访问页面。IIS依靠一个NT安全数据库实现登录身份验证,NT安全数据库既可以在本地服务器上,也可以在域控制器上。当用户运行一个访问SQL Server数据库的程序或者脚本时,IIS把用户为了浏览页面而提供的身份信息发送给服务器。如果你使用这种方法,应该记住:在通常情况下,浏览器与服务器之间的密码传送一般是不加密的,对于那些使用Basic验证而安全又很重要的网站,你必须实现SSL(Secure Sockets Layer,安全套接字层)。

在客户端只使用IE 5.0、IE 4.0、IE 3.0浏览器的情况下,你可以使用第三种验证方法。你可以在Web网站上和虚拟目录上都启用NT验证。IE会把用户登录计算机的身份信息发送给IIS,当该用户试图登录SQL Server时IIS就使用这些登录信息。使用这种简化的方法时,我们可以在一个远程网站的域上对用户身份进行验证(该远程网站登录到一个与运行着Web服务器的域有着信任关系的域)。

最后,如果用户都有个人数字证书,你可以把那些证书映射到本地域的NT帐户上。个人数字证书与服务器数字证书以同样的技术为基础,它证明用户身份标识的合法性,所以可以取代NT的Challenge/Response(质询/回应)验证算法。Netscape和IE都自动在每一个页面请求中把证书信息发送给IIS。IIS提供了一个让管理员把证书映射到NT帐户的工具。因此,我们可以用数字证书取代通常的提供帐户名字和密码的登录过程。

由此可见,通过NT帐户验证用户时我们可以使用多种实现方法。即使当用户通过IIS跨越Internet连接SQL Server时,选择仍旧存在。因此,你应该把NT验证作为首选的用户身份验证办法。

三、设置全局组
构造安全策略的下一个步骤是确定用户应该属于什么组。通常,每一个组织或应用程序的用户都可以按照他们对数据的特定访问要求分成许多类别。例如,会计应用软件的用户一般包括:数据输入操作员,数据输入管理员,报表编写员,会计师,审计员,财务经理等。每一组用户都有不同的数据库访问要求。

控制数据访问权限最简单的方法是,对于每一组用户,分别地为它创建一个满足该组用户权限要求的、域内全局有效的组。我们既可以为每一个应用分别创建组,也可以创建适用于整个企业的、涵盖广泛用户类别的组。然而,如果你想要能够精确地了解组成员可以做些什么,为每一个应用程序分别创建组是一种较好的选择。例如,在前面的会计系统中,我们应该创建Data Entry Operators、Accounting Data Entry Managers等组。请记住,为了简化管理,最好为组取一个能够明确表示出作用的名字。

除了面向特定应用程序的组之外,我们还需要几个基本组。基本组的成员负责管理服务器。按照习惯,我们可以创建下面这些基本组:SQL Server Administrators,SQL Server Users,SQL Server Denied Users,SQL Server DB Creators,SQL Server Security Operators,SQL Server Database Security Operators,SQL Server Developers,以及 DB_Name Users(其中DB_Name是服务器上一个数据库的名字)。当然,如果必要的话,你还可以创建其他组。

创建了全局组之后,接下来我们可以授予它们访问SQL Server的权限。首先为SQL Server Users创建一个NT验证的登录并授予它登录权限,把Master数据库设置为它的默认数据库,但不要授予它访问任何其他数据库的权限,也不要把这个登录帐户设置为任何服务器角色的成员。接着再为SQL Server Denied Users重复这个过程,但这次要拒绝登录访问。在SQL Server中,拒绝权限始终优先。创建了这两个组之后,我们就有了一种允许或拒绝用户访问服务器的便捷方法。

为那些没有直接在Sysxlogins系统表里面登记的组授权时,我们不能使用Enterpris Managr,因为Enterprise Manager只允许我们从现有登录名字的列表选择,而不是域内所有组的列表。要访问所有的组,请打开Query Analyzer,然后用系统存储过程sp_addsrvrolemember以及sp_addrolemember进行授权。

对于操作服务器的各个组,我们可以用sp_addsrvrolemember存储过程把各个登录加入到合适的服务器角色:SQL Server Administrators成为Sysadmins角色的成员,SQL Server DB Creators成为Dbcreator角色的成员,SQL Server Security Operators成为Securityadmin角色的成员。注意sp_addsrvrolemember存储过程的第一个参数要求是帐户的完整路径。例如,BigCo域的JoeS应该是bigco\joes(如果你想用本地帐户,则路径应该是server_name\joes)。

要创建在所有新数据库中都存在的用户,你可以修改Model数据库。为了简化工作,SQL Server自动把所有对Model数据库的改动复制到新的数据库。只要正确运用Model数据库,我们无需定制每一个新创建的数据库。另外,我们可以用sp_addrolemember存储过程把SQL Server Security Operators加入到db_securityadmin,把SQL Server Developers加入到db_owner角色。

注意我们仍然没有授权任何组或帐户访问数据库。事实上,我们不能通过Enterprise Manager授权数据库访问,因为Enterprise Manager的用户界面只允许我们把数据库访问权限授予合法的登录帐户。SQL Server不要求NT帐户在我们把它设置为数据库角色的成员或分配对象权限之前能够访问数据库,但Enterprise Manager有这种限制。尽管如此,只要我们使用的是sp_addrolemember存储过程而不是Enterprise Manager,就可以在不授予域内NT帐户数据库访问权限的情况下为任意NT帐户分配权限。

到这里为止,对Model数据库的设置已经完成。但是,如果你的用户群体对企业范围内各个应用数据库有着类似的访问要求,你可以把下面这些操作移到Model数据库上进行,而不是在面向特定应用的数据库上进行。

四、允许数据库访问
在数据库内部,与迄今为止我们对登录验证的处理方式不同,我们可以把权限分配给角色而不是直接把它们分配给全局组。这种能力使得我们能够轻松地在安全策略中使用SQL Server验证的登录。即使你从来没有想要使用SQL Server登录帐户,本文仍旧建议分配权限给角色,因为这样你能够为未来可能出现的变化做好准备。

创建了数据库之后,我们可以用sp_grantdbaccess存储过程授权DB_Name Users组访问它。但应该注意的是,与sp_grantdbaccess对应的sp_denydbaccess存储过程并不存在,也就是说,你不能按照拒绝对服务器访问的方法拒绝对数据库的访问。如果要拒绝数据库访问,我们可以创建另外一个名为DB_Name Denied Users的全局组,授权它访问数据库,然后把它设置为db_denydatareader以及db_denydatawriter角色的成员。注意SQL语句权限的分配,这里的角色只限制对对象的访问,但不限制对DDL(Data Definition Language,数据定义语言)命令的访问。

正如对登录过程的处理,如果访问标记中的任意SID已经在Sysusers系统表登记,SQL将允许用户访问数据库。因此,我们既可以通过用户的个人NT帐户SID授权用户访问数据库,也可以通过用户所在的一个(或者多个)组的SID授权。为了简化管理,我们可以创建一个名为DB_Name Users的拥有数据库访问权限的全局组,同时不把访问权授予所有其他的组。这样,我们只需简单地在一个全局组中添加或者删除成员就可以增加或者减少数据库用户。

五、分配权限
实施安全策略的最后一个步骤是创建用户定义的数据库角色,然后分配权限。完成这个步骤最简单的方法是创建一些名字与全局组名字配套的角色。例如对于前面例子中的会计系统,我们可以创建Accounting Data Entry Operators、Accounting Data Entry Managers之类的角色。由于会计数据库中的角色与帐务处理任务有关,你可能想要缩短这些角色的名字。然而,如果角色名字与全局组的名字配套,你可以减少混乱,能够更方便地判断出哪些组属于特定的角色。

创建好角色之后就可以分配权限。在这个过程中,我们只需用到标准的GRANT、REVOKE和DENY命令。但应该注意DENY权限,这个权限优先于所有其他权限。如果用户是任意具有DENY权限的角色或者组的成员,SQL Server将拒绝用户访问对象。

接下来我们就可以加入所有SQL Server验证的登录。用户定义的数据库角色可以包含SQL Server登录以及NT全局组、本地组、个人帐户,这是它最宝贵的特点之一。用户定义的数据库角色可以作为各种登录的通用容器,我们使用用户定义角色而不是直接把权限分配给全局组的主要原因就在于此。

由于内建的角色一般适用于整个数据库而不是单独的对象,因此这里建议你只使用两个内建的数据库角色,,即db_securityadmin和db_owner。其他内建数据库角色,例如db_datareader,它授予对数据库里面所有对象的SELECT权限。虽然你可以用db_datareader角色授予SELECT权限,然后有选择地对个别用户或组拒绝SELECT权限,但使用这种方法时,你可能忘记为某些用户或者对象设置权限。一种更简单、更直接而且不容易出现错误的方法是为这些特殊的用户创建一个用户定义的角色,然后只把那些用户访问对象所需要的权限授予这个用户定义的角色。

六、简化安全管理
SQL Server验证的登录不仅能够方便地实现,而且与NT验证的登录相比,它更容易编写到应用程序里。但是,如果用户的数量超过25,或者服务器数量在一个以上,或者每个用户都可以访问一个以上的数据库,或者数据库有多个管理员,SQL Server验证的登录不容易管理。由于SQL Server没有显示用户有效权限的工具,要记忆每个用户具有哪些权限以及他们为何要得到这些权限就更加困难。即使对于一个数据库管理员还要担负其他责任的小型系统,简化安全策略也有助于减轻问题的复杂程度。因此,首选的方法应该是使用NT验证的登录,然后通过一些精心选择的全局组和数据库角色管理数据库访问。

下面是一些简化安全策略的经验规则:


用户通过SQL Server Users组获得服务器访问,通过DB_Name Users组获得数据库访问。
用户通过加入全局组获得权限,而全局组通过加入角色获得权限,角色直接拥有数据库里的权限。
需要多种权限的用户通过加入多个全局组的方式获得权限。
只要规划得恰当,你能够在域控制器上完成所有的访问和权限维护工作,使得服务器反映出你在域控制器上进行的各种设置调整。虽然实际应用中情况可能有所变化,但本文介绍的基本措施仍旧适用,它们能够帮助你构造出很容易管理的安全策略。

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
62#
 楼主| 发表于 2003-12-15 13:26 | 只看该作者
《jsp连接数据库大全》  
[ 作者:佚名    转贴自:本站原创    点击数:4    更新时间:2003-11-26    文章录入:cxmy ]

现在有好多初学jsp的网友经常会问数据库怎么连接啊,怎么老出错啊?所以我集中的在这写篇文章供大家参考,其实这种把数据库逻辑全部放在jsp里未必是好的做法,但是有利于初学者学习,所以我就这样做了,当大家学到一定程度的时候,可以考虑用MVC的模式开发。在练习这些代码的时候,你一定将jdbc的驱动程序放到服务器的类路径里,然后要在数据库里建一个表test,有两个字段比如为test1,test2,可以用下面SQL建
create table test(test1 varchar(20),test2 varchar(20)
然后向这个表写入一条测试纪录
那么现在开始我们的jsp和数据库之旅吧。
一、jsp连接Oracle8/8i/9i数据库(用thin模式)
testoracle.jsp如下:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%Class.forName("oracle.jdbc.driver.OracleDriver".newInstance();
String url="jdbcracle:thin:@localhost:1521rcl";
//orcl为你的数据库的SID
String user="scott";
String password="tiger";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {%>
您的第一个字段内容为:<%=rs.getString(1)%>
您的第二个字段内容为:<%=rs.getString(2)%>
<%}%>
<%out.print("数据库操作成功,恭喜你";%>
<%rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
二、jsp连接Sql Server7.0/2000数据库
testsqlserver.jsp如下:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver".newInstance();
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=pubs";
//pubs为你的数据库的
String user="sa";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {%>
您的第一个字段内容为:<%=rs.getString(1)%>
您的第二个字段内容为:<%=rs.getString(2)%>
<%}%>
<%out.print("数据库操作成功,恭喜你";%>
<%rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
三、jsp连接DB2数据库
testdb2.jsp如下:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%Class.forName("com.ibm.db2.jdbc.app.DB2Driver ".newInstance();
String url="jdbc:db2://localhost:5000/sample";
//sample为你的数据库名
String user="admin";
String password="";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {%>
您的第一个字段内容为:<%=rs.getString(1)%>
您的第二个字段内容为:<%=rs.getString(2)%>
<%}%>
<%out.print("数据库操作成功,恭喜你";%>
<%rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
四、jsp连接Informix数据库
testinformix.jsp如下:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%Class.forName("com.informix.jdbc.IfxDriver".newInstance();
String url =
"jdbc:informix-sqli://123.45.67.89:1533/testDB:INFORMIXSERVER=myserver;
user=testuser;password=testpassword";
//testDB为你的数据库名
Connection conn= DriverManager.getConnection(url);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {%>
您的第一个字段内容为:<%=rs.getString(1)%>
您的第二个字段内容为:<%=rs.getString(2)%>
<%}%>
<%out.print("数据库操作成功,恭喜你";%>
<%rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
五、jsp连接Sybase数据库
testmysql.jsp如下:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%Class.forName("com.sybase.jdbc.SybDriver".newInstance();
String url =" jdbc:sybase:Tds:localhost:5007/tsdata";
//tsdata为你的数据库名
Properties sysProps = System.getProperties();
SysProps.put("user","userid";
SysProps.put("password","user_password");
Connection conn= DriverManager.getConnection(url, SysProps);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {%>
您的第一个字段内容为:<%=rs.getString(1)%>
您的第二个字段内容为:<%=rs.getString(2)%>
<%}%>
<%out.print("数据库操作成功,恭喜你");%>
<%rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
六、jsp连接MySQL数据库
testmysql.jsp如下:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%Class.forName("org.gjt.mm.mysql.Driver").newInstance();
String url ="jdbc:mysql://localhost/softforum?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1"
//testDB为你的数据库名
Connection conn= DriverManager.getConnection(url);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {%>
您的第一个字段内容为:<%=rs.getString(1)%>
您的第二个字段内容为:<%=rs.getString(2)%>
<%}%>
<%out.print("数据库操作成功,恭喜你");%>
<%rs.close();
stmt.close();
conn.close();
%>
</body>
</html>
七、jsp连接PostgreSQL数据库
testmysql.jsp如下:
<%@ page contentType="text/html;charset=gb2312"%>
<%@ page import="java.sql.*"%>
<html>
<body>
<%Class.forName("org.postgresql.Driver").newInstance();
String url ="jdbcostgresql://localhost/soft"
//soft为你的数据库名
String user="myuser";
String password="mypassword";
Connection conn= DriverManager.getConnection(url,user,password);
Statement stmt=conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);
String sql="select * from test";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()) {%>
您的第一个字段内容为:<%=rs.getString(1)%>
您的第二个字段内容为:<%=rs.getString(2)%>
<%}%>
<%out.print("数据库操作成功,恭喜你");%>
<%rs.close();
stmt.close();
conn.close();
%>
</body>
</html>

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
63#
 楼主| 发表于 2003-12-15 13:27 | 只看该作者
使用JDBC创建数据库对象》  
[ 作者:佚名    转贴自:本站原创    点击数:3    更新时间:2003-11-26    文章录入:cxmy ]

James W. Cooper
IBM T.J. Watson 研究中心
1998 年 5 月

摘自:Java 1.1 中面向对象编程的原理

 

摘要
本文分析了Java DataBase Connectivity (JDBC),一个在 Java 中以面向对象的方法来连接数据库的技术。它是对 ODBC API 进行的一种面向对象的封装和重新设计,它易于学习和使用,并且它能够使您编写不依赖供应商的代码,用以查询和操纵数据库。JDBC 提供了一些相当低层的方法来存取数据库,同时也在相当高层提供了功能强大的对象来处理数据库。

什么是数据库?
数据库是以某种文件结构存储的一系列信息表,这种文件结构使您能够访问这些表、选择表中的列、对表进行排序以及根据各种标准选择行。数据库通常有多个 索引与这些表中的许多列相关联,所以我们能尽可能快地访问这些表。
在进行计算时,数据库比其它类型的结构更常用。您会发现在员工记录和薪资系统中数据库处于核心地位,在旅行计划系统中以及在产品生产和销售的整个过程中都可以发现数据库。

以员工记录为例,您可以设想一个含有员工姓名、地址、工资、扣税以及津贴等内容的表。让我们考虑一下这些内容可能如何组织在一起。您可以设想一个表包含员工姓名、地址和电话号码。您希望保存的其它信息可能包括工资、工资范围、上次加薪时间、下次加薪时间、员工业绩评定等内容。

这些内容是否应保存在一个表格中?几乎可以肯定不应该如此。不同类别的员工的工资范围可能没有区别;这样,您可以仅将员工类型储存在员工记录表中,而将工资范围储存在另一个表中,通过类型编号与这个表关联。考虑以下情况:


Key Lastname SalaryType SalaryType Min Max
1 Adams 2 1 30000 45000
2 Johnson 1 2 45000 60000
3 Smyth 3 3 60000 75000
4 Tully 1
5 Wolff 2

SalaryType 列中的数据引用第二个表。我们可以想象出许多种这样的表,如用于存储居住城市和每个城市的税值、健康计划扣除金额等的表。每个表都有一个主键列(如上面两个表中最左边的列)和若干数据列。在数据库中建立表格既是一门艺术,也是一门科学。这些表的结构由它们的 范式指出。我们通常说表属于第一、第二或第三范式,简称为 1NF、2NF 或 3NF。

第一范式:表中的每个表元应该只有一个值(永远不可能是一个数组)。(1NF)

第二范式:满足 1NF,并且每一个副键列完全依赖于主键列。这表示主键和该行中的剩余表元之间是 1 对 1 的关系。(2NF)

第三范式:满足 2NF,并且所有副键列是互相独立的。任何一个数据列中包含的值都不能从其他列的数据计算得到。(3NF)

现在,几乎所有的数据库都是基于“第三范式 (3NF)”创建的。这意味着通常都有相当多的表,每个表中的信息列都相对较少。

从数据库中获取数据
假设我们希望生成一个包含员工及其工资范围的表,在我们设计的一个练习中将使用这个表。这个表格不是直接存在在数据库中,但可以通过向数据库发出一个查询来构建它。我们希望得到如下所示的一个表:

Name Min Max
Adams $45,000.00 $60,000.00
Johnson $30,000.00 $45,000.00
Smyth $60,000.00 $75,000.00
Tully $30,000.00 $45,000.00
Wolff $45,000.00 $60,000.00

或者,按照工资递增的顺序排序


Name Min Max
Tully $30,000.00 $45,000.00
Johnson $30,000.00 $45,000.00
Wolff $45,000.00 $60,000.00
Adams $45,000.00 $60,000.00
Smyth $60,000.00 $75,000.00

我们发现,获得这些表的查询形式如下所示

SELECT DISTINCTROW Employees.Name, SalaryRanges.Min,
SalaryRanges.Max FROM Employees INNER JOIN SalaryRanges ON Employees.SalaryKey = SalaryRanges.SalaryKey
ORDER BY SalaryRanges.Min;


这种语言称为结构化查询语言,即 SQL(一般读作 "sequel"),而且它是几乎目前所有数据库都可以使用的一种语言。这几年已颁布了若于 SQL 标准,而且大多数 PC 数据库支持大部分 ANSI 标准。SQL-92 标准被认为是一种基础标准,而且已更新多次。然而,没有一种数据库可以完美地支持后来的 SQL 版本,而且大多数数据库都提供了多种 SQL 扩展,以支持他们数据库独有的性能。
数据库的种类
由于 PC 已成为主要的办公工具,因此,已开发出在 PC 上的大量流行的数据库,这些数据库都是可以自管理的。它们包括初级数据库,如 Microsoft Works,还包括更为复杂的数据库,如 Approach、 dBase、Borland Paradox、Microsoft Access 和 FoxBase。
另一类 PC 数据库包括那些可由许多 PC 客户机通过服务器访问的数据库。其中包括 IBM DB/2、Microsoft SQL Server、 Oracle、Sybase、SQLBase 和 XDB。所有这些数据库产品都支持多种相对类似的 SQL 方言,因此,所有数据库最初看起来好象可以互换。当然,它们 不能互换的原因是每种数据库都有不同的性能特征,而且每一种都有不同的用户界面和编程接口。您可能会想,既然它们都支持 SQL,对它们进行的编程也应该相似,但这是绝对错误的,因为每种数据库都使用其自己方式接收 SQL 查询,并使用其自己的方式返回结果。这就自然引出了一种新一代的标准:ODBC

ODBC
如果我们能够以某种方式编写不依赖于特定厂商的数据库的代码,并且能够不改变自己的调用程序即可从这些数据库中得到相同的结果,那将是一件很好的事。如果我们可以仅为所有这些数据库编写一些封装,使它们具有相似的编程接口,这种对数据库编程独立于供应商的特性将很容易实现。
Microsoft 于 1992 年首先尝试了这一技巧,该公司发布了一个规范,称为对象数据库连接性。这被认为是在 Windows 环境下连接所有数据库的答案。与所有软件的第一个版本相同,它也经历了一些发展的困扰,在 1994 年推出了另一个版本,该版本运行速度更快,而且更为稳定。它也是第一个 32 位的版本。另外,ODBC 开始向 Windows 之外的其它平台发展,到目前为止,它在 PC 和工作站领域已十分普遍。几乎每个主要的数据库厂商都提供 ODBC 驱动程序。

然而,ODBC 并不是我们最初想象的灵丹妙药。许多数据库厂商都将 ODBC 作为其标准接口之外的“备选接口”,而且对 ODBC 的编程微不足道。与其它 Windows 编程一样,它包括句柄、指针和选项,使其难以掌握。最后一点,ODBC 不是中立的标准。它由 Microsoft 公司开发,并由该公司不断改进,而微软同时也推出了我们所有人所使用的极具竞争性的软件平台,这使得ODBC的未来难以预测。

什么是 JDBC?
JDBC 是一组首字母缩写,曾经代表“Java DataBase Connectivity”,但现在它本身已成为一个商标符号。它是对 ODBC API 进行的一种面向对象的封装和重新设计,它易于学习和使用,并且它真正能够使您编写不依赖厂商的代码,用以查询和操纵数据库。尽管它与所有 Java API 一样,都是面向对象的,但它并不是很高级别的对象集,在本章的剩余部分,我们将提出更高级别的方法。
除 Microsoft 之外,多数厂商都采用了 JDBC,并为其数据库提供了 JDBC 驱动程序;这使您可轻松地真正编写几乎完全不依赖数据库的代码。另外,JavaSoft 和 Intersolv 已开发了一种称为 JDBC-ODBC Bridge 的产品,可使您连接还没有直接的 JDBC 驱动程序的数据库。支持 JDBC 的所有数据库必须至少可以支持 SQL-92 标准。这在很大程度上实现了跨数据库和平台的可移植性。

安装和使用 JDBC
JDBC 的类都被归到 java.sql 包中,在安装 Java JDK 1.1 或更高版本时会自动安装。然而,如果您想使用 JDBC-ODBC 桥,还必须安装两个另外的程序包。首先,如果您使用 Windows 95,则必须将您的 ODBC 驱动程序升级为 32 位驱动程序,您可从 Microsoft 的网站下载。这个驱动程序在 Microsoft 的网站上很难找到;请搜索 DataAcc.exe 并进行下载和安装。
JDBC-ODBC 驱动程序可从 Sun 的 Java 网站 (http://java.sun.com) 轻松地找到并下载。在您扩充并安装了这个驱动程序后,必须执行下列步骤:

将 \jdbc-odbc\classes; 路径添加到您的 PATH 环境变量中。
将 \jdbc-odbc\classes; 路径添加到您的 CLASSPATH 环境变量中。
在 Windows 95 环境下,将它们放入 autoexec.bat 文件中,重新引导,以使所有设置生效。
在 Windows NT 环境下,将它们添加到“控制面板”中“系统”对象的“环境”选项卡中,退出并重新登录,以使其生效。
JDBC 驱动程序的类型
Java 程序连接数据库的方法实际上有四种:
JDBC-ODBC 桥和 ODBC 驱动程序 -- 在这种方式下,这是一个本地解决方案,因为 ODBC 驱动程序和桥代码必须出现在用户的每台机器中。从根本上说这是一个临时解决方案。

本机代码和 Java 驱动程序 -- 它用另一个本地解决方案(该平台上的 Java 可调用的本机代码)取代 ODBC 和 JDBC-ODBC 桥。

JDBC 网络的纯 Java 驱动程序 -- 由 Java 驱动程序翻译的 JDBC 形成传送给服务器的独立协议。然后,服务器可连接任何数量的数据库。这种方法使您可能从客户机 Applet 中调用服务器,并将结果返回到您的 Applet。在这种情况下,中间件软件提供商可提供服务器。

本机协议 Java 驱动程序 -- Java 驱动程序直接转换为该数据库的协议并进行调用。这种方法也可以通过网络使用,而且可以在 Web 浏览器的 Applet 中显示结果。在这种情况下,每个数据库厂商将提供驱动程序。
如果您希望编写代码来处理 PC 客户机数据库,如 dBase、Foxbase 或 Access,则您可能会使用第一种方法,并且拥有用户机器上的所有代码。更大的客户机-服务器数据库产品(如 IBM 的 DB2)已提供了第 3 级别的驱动程序。
两层模型和三层模型
当数据库和查询它的应用程序在同一台机器上,而且没有服务器代码的干预时,我们将生成的程序称为 两层模型。一层是应用程序,而另一层是数据库。在 JDBC-ODBC 桥系统中通常是这种情况。
当一个应用程序或 applet 调用服务器,服务器再去调用数据库时,我们称其为三层模型。当您调用称为“服务器”的程序时通常是这种情况。

编写 JDBC 代码访问数据库
现在,我们将开始看一下如何编写 Java 程序来访问数据库。我们要使用的数据库是一个称为 groceries.mdb 的 Microsoft Access 数据库。此数据库中的数据由三个本地杂货店中一些常见商品的价格组成。食品表如下所示:

FoodKey FoodName
1 Apples
2 Oranges
3 Hamburger
4 Butter
5 Milk
6 Cola
7 Green beans

杂货店表如下所示:


StoreKey StoreName
1 Stop and Shop
2 Village Market
3 Waldbaum′s

杂货店定价表仅由这三个表格中的键值和价格组成:


FSKey StoreKey FoodKey Price
1 1 1 $0.27
2 2 1 $0.29
3 3 1 $0.33
4 1 2 $0.36
5 2 2 $0.29
6 3 2 $0.47
7 1 3 $1.98
8 2 3 $2.45
9 3 3 $2.29
10 1 4 $2.39
11 2 4 $2.99
12 3 4 $3.29
13 1 5 $1.98
14 2 5 $1.79
15 3 5 $1.89
16 1 6 $2.65
17 2 6 $3.79
18 3 6 $2.99
19 1 7 $2.29
20 2 7 $2.19
21 3 7 $1.99


用 ODBC 注册您的数据库
在 Windows 95 或 NT 环境下访问 ODBC 数据库之前,必须使用控制面板中的ODBC 驱动程序对它进行注册。在 Windows 95 环境下,就是“控制面板”程序中的 ODBC 图标。在 Windows NT 环境下,您会在“开始”菜单中找到此程序。(如果找不到,您需要安装上述的 ODBC 驱动程序,即 WX1350.exe)。
双击 ODBC 图标,然后单击“添加”,如图 1 所示。然后选择数据库驱动程序(此处使用 Microsoft Access),然后单击“确定”。在“数据源名”和“描述”中分别键入数据源名称 (Groceries) 和数据库说明 (Grocery prices)(这两项都不需要和文件名相关),然后单击“选取”,找到数据库,并选择该数据库。找到该数据库后,屏幕将如图 2 所示。单击“确定”,然后单击“关闭”来关闭面板。


图 1:ODBC 控制面板设置屏幕。


图 2:在 ODBC 控制面板中选择数据库和说明。



连接数据库
所有与数据库有关的对象和方法都在 java.sql 包中,因此在使用 JDBC 的程序中必须加入 "import java.sql.* "。 JDBC 要连接 ODBC 数据库,您必须首先加载 JDBC-ODBC 桥驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver";

该语句加载驱动程序,并创建该类的一个实例。然后,要连接一个特定的数据库,您必须创建 Connect 类的一个实例,并使用 URL 语法连接数据库。
String url = "jdbcdbc:Grocery prices";
Connection con = DriverManager.getConnection(url);

请注意,您使用的数据库名是您在 ODBC 设置面板中输入的“数据源”名称。
URL 语法可能因数据库类型的不同而变化极大。

jdbc:subprotocol:subname

第一组字符代表连接协议,并且始终是 jdbc。还可能有一个子协议,在此处,子协议被指定为 odbc。它规定了一类数据库的连通性机制。如果您要连接其它机器上的数据库服务器,可能也要指定该机器和一个子目录:
jdbc:bark//doggie/elliott

最后,您可能要指定用户名和口令,作为连接字符串的一部分:
jdbc:bark//doggie/elliot;UID=GoodDog;PWD=woof

访问数据库
一旦连接到数据库,就可以请求表名以及表列的名称和内容等信息,而且您可以运行 SQL 语句来查询数据库或者添加或修改其内容。可用来从数据库中获取信息的对象有:

DatabaseMetaData 有关整个数据库的信息:表名、表的索引、数据库产品的名称和版本、数据库支持的操作。
ResultSet 关于某个表的信息或一个查询的结果。您必须逐行访问数据行,但是您可以任何顺序访问列。
ResultSetMetaData 有关 ResultSet 中列的名称和类型的信息。

尽管每个对象都有大量的方法让您获得数据库元素的极为详细的信息,但在每个对象中都有几种主要的方法使您可获得数据的最重要信息。然而,如果您希望看到比此处更多的信息,建议您学习文档以获得其余方法的说明。

ResultSet
ResultSet 对象是 JDBC 中最重要的单个对象。从本质上讲,它是对一个一般宽度和未知长度的表的一种抽象。几乎所有的方法和查询都将数据作为 ResultSet 返回。ResultSet 包含任意数量的命名列,您可以按名称访问这些列。它还包含一个或多个行,您可以按顺序自上而下逐一访问。在您使用 ResultSet 之前,必须查询它包含多少个列。此信息存储在 ResultSetMetaData 对象中。
 

//从元数据中获得列数
ResultSetMetaData rsmd;
rsmd = results.getMetaData();
numCols = rsmd.getColumnCount();


当您获得一个 ResultSet 时,它正好指向第一行之前的位置。您可以使用 next() 方法得到其他每一行,当没有更多行时,该方法会返回 false。由于从数据库中获取数据可能会导致错误,您必须始终将结果集处理语句包括在一个 try 块中。

try
{
rsmd = results.getMetaData();
numCols = rsmd.getColumnCount();
boolean more = results.next();
while (more)
{
for (I = 1; I <= numCols; i++)
System.out.print(results.getString(i)+" ";
System.out.println();
more = results.next();
}
results.close();
}
catch(Exception e)
{System.out.println(e.getMessage());}

您可以多种形式获取 ResultSet 中的数据,这取决于每个列中存储的数据类型。另外,您可以按列序号或列名获取列的内容。请注意,列序号从 1 开始,而不是从 0 开始。ResultSet 对象的一些最常用方法如下所示。

getInt(int);

将序号为 int 的列的内容作为整数返回。
getInt(String);

将名称为 String 的列的内容作为整数返回。
getFloat(int);

将序号为 int 的列的内容作为一个 float 型数返回。
getFloat(String);

将名称为 String 的列的内容作为 float 型数返回。
getDate(int);

将序号为 int 的列的内容作为日期返回。
getDate(String);

将名称为 String 的列的内容作为日期返回。
next();

将行指针移到下一行。如果没有剩余行,则返回 false。
close();

关闭结果集。
getMetaData();

返回 ResultSetMetaData 对象。

ResultSetMetaData
您使用 getMetaData() 方法从 ResultSet 中获取 ResultSetMetaData 对象。您可以使用此对象获得列的数目和类型以及每一列的名称。

getColumnCount();

返回 ResultSet 中的列数。
getColumnName(int);

返回列序号为 int 的列名。
getColumnLabel(int);

返回此列暗含的标签。
isCurrency(int);

如果此列包含带有货币单位的一个数字,则返回 true。
isReadOnly(int);

如果此列为只读,则返回 true。
isAutoIncrement(int);

如果此列自动递增,则返回 true。这类列通常为键,而且始终是只读的。
getColumnType(int);

返回此列的 SQL 数据类型。这些数据类型包括
BIGINT
BINARY
BIT
CHAR
DATE
DECIMAL
DOUBLE
FLOAT
INTEGER
LONGVARBINARY
LONGVARCHAR
NULL
NUMERIC
OTHER
REAL
SMALLINT
TIME
TIMESTAMP
TINYINT
VARBINARY
VARCHAR

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
64#
 楼主| 发表于 2003-12-15 13:27 | 只看该作者
DatabaseMetaData
DatabaseMetaData 对象可为您提供整个数据库的信息。您主要用它获取数据库中表的名称,以及表中列的名称。由于不同的数据库支持不同的 SQL 变体,因此,也有多种方法查询数据库支持哪些 SQL 方法。

getCatalogs()

返回该数据库中的信息目录列表。使用 JDBC-ODBC Bridge 驱动程序,您可以获得用 ODBC 注册的数据库列表。这很少用于 JDBC-ODBC 数据库。
getTables(catalog, schema, tableNames, columnNames) 返回表名与 tableNames 相符而且列名与 columnNames 相符的所有表的说明。
getColumns(catalog, schema, tableNames, columnNames) 返回表名与 tableNames 相符而且列名与 columnNames 相符的所有表列说明。
getURL();

获得您所连接的 URL 名称。
getDriverName();

获得您所连接的数据库驱动程序的名称。

获取有关表的信息
您可以使用 DataBaseMetaData 的 getTables() 方法来获取数据库中表的信息。这个方法有如下 4 个 String 参数:
results =
dma.getTables(catalog, schema, tablemask, types[]);

其中参数的意义是:

catalog

要在其中查找表名的目录名。对于 JDBC-ODBC 数据库以及许多其他数据库而言,可将其设置为 null。这些数据库的目录项实际上是它在文件系统中的绝对路径名称。
schema

要包括的数据库“方案”。许多数据库不支持方案,而对另一些数据库而言,它代表数据库所有者的用户名。一般将它设置为 null。
tablemask

一个掩码,用来描述您要检索的表的名称。如果您希望检索所有表名,则将其设为通配符 %。请注意,SQL 中的通配符是 % 符号,而不是一般 PC 用户的 * 符号。
types[]

这是描述您要检索的表的类型的 String 数组。数据库中通常包括许多用于内部处理的表,而对作为用户的您没什么价值。如果它是空值,则您会得到所有这些表。如果您将其设为包含字符串“TABLES”的单元素数组,您将仅获得对用户有用的表格。

用于从数据库中获取表名的简单代码相当于获取 DatabaseMetaData 对象,并从其中检索表名:


con = DriverManager.getConnection(url);
//获取数据库的元数据
dma =con.getMetaData();
//将数据库中的表的名称转储出来
String[] types = new String[1];
types[0] = "TABLES"; //设置查询类型
//请注意通配符是 % 符号(而不是“*”)
results = dma.getTables(null, null, "%", types);

然后,我们可以打印出表名,正如我们上面所做的那样:

boolean more = results.next();
while (more)
{
for (I = 1; I <= numCols; i++)
System.out.print(results.getString(i)+" ";
System.out.println();
more = results.next();
}

如前文所述,将所有代码包括在 try 块中。
执行 SQL 查询
我们已经理解了 JDBC 的基本对象,现在就可以执行 SQL 查询了。查询是作为 Statement 对象的方法执行的,您很容易从 Connection 对象获得Statement对象:
String query = "SELECT FoodName FROM Food;";
ResultSet results;
try
{
Statement stmt = con.createStatement();
results = stmt.executeQuery(query);
}
catch (Exception e)
{System.out.println("query exception";}

请注意,这个简单的查询返回 Food 表中的整个 FoodName 列。您使用像这样的简单查询获取整个列的内容。请注意,查询的查询本身是一个 ResultSet,您可以用我们上面刚讨论过的方法对它进行处理。
打印 ResultSet
因为我们总是要从 ResultSets 中打印数据,我们可以设计一种简单的方法,将整个 ResultSet 转储出来,包括表名称元数据。该子程序如下所示:
private void dumpResults(String head)
{
//这是打印列标头和每列的内容的
//通用方法
System.out.println(head);
try
{
//从元数据中获取列数
rsmd = results.getMetaData();
numCols = rsmd.getColumnCount();
//打印列名
for (I = 1; i<= numCols; i++)
System.out.print(rsmd.getColumnName(i)+" ";
System.out.println();
//打印列内容
boolean more = results.next();
while (more)
{
for (I = 1; I <= numCols; i++)
System.out.print(results.getString(i)+" ";
System.out.println();
more = results.next();
}
}
catch(Exception e)
{System.out.println(e.getMessage());}
}


一个简单的 JDBC 程序
我们已经学习了 JDBC 的所有基本功能,现在我们可以编写一个简单的程序,该程序打开数据库,打印它的表名以及某一表列的内容,然后对该数据库执行查询。此程序如下所示:
import java.net.URL;
import java.sql.*;
import java.util.*;
class JdbcOdbc_test
{
ResultSet results;
ResultSetMetaData rsmd;
DatabaseMetaData dma;
Connection con;
int numCols, I;
//--
public JdbcOdbc_test()
{
String url = "jdbcdbc:Grocery prices";
String query = "SELECT DISTINCTROW FoodName FROM Food " + "WHERE (FoodName like ′C%′);";
try
{
//加载 JDBC-ODBC 桥驱动程序
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver";
//连接数据库
con = DriverManager.getConnection(url);
//获取数据库的元数据
dma =con.getMetaData();
System.out.println("Connected to:"+dma.getURL());
System.out.println("Driver "+dma.getDriverName());
//将数据库中的表的名称转储出来
String[] types = new String[1];
types[0] = "TABLES";
//请注意通配符是 % 符号(而不是“*”)
results = dma.getTables(null, null, "%", types);
dumpResults("--Tables--";
results.close();
}
catch (Exception e)
{System.out.println(e);}
//获取表列的名称
System.out.println("--Column Names--";
try {
results =
dma.getColumns(null, null, "FoodPrice", null);
ResultSetMetaData rsmd = results.getMetaData();
int numCols = rsmd.getColumnCount();
while (results.next() )
String cname = results.getString("COLUMN_NAME";
System.out.print(cname + " ";
System.out.println();
results.close();
}
catch (Exception e)
{System.out.println(e);}
//列出一个列的内容 -- 这是一个查询
try {
Statement stmt = con.createStatement();
results =
stmt.executeQuery("SELECT FOODNAME FROM FOOD;";
}
catch (Exception e)
{System.out.println("query exception";}
dumpResults("--Contents of FoodName column--");
//尝试实际的 SQL 语句
try
{
Statement stmt = con.createStatement();
results = stmt.executeQuery(query);
}
catch (Exception e)
{System.out.println("query exception");}
dumpResults("--Results of Query--");
}

该程序打印出的结果如下所示:
C:\Projects\objectJava\chapter19>java JdbcOdbc_test
Connected to:jdbcdbc:Grocery prices
Driver JDBC-ODBC Bridge (ODBCJT32.DLL)
--Tables--
TABLE_QUALIFIER TABLE_OWNER TABLE_NAME TABLE_TYPE REMARKS
groceries null Food TABLE null
groceries null FoodPrice TABLE null
groceries null Stores TABLE null
--Column Names--
FSKey StoreKey FoodKey Price
--Contents of FoodName column--
FOODNAME
Apples
Oranges
Hamburger
Butter
Milk
Cola
Green beans
--Results of Query--
FoodName
Cola

构建更高级别的 JDBC 对象
从上面的例子可以明显看出,如果可以将我们使用过的一些方法封装在几个更高级别对象中,那将非常有帮助,我们不仅可以封装 try 程序块,而且可以更简单地访问 ResultSet 方法。
在这一部分中,我们将构建一个新的 resultSet 对象,该对象封装了 JDBC ResultSet 对象,并以 String 数组的形式返回一行数据。我们发现您始终需要从 ResultSetMetaData 对象中获取列的序号和名称,因此,创建一个封装元数据的新对象就非常合理。

另外,我们经常需要按名称或整数索引提取某行的元素,如果不必总是将这些访问语句包括 try 块中,那将大有帮助。最后一点,如果我们需要整行的内容,则更方便的做法是将整行以String 数组形式返回。在下面所示的 resultSet 对象中,我们致力于实现这些目标:

class resultSet
{
//这个类是 JDBC ResultSet 对象的更高级抽象
ResultSet rs;
ResultSetMetaData rsmd;
int numCols;
public resultSet(ResultSet rset)
{
rs = rset;
try
{
//同时获取元数据和列数
rsmd = rs.getMetaData();
numCols = rsmd.getColumnCount();
}
catch (Exception e)
{System.out.println("resultset error"
+e.getMessage());}
}
//--
public String[] getMetaData()
{
//返回包含所有列名或其他元数据的
//一个数组
String md[] = new String[numCols];
try
{
for (int i=1; i<= numCols; i++)
md[i-1] = rsmd.getColumnName(i);
}
catch (Exception e)
{System.out.println("meta data error"+
e.getMessage());}
return md;
}
//--
public boolean hasMoreElements()
{
try{
return rs.next();
}
catch(Exception e){return false;}
}
//--
public String[] nextElement()
{
//将行的内容复制到字符串数组中
String[] row = new String[numCols];
try
{
for (int I = 1; I <= numCols; i++)
row[i-1] = rs.getString(i);
}
catch (Exception e)
{System.out.println("next element error"+
e.getMessage());}
return row;
}
//--
public String getColumnValue(String columnName)
{
String res = "";
try
{
res = rs.getString(columnName);
}
catch (Exception e)
{System.out.println("Column value error:"+
columnName+e.getMessage());}
return res;
}
//--
public String getColumnValue(int i)
{
String res = "";
try
{
res = rs.getString(i);
}
catch (Exception e)
{System.out.println("Column value error:"+
columnName+e.getMessage());}
return res;
}
//--
public void finalize()
{
try{rs.close();}
catch (Exception e)
{System.out.println(e.getMessage());}
}
}

通过简单使用 new 操作符就地创建一个 ResultSet 对象,我们很容易将任何 ResultSet 对象封装在此类中:
ResultSet results = .. //按通常的方法获得ResultsSet
//利用它创建一个更有用的对象
resultSet rs = new resultSet(results);

并很容易在任何 JDBC 程序中使用这个对象。
构建一个 Database 对象
我们沿 00 链向上移的另一部分努力是创建一个 Database 对象,它将封装下列对象的行为:Connection、Statement 和 DatabaseMetaData 对象, 以及我们刚刚构建的 SQL 查询和 resultSet。我们的 Database 对象允许我们创建连接、获取表名、在数据库中移动以及更简单地获得行和列的值。请注意, Execute 方法返回一个 resultSet 对象,您可以直接对它进行操作。
class Database
{
//这是一个将 JDBC 数据库的所有功能封装在单个对象中的类
Connection con;
resultSet results;
ResultSetMetaData rsmd;
DatabaseMetaData dma;
String catalog;
String types[];
public Database(String driver)
{
types = new String[1];
types[0] = "TABLES"; //初始化类型
try{Class.forName(driver);} //加载 JDBC-ODBC 桥驱动程序
catch (Exception e)
{System.out.println(e.getMessage());}
}
//--
public void Open(String url, String cat)
{
catalog = cat;
try {con = DriverManager.getConnection(url);
dma =con.getMetaData(); //获取元数据
}
catch (Exception e)
{System.out.println(e.getMessage());}
}
//--
public String[] getTableNames()
{
String[] tbnames = null;
Vector tname = new Vector();
//将表名添加到一个 Vector 中,
//因为我们不知道有多少个表
try {
results =
new resultSet(dma.getTables(catalog, null,
"%", types));

while (results.hasMoreElements())
tname.addElement(results.getColumnValue("TABLE_NAME"));

}
catch (Exception e) {System.out.println(e);}
//将表名复制到一个 String 数组中
tbnames = new String[tname.size()];
for (int i=0; i< tname.size(); i++)
tbnames = (String)tname.elementAt(i);
return tbnames;
}
//--
public String[] getTableMetaData()
{
// 返回表类型的信息
results = null;
try{
results =
new resultSet(dma.getTables(catalog, null,
"%", types));
}
catch (Exception e)
{System.out.println(e.getMessage());}
return results.getMetaData();
}
//--
public String[] getColumnMetaData(String tablename)
{
//返回一个列的数据
results = null;
try {
results =
new resultSet(dma.getColumns(catalog, null,
tablename, null));
}
catch (Exception e)
{System.out.println(e.getMessage());}
return results.getMetaData();
}
//--
public String[] getColumnNames(String table)
{
//返回一个列名数组
String[] tbnames = null;
Vector tname = new Vector();
try {
results =
new resultSet(dma.getColumns(catalog, null,
table, null));
while (results.hasMoreElements() )
tname.addElement(results.getColumnValue("COLUMN_NAME"));
}
catch (Exception e) {System.out.println(e);}
tbnames = new String[tname.size()];
for (int i=0; i< tname.size(); i++)
tbnames = (String)tname.elementAt(i);
return tbnames;
}
//--
public String getColumnValue(String table,
String columnName)
{
//返回给定列的值 String res = null;
try
{
if (table.length()>0)
results =
Execute("Select " + columnName +
" from " + table +
" order by "+columnName);
if (results.hasMoreElements())
res = results.getColumnValue(columnName);
}
catch (Exception e)
{System.out.println("Column value error" +
columnName+ e.getMessage());}
return res;
}
//--
public String getNextValue(String columnName)
{
// 使用存储的 resultSet
//返回该列的下一个值
String res = "";
try
{
if (results.hasMoreElements())
res = results.getColumnValue(columnName);
}
catch (Exception e)
{System.out.println("next value error"+
columnName+ e.getMessage());}
return res;
}
//--
public resultSet Execute(String sql)
{
//对此数据库执行一个 SQL 查询
results = null;
try
{
Statement stmt = con.createStatement();
results = new resultSet(stmt.executeQuery(sql));
}
catch (Exception e)
{System.out.println("execute error"+
e.getMessage());}
return results;
}
}

一个可视化的数据库程序
为了对我们本章学习的内容进行总结,我们编写一个简单的 GUI 程序,它可以显示数据库的表名、列名和列内容。我们还将包括一个文本区域,您可以在其中键入一个要对数据库执行的 SQL 查询。在 Companion CD-ROM 上的 \chapter20 子目录中,可以找到本程序(称为 dbFrame.java)所使用的 resultSet 和 Database 类。程序的显示界面如图 3 所示。


图 3:用来显示用 JDBC 连接的数据库中的数据的 dbFrame.java 程序。

在本程序中,默认数据库 (groceries.mdb) 的表名显示在左侧的栏中。当您单击其中一个表名时,列名就会显示在中间的栏中。最后,当您单击中间栏中的某一行时,该行的内容就会显示在右侧的栏中。

本程序的关键只是接收列表选择,然后清除并填充正确的列表框:

public void itemStateChanged(ItemEvent e)
{
Object obj = e.getSource();
if (obj == Tables) //放入列名
showColumns();
if (obj == Columns) //放入列的内容
showData();
}
//--
private void loadList(List list, String[] s)
{
//清除并填充指定的列表框
list.removeAll();
for (int i=0; i< s.length; i++)
list.add(s);
}
//--
private void showColumns()
{
//显示列名
String cnames[] =
db.getColumnNames(Tables.getSelectedItem());
loadList(Columns, cnames);
}
//--
private void showData()
{
String colname = Columns.getSelectedItem();
String colval =
db.getColumnValue(Tables.getSelectedItem(),
colname);
Data.setVisible(false);
Data.removeAll();
Data.setVisible(true);
colval =
db.getNextValue(Columns.getSelectedItem());
while (colval.length()>0)
{
Data.add(colval);
colval =
db.getNextValue(Columns.getSelectedItem());
}
}

执行查询
显示画面底部的文本区域使您可键入所需的任何 SQL 查询。演示程序中构建的一个查询如下所示:
String queryText =
"SELECT DISTINCTROW FoodName, StoreName, Price "+
"FROM (Food INNER JOIN FoodPrice ON "+
"Food.FoodKey = FoodPrice.FoodKey) " +
"INNER JOIN Stores ON "+
"FoodPrice.StoreKey = Stores.StoreKey "+
"WHERE (((Food.FoodName)=\′Oranges\′)) "+
" ORDER BY FoodPrice.Price;";

此查询简单地列出每个杂货店的桔子价格。
当您单击 Run Query 按钮时,它将执行此查询,并将 resultSet 对象传送给一个对话框进行显示:

public void actionPerformed(ActionEvent e)
{
Object obj = e.getSource();
if (obj == Quit)
System.exit(0);
if (obj == Search)
clickedSearch();
}
//--
private void clickedSearch()
{
resultSet rs = db.Execute(query.getText());
String cnames[] = rs.getMetaData();

queryDialog q = new queryDialog(this, rs);
q.show();
}

查询结果对话框
查询对话框获得 resultSet 对象,并将每一行放入一个 String 数组中,然后将这些 String 数组放入一个 Vector 中,这样就可以在 paint() 子程序运行期间快速访问这些行。
private void makeTables()
{
//将每一行放入一个 String 数组中,并将
//这些字符串数组全部放入一个 Vector 中
tables = new Vector();
String t[] = results.getMetaData();
tables.addElement( t);
while (results.hasMoreElements())
tables.addElement(results.nextElement());
}

我们通过 Graphics 的 drawString() 方法将数据绘制在一个 Panel 中。就像在 Printer 对象中一样,我们必须自己跟踪 x 和 y 的位置。
public void paint(Graphics g)
{
String s[];
int x=0;
//计算字体的高度
int y =g.getFontMetrics().getHeight();
//估算列的高度
int deltaX = (int)1.5f*
(g.getFontMetrics().stringWidth("wwwwwwwwwwwwww"));
//遍历表矢量
for (int i=0; i< tables.size(); i++)
{
s = (String[])tables.elementAt(i);
//绘制字符串数组中的每一行
for (int j =0; j< s.length; j++)
{
String st= s[j];
g.drawString(st, x, y);
x += deltaX; //移到下一列
}
x = 0; //开始一个新行
y += g.getFontMetrics().getHeight();
//列标签与列数据之间的额外空间
if (I == 0) y += g.getFontMetrics().getHeight();
}
}

内建查询的 queryDialog 如图 4 所示。


图 4:dbFrame 程序中 显示的 queryDialog,其中显示的是默认查询的结果。

示例文件
groceries.zip
dbFrame.zip
jdbc-odbc Bridge
小结
在本文中,我们讨论了数据库以及检验数据库并对数据库执行查询的方法。我们已经看到,JDBC 提供了一种与平台和数据库无关的、面向对象的方法来访问这些数据,我们还学习了 JDBC 的主要对象:ResultSet、ResultSetMetaData 和 DatabaseMetaData。在用这些对象编写了一个简单的程序之后,我们设计了更高级别的 resultSet 和 Database 对象,我们用它们构建了一个简单的可视化界面来显示数据库信息。
如果您熟悉数据库的强大功能,就会认识到 SQL 语言可使您执行比我们此处所述操作更强大的任务。例如,您可以创建新表、添加、更改或删除表的行、列或单个表元。使用 JDBC,所有这一切都变得通用和易于处理。

如果您使用的是特定平台的数据库驱动程序,如 JDBC-ODBC Bridge,则您在编写应用程序时会受到限制,因为 applet 不能连接在另一台计算机上运行的这个桥。其他客户机-服务器数据库,如 IBM 的 DB2,允许您使用 applet 中的 JDBC 与其连接。

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
65#
 楼主| 发表于 2003-12-15 13:28 | 只看该作者
数据库的数据挖掘概述(一)》  
[ 作者:佚名    转贴自:本站原创    点击数:2    更新时间:2003-11-26    文章录入:cxmy ]

随着数据库技术的不断发展及数据库管理系统的广泛应用,数据库中存储的数据量急剧增大,在大量的数据背后隐藏着许多重要的信息,如果能把这些信息从数据库中抽取出来,将为公司创造很多潜在的利润,而这种从海量数据库中挖掘信息的技术,就称之为数据挖掘。
数据挖掘工具能够对将来的趋势和行为进行预测,从而很好地支持人们的决策,比如,经过对公司整个数据库系统的分析,数据挖掘工具可以回答诸如“哪个客户对我们公司的邮件推销活动最有可能作出反应,为什么”等类似的问题。有些数据挖掘工具还能够解决一些很消耗人工时间的传统问题,因为它们能够快速地浏览整个数据库,找出一些专家们不易察觉的极有用的信息。

下文将对数据挖掘的基本技术作一个简单的介绍。

数据挖掘的基础

数据挖掘技术是人们长期对数据库技术进行研究和开发的结果。起初各种商业数据是存储在计算机的数据库中的,然后发展到可对数据库进行查询和访问,进而发展到对数据库的即时遍历。数据挖掘使数据库技术进入了一个更高级的阶
段,它不仅能对过去的数据进行查询和遍历,并且能够找出过去数据之间的潜在联系,从而促进信息的传递。现在数据挖掘技术在商业应用中已经可以马上投入使用,因为对这种技术进行支持的三种基础技术已经发展成熟,他们是:

海量数据搜集
强大的多处理器计算机
数据挖掘算法

商业数据库现在正在以一个空前的速度增长,并且数据仓库正在广泛地应用于各种行业;对计算机硬件性能越来越高的要求,也可以用现在已经成熟的并行多处理机的技术来满足;另外数据挖掘算法经过了这10多年的发展也已经成为一种成熟,稳定,且易于理解和操作的技术。

从商业数据到商业信息的进化过程中,每一步前进都是建立在上一步的基础上的。见下表。表中我们可以看到,第四步进化是革命性的,因为从用户的角度来看,这一阶段的数据库技术已经可以快速地回答商业上的很多问题了。

进化阶段 商业问题 支持技术 产品厂家 产品特点 数据搜集
(60年代) “过去五年中我的总收入是多少?” 计算机、磁带和磁盘 IBM, CDC 提供历史性的、静态的数据信息 数据访问
(80年代) “在新英格兰的分部去年三月的销售额是多少?” 关系数据库(RDBMS),结构化查询语言(SQL),ODBC Oracle、Sybase、Informix、IBM、Microsoft 在记录级提供历史性的、动态数据信息 数据仓库;决策支持
(90年代) “在新英格兰的分部去年三月的销售额是多少?波士顿据此可得出什么结论?” 联机分析处理(OLAP)、多维数据库、数据仓库 Pilot、Comshare、Arbor、Cognos、Microstrategy 在各种层次上提供回溯的、动态的数据信息 数据挖掘
(正在流行) “下个月波士顿的销售会怎么样?为什么?” 高级算法、多处理器计算机、海量数据库 Pilot、
Lockheed、IBM、SGI、其他初创公司 提供预测性的信息

表一、数据挖掘的进化历程。

数据挖掘的核心模块技术历经了数十年的发展,其中包括数理统计、人工智能、机器学习。今天,这些成熟的技术,加上高性能的关系数据库引擎以及广泛的数据集成,让数据挖掘技术在当前的数据仓库环境中进入了实用的阶段。 数据挖掘的范围

“数据挖掘”这个名字来源于它有点类似于在山脉中挖掘有价值的矿藏。在商业应用里,它就表现为在大型数据库里面搜索有价值的商业信息。这两种过程都需要对巨量的材料进行详细地过滤,并且需要智能且精确地定位潜在价值的所
在。对于给定了大小的数据库,数据挖掘技术可以用它如下的超能力产生巨大的商业机会:

自动趋势预测。数据挖掘能自动在大型数据库里面找寻潜在的预测信息。传统上需要很多专家来进行分析的问题,现在可以快速而直接地从数据中间找到答案。一个典型的利用数据挖掘进行预测的例子就是目标营销。数据挖掘工具可以根据过去邮件推销中的大量数据找出其中最有可能对将来的邮件推销作出反应的客户。 自动探测以前未发现的模式。数据挖掘工具扫描整个数据库并辨认出那些隐藏着的模式,比如通过分析零售数据来辨别出表面上看起来没联系的产品,实际上有很多情况下是一起被售出的情况。

数据挖掘技术可以让现有的软件和硬件更加自动化,并且可以在升级的或者新开发的平台上执行。当数据挖掘工具运行于高性能的并行处理系统上的时候,它能在数分钟内分析一个超大型的数据库。这种更快的处理速度意味着用户有更多的机会来分析数据,让分析的结果更加准确可靠,并且易于理解。 数据库可以由此拓展深度和广度

深度上,允许有更多的列存在。以往,在进行较复杂的数据分析时,专家们限于时间因素,不得不对参加运算的变量数量加以限制,但是那些被丢弃而没有参加运算的变量有可能包含着另一些不为人知的有用信息。现在,高性能的数据挖掘工具让用户对数据库能进行通盘的深度编历,并且任何可能参选的变量都被考虑进去,再不需要选择变量的子集来进行运算了。

广度上,允许有更多的行存在。更大的样本让产生错误和变化的概率降低,这样用户就能更加精确地推导出一些虽小但颇为重要的结论。 最近,Gartner Group的一次高级技术调查将数据挖掘和人工智能列为“未来三到五年内将对工业产生深远影响的五大关键技术”之首,并且还将并行处理体系和数据挖掘列为未来五年内投资焦点的十大新兴技术前两位。根据最近Gartner的HPC研究表明,“随着数据捕获、传输和存储技术的快速发展,大型系统用户将更多地需要采用新技术来挖掘市场以外的价值,采用更为广阔的并行处理系统来创建新的商业增长点。”

在数据挖掘中最常用的技术有:

人工神经网络:仿照生理神经网络结构的非线形预测模型,通过学习进行模式识别。

决策树:代表着决策集的树形结构。

遗传算法:基于进化理论,并采用遗传结合、遗传变异、以及自然选择等设计方法的优化技术。

近邻算法:将数据集合中每一个记录进行分类的方法。

规则推导:从统计意义上对数据中的“如果-那么”规则进行寻找和推导。

采用上述技术的某些专门的分析工具已经发展了大约十年的历史,不过这些工具所面对的数据量通常较小。而现在这些技术已经被直接集成到许多大型的工业标准的数据仓库和联机分析系统中去了。

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
66#
 楼主| 发表于 2003-12-15 13:29 | 只看该作者
《数据库的数据挖掘概述(二)》  
[ 作者:佚名    转贴自:本站原创    点击数:2    更新时间:2003-11-26    文章录入:cxmy ]

数据挖掘工具是怎样准确地告诉你那些隐藏在数据库深处的重要信息的呢?它们又是如何作出预测的?答案就是建模。建模实际上就是在你知道结果的情况下建立起一种模型,并且把这种模型应用到你所不知道的那种情况中。比如说,如果你想要在大海上去寻找一艘古老的西班牙沉船,也许你首先想到的就是去找找过去发现这些宝藏的时间和地点有哪些。那么,经过调查你发现这些沉船大部分都是在百慕大海区被发现,并且那个海区有着某种特征的洋流,以及那个时代的航线也有一定的特征可寻。在这众多的类似特征中,你将它们抽象并概括为一个普适的模型。利用这个模型,你就很有希望在具有大量相同特征的另外一个地点发现一件不为人知的宝藏。

当然,在数据挖掘技术甚至计算机出现以前,这种建模抽象的方法就已经广泛地被人们所使用。在计算机中的建模和以前的建模方法并无很大不同,主要的差异在于计算机能处理的信息量比起以前来更加庞大。计算机中能够存储已知了结果的大量不同情况,然后由数据挖掘工具从这些大量的信息里面披沙拣金,将能够产生模型的信息提取出来。一当模型建立好了之后,就可以应用在那些情形相似但结果尚未知的判断中了。比如,现在假设你是一个电信公司的营销主任,公司想发展一些新的长途电话用户,那么你是不是会漫无目的地到街上去散发广告呢?——就象漫无目的地在海上去寻宝一样。其实,比起漫无目的地去进行宣传来,利用你以前的商业经验来有目的地去拉拢客户会产生高得多的效率。

作为一个营销主任,你对客户的很多信息都可以了解得一清二楚:年龄、性别、信用记录以及长途电话使用状况。从好的一方面来看,掌握了这些客户的信息其实就是掌握了很多潜在的用户的同样的信息。问题在于你还不一定了解他们的长途电话使用情况(因为他们的长途电话也许是通过的另一个电信公司)。现在你的主要精力就集中在用户中谁有比较多的长途电话上。通过下面这个表格,我们可以从数据库里面抽象某些变量,建立起一个可以对此进行分类营销的模型。
  客户 潜力
一般信息
(e.g. demographic data) 已知 已知
私有信息
(e.g. customer transactions) 已知 待定

表二、数据挖掘应用于分类营销

根据我们创建的从一般信息到私有信息的计算模型,我们可以得出表二右下方表格中的信息。比如,一个电信公司的简化模型可以是:年薪6万美圆以上的98%的客户,每个月长话费80美圆以上。根据这个模型,我们就能应用这些数据来推断出公司现在尚不能明确的私有信息,这样,新客户群体就可以大体确定出来了。小型市场的试销数据对于这样的模型来说显得极为有用。因为小范围内试销数据的挖掘,能够为全部市场的分类销售打下一个良好的基础。表三则描述了另外一样数据挖掘的普遍应用:预测。
  过去 现在 将来
静态信息和当前计划 已知 已知 已知
动态信息 已知 已知 待定

表三、数据挖掘应用于预测

数据挖掘的体系结构

现有很多数据挖掘工具是独立于数据仓库以外的,它们需要独立地输入输出数据,以及进行相对独立的数据分析。为了最大限度地发挥数据挖掘工具的潜力,它们必须象很多商业分析软件一样,紧密地和数据仓库集成起来。这样,在人们对参数和分析深度进行变化的时候,高集成度就能大大地简化数据挖掘过程。下图显示了一个大型数据库中的高级分析过程。



集成后的数据挖掘体系

应用数据挖掘技术,较为理想的起点就是从一个数据仓库开始,这个数据仓库里面应保存着所有客户的合同信息,并且还应有相应的市场竞争对手的相关数据。这样的数据库可以是各种市场上的数据库:Sybase、Oracle、Redbrick、和其他等等,并且可以针对其中的数据进行速度上和灵活性上的优化。

联机分析系统OLAP服务器可以使一个十分复杂的最终用户商业模型应用于数据仓库中。数据库的多维结构可以让用户从不同角度,——比如产品分类,地域分类,或者其他关键角度——来分析和观察他们的生意运营状况。数据挖掘服务器在这种情况下必须和联机分析服务器,以及数据仓库紧密地集成起来,这样就可以直接跟踪数据和并辅助用户快速作出商业决策,并且用户还可以在更新数据的时候不断发现更好的行为模式,并将其运用于未来的决策当中。

数据挖掘系统的出现代表着常规决策支持系统的基础结构的转变。不象查询和报表语言仅仅是将数据查询结果反馈给最终用户那样,数据挖掘高级分析服务器把用户的商业模型直接应用于其数据仓库之上,并且反馈给用户一个相关信息的分析结果。这个结果是一个经过分析和抽象的动态视图层,通常会根据用户的不同需求而变化。基于这个视图,各种报表工具和可视化工具就可以将分析结果展现在用户面前,以帮助用户计划将采取怎样的行动。

产生利润的工具

有很多公司都成功地安装了数据挖掘工具。早先采用了这种技术的公司大部分都是信息密集型公司,比如金融服务和邮件营销系统,但是现在这种技术已经准备好应用于各个公司中,只要公司具有大型数据库,并且有强烈的通过软件技术改善公司管理的愿望。但是采用数据挖掘技术,公司必须两个关键的因素,一个就是大型的,集成化的数据库;另一个就是定义完善的商业处理程序,这样数据挖掘才好紧密地应用于公司数据之上。

采用数据挖掘技术的一些成功应用,例如一个药品公司,通过对它最近的营销强度和销售结果的分析,来决定哪一种营销活动在最近几个月内对高附加值的医生群体影响最大,这样的分析建立在竞争对手的销售活动信息和当地健康状况的数据系统之上。然后这个药品公司可以通过其办公网络,将分析结果传达到各地的销售代表处,销售代表们则可以根据公司传递的关键信息来作出相应的销售抉择,这样,在快速变化的、动态的市场上,销售代表们都可以根据各种特殊情况的分析作出最优的选择。

结语
全面集成了客户、供应者以及市场信息的大型数据仓库导致公司内的信息呈爆炸性增长,企业在市场竞争中,需要及时而准确地对这些信息作复杂的分析。为了更加及时地,更加准确地作出利于企业的抉择,建立在关系数据库和联机分析技术上的数据挖掘工具为我们带来了一个新的转机。目前,数据挖掘工具正以前所未有的速度发展,并且扩大着用户群体,在未来越加激烈的市场竞争中,拥有数据挖掘技术必将比别人获得更快速的反应,赢得更多的商业机会。

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
67#
 楼主| 发表于 2003-12-15 14:20 | 只看该作者
当SQL Server数据库崩溃时如何恢复?
出处:PConline
责任编辑:pcedu

[03-9-8 16:14]  作者:怡红公子  

  
  任何数据库系统都无法避免崩溃的状况,即使你使用了Clustered,双机热备……仍然无法完全根除系统中的单点故障,何况对于大部分用户来说,无法承受这样昂贵的硬件投资。所以,在系统崩溃的时候,如何恢复原有的宝贵数据就成为一个极其重要的问题了。



  在恢复的时候,最理想的情况就是你的数据文件和日志文件都完好无损了,这样只需要sp_attach_db,把数据文件附加到新的数据库上即可,或者在停机的时候把所有数据文件(一定要有master等)都copy到原有路径下也行,不过一般不推荐这样的做法,sp_attach_db比较好,虽然麻烦许多。

  但是呢,一般数据库崩溃的时候系统是未必能有时间把未完成的事务和脏页等写入磁盘的,这样的情况sp_attach_db就会失败。那么,寄期望于DBA制定了一个良好的灾难恢复计划吧。按照你的恢复计划,还原最新的完全备份,增量备份或者事务日志备份,然后如果你的活动事务日志还能读得出来的话,恭喜你!你可以还原到崩溃前的状态。

   一般的单位都是没有专职的DBA的,如果没有可用的备份,更可能是最近一次备份的时间过于久远而导致不可接受的数据损失,而且你的活动事务日志也处于不可用的状态,那就是最麻烦的情况了。

  不幸的很的是,一般数据库崩溃都是由于存储子系统引起的,而这样的情况是几乎不可能有可用的日志用于恢复的。

  那么就只好试一下这些方案了。当然,是要求至少你的数据文件是存在的,要是数据文件、日志文件和备份都没有了的话,别找我,你可以到楼顶上去唱“神啊,救救我吧”。

  首先,你可以试一下sp_attach_single_file_db,试着恢复一下你的数据文件,虽然能恢复的可能性不大,不过假如这个数据库刚好执行了一个checkpoint的话,还是有可能成功的。

  如果你没有好到有摸彩票的手气,最重要的数据库没有像你期盼的那样attach上去,不要气馁,还是有别的方案的。

  我们可以试着重新建立一个log,先把数据库设置为emergency mode,sysdatabases的status为32768 就表示数据库处于此状态。

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
68#
 楼主| 发表于 2003-12-15 14:20 | 只看该作者
当SQL Server数据库崩溃时如何恢复?
出处:PConline
责任编辑:pcedu

[03-9-8 16:14]  作者:怡红公子  

  

  不过系统表是不能随便改的,设置一下先
  Use Master
  Go
  sp_configure 'allow updates', 1
  reconfigure with override
  Go
  然后
  update sysdatabases set status = 32768 where name = ''

  现在,祈求满天神佛的保佑吧,重新建立一个log文件。成功的机会还是相当大的,系统一般都会认可你新建立的日志。如果没有报告什么错误,现在就可以松一口气了。

  虽然数据是恢复了,可是别以为事情就算完成了,正在进行的事务肯定是丢失了,原来的数据也可能受到一些损坏。

  先把SQL Server 重新启动一下,然后检查你的数据库吧。
  先设置成单用户模式,然后做dbcc
  sp_dboption '', 'single user', 'true'
  DBCC CHECKDB('')

  如果没有什么大问题就可以把数据库状态改回去了,记得别忘了把系统表的修改选项关掉。
update sysdatabases set status = 28 where name = '' --当然你的数据库状态可能不是这个,自己改为合适的值吧。也可以用sp_resetstatus
  go
  sp_configure 'allow updates', 0
  reconfigure with override
  Go

  checkdb的时候可能报告有一些错误,这些错误的数据你可能就只好丢弃了。

  checkdb有几种修复选项,自己看着用吧,不过最后你可能还是得REPAIR_ALLOW_DATA_LOSS,完成所有修复。

  chekcdb并不能完成所有的修复,我们需要更进一步的修复,用DBCC CHECKTABLE对每一个表做检查吧。

  表的列表可以用sysobjects里面得到,把OBJECTPROPERTY是IsTable的全部找出来检查一下吧,这样能够基本上解决问题了,如果还报告错误,试着把数据select into到另一张表检查一下。

  这些都做完了之后,把所有索引、视图、存储过程、触发器等重新建立一下。DBCC DBREINDEX也许可以帮你一些忙。

  上面提到的命令、对象在Books Online中均有详细说明,请注意参看

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
69#
 楼主| 发表于 2003-12-15 14:22 | 只看该作者
解决MSSQL占用过多内存的简单方法
出处:PConline
责任编辑:pcedu

[03-9-11 11:04]  作者:佚名  

  
  经常看见有人问,MSSQL占用了太多的内存,而且还不断的增长;或者说已经设置了使用内存,可是它没有用到那么多,这是怎么一回事儿呢?
  


  首先,我们来看看MSSQL是怎样使用内存的。

  最大的开销一般是用于数据缓存,如果内存足够,它会把用过的数据和觉得你会用到的数据统统扔到内存中,直到内存不足的时候,才把命中率低的数据给清掉。所以一般我们在看statistics io的时候,看到的physics read都是0。

  其次就是查询的开销,一般地说,hash join是会带来比较大的内存开销的,而merge join和nested loop的开销比较小,还有排序和中间表、游标也是会有比较大的开销的。

  所以用于关联和排序的列上一般需要有索引。

  再其次就是对执行计划、系统数据的存储,这些都是比较小的。

  我们先来看数据缓存对性能的影响,如果系统中没有其它应用程序来争夺内存,数据缓存一般是越多越好,甚至有些时候我们会强行把一些数据pin在高速缓存中。但是如果有其它应用程序,虽然在需要的时候MSSQL会释放内存,但是线程切换、IO等待这些工作也是需要时间的,所以就会造成性能的降低。这样我们就必须设置MSSQL的最大内存使用。可以在SQL Server 属性(内存选项卡)中找到配置最大使用内存的地方,或者也可以使用sp_configure来完成。如果没有其它应用程序,那么就不要限制MSSQL对内存的使用。

  然后来看查询的开销,这个开销显然是越低越好,因为我们不能从中得到好处,相反,使用了越多的内存多半意味着查询速度的降低。所以我们一般要避免中间表和游标的使用,在经常作关联和排序的列上建立索引。

使用道具 举报

回复
求职 : 系统分析师
论坛徽章:
691
博彩大赢家
日期:2014-07-14 11:41:47博彩大赢家
日期:2015-09-24 12:11:05菠菜神灯
日期:2016-04-18 13:59:20NBA季后赛大富翁
日期:2016-04-27 11:51:10NBA季后赛大富翁
日期:2016-06-24 10:29:08芝加哥公牛
日期:2015-06-25 09:32:08芝加哥公牛
日期:2016-04-18 14:22:33芝加哥公牛
日期:2016-10-27 14:28:54芝加哥公牛
日期:2016-12-27 14:16:24芝加哥公牛
日期:2017-04-18 17:07:58
70#
 楼主| 发表于 2003-12-15 14:24 | 只看该作者
数据库的备份与恢复
出处:中国电脑教育报
责任编辑:pcedu

[02-12-9 14:58]  作者:刘利强  
   
内容搜索
   
  高级搜索      


  
  随着信息时代和互联网技术的飞速发展,企业的信息数据量也急剧增长。如何避免突如其来的数据破坏(如:黑客攻击、病毒袭击、硬件故障和人为误操作等),提高数据的安全性和数据恢复能力一直是用户和厂商关注的焦点。备份是恢复数据最容易和最有效的保证方法,备份应定期进行,并执行有效的数据管理。

  Microsoft公司的SQL Server是一个功能完善的数据库管理系统,由于和Windows操作系统无缝结合,操作简便易行,应用十分广泛。下面来看一看基于NT的SQL Server 7.0的备份与数据恢复的有效方法。

  针对服务器系统

  由于数据库服务器中安装的系统较多,设置复杂,如出现硬件故障,则必须重装系统,恢复设置,因此有必要对数据库服务器进行备份。

  1、使用NT Server提供的功能

  在防止数据丢失方面,NT的磁盘管理器具有强大的功能,它支持RAID的第0、1、5级。其中RAID 1级是指把一个驱动器上的某一分区在另一个上建立一个镜像。进行写操作时,数据将向两个磁盘中写入同样的数据,读取时可以从两个磁盘同时读取。当驱动器损坏时,由它的镜像来进行恢复。

  2、使用第三方备份工具

  采用其他公司的备份软件来对服务器系统做备份。笔者常用的是Norton公司的磁盘备份工具——Ghost。该软件可以直接将磁盘上的某个分区或整个硬盘克隆成一个镜像文件,然后把它存放在别处,那么当该分区或硬盘出现问题甚至毁坏时,使用Ghost在另一硬盘或分区上,利用镜像文件快速还原。

  针对SQL Server

  1、在本地机上进行数据库备份

  先确认SQL Server服务是否已经启动,如果没有启动,则使用SQL Server 7.0程序菜单中的“SQL Server Service Manager”进行启动,然后打开 “Enterprise Manager”,展开左边的SQL Server Group,展开SQL Server中的“Databases”,单击右键,在菜单中选择“所有任务”选项中的“Backup Database”子选项,出现如图1的数据库备份画面。

  
  图1

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表