Perl学习笔记(十)--通过DBI访问数据库

  Perl访问数据库最常用的包是DBI,可以在www.cpan.org找到。另外还需要安装对应数据库的驱动包,例如DBD::MySQL、DBD::Oracle、DBD::Sybase或者DBD::ODBC等。

一、基本流程

  一般来说,数据库操作由以下几个步骤组成一个常见的流程:

  1. 建立一个数据库连接

  2. 通过建立的数据库连接,执行SQL语句

  3. 执行SQL后获取返回的数据集

  4. 在数据集中对记录进行处理,一般是一个循环的过程

  5. 处理完毕,关闭数据库连接,释放资源

下面是按照上述的流程,在Perl中访问MySQL的一段代码,以这段代码为例,详细说明DBI的使用方法。

#!/usr/bin/perl -w
use strict;
use DBI;

my $dbh = DBI->connect("DBI:mysql:test:192.168.1.2", ‘root‘, ‘password‘);
my $sth = $dbh->prepare("SELECT * FROM test1");
$sth->execute();

while ( my @row = $sth->fetchrow_array() )
{
       print join(‘\t‘, @row)."\n";
}

$sth->finish();
$dbh->disconnect();

 1.1 连接数据库

my $dbh = DBI->connect("DBI:mysql:test:192.168.1.2", ‘root‘, ‘password‘);

  调用DBI的方法DBI->connect来建立一个数据库的连接,如果连接成功则返回一个数据库连接句柄,之后执行SQL等操作都要把这个连接句柄作为一个操作参数。在connect调用中,首先要提供一个数据库连接串。这个连接串用冒号分为了几个部分:

小节 说明
DBI 接口类型
mysql 数据库类型
test 数据库名称
192.168.1.2 数据库主机地址

  在前面例子中的连接串中,DBI表示这是DBI接口的一个连接串;mysql表示要连接的数据库是MySQL数据库(如果要连接Oracle数据 库,这里则是oracle),不同的数据库有不同的连接串定义,可以参考DBI对应的访问驱动的说明;test指明了连接到数据库主机上的数据库名 称;192.168.1.2就是MySQL服务器的IP地址。这里要注意的是,连接串中的数据库类型mysql必须小写。如果省略了主机名,则缺省为 localhost。connect方法的后面两个参数是连接数据库主机的用户名和密码,这个可是不可缺少的 J

  如果在连接过程中出现任何错误,则connect的返回值都会是undef(和C语言中的NULL是一回事)。这里为了简化而略去了错误检查,实际做项目的时候应当对这些错误和返回值的进行检查。

1.2 执行SQL语句

my $sth = $dbh->prepare("SELECT * FROM test1");
$sth->execute();
$dbh->do(“UPDATE test1 SET time=now()”);

  连接上了数据库,获得了数据库连接句柄,就可以利用这个句柄来对数据库进行操作了。要执行一条SQL语句,为了提高性能,DBI分两个步骤来做。先把 SQL语句通过prepare方法提交到数据库,数据库为该语句分配执行资源,之后调用execute方法通知数据库执行该SQL语句。注意 prepare方法是通过数据库连接句柄调用的,如果成功则返回一个该SQL的句柄,之后通过该SQL语句句柄调用execute执行SQL。 一般来说execute执行的都是返回数据的语句(例如SELECT语句)。反之如果执行INSERT、UPDATE、DELETE、CREATE TABLE等不需要返回数据的语句,则有一个更方便、快速的方法 $dbh->do(SQL语句),可以省去prepare的步骤。do方法返回的是受该SQL影响的记录数量。

1.2.1 技巧:对SQL进行排版

常写大段SQL的朋友可能会对于SQL中的引号很头痛,每每都因为引号的问题搞的SQL语句乱成一团分辨不清。还记得上篇文章讲过的qq吗?这里正 是它的好用处。由于qq中的字符串同双引号” ”内的字符串一样会对变量进行解释,同时qq还可以换行。因此使用它来对SQL进行排版是非常好的一个选择,例如像这样的一条SQL语句:

my $res_operator = $dbhandle->prepare( qq{
       SELECT o_customerid, COUNT(*) AS totalMsgNum FROM mm4fcdrs
       WHERE (m_date>‘$begindate‘) AND (m_date<‘enddate‘)
       GROUP BY o_customerid
});

 1.2.2 通过SQL语句中的参数优化查询执行效率

  在执行大量INSERT之类的语句的时候,反复向数据库服务器提交同样结构的一个SQL语句,在这种情况下可以利用prepare和SQL参数来优化执行效率:

  1.先使用prepare提交一个SQL模板给数据库服务器,把其中值的部分用参数占位符代替。

  2.使用prepare让服务器为该SQL准备了执行资源后,调用execute并在该方法中传入参数实际的值执行SQL。

  3.之后可以反复调用execute,不需要服务器重新prepare

  假设要执行这样的一个系列的SQL

INSERT INTO test1 VALUES (NULL, ‘a’, ‘2005-04-01’)
... ...
INSERT INTO test1 VALUES (NULL, ‘z’, ‘2005-04-01’)

其中第二个字段的值是从a到z的字母。那么可以这样来优化执行效率:

my $sth = $dbh->prepare( qq{
    INSERT INTO test1 VALUES (NULL, ?, ‘2005-04-01’)
} );

for my $value(‘a‘..‘z‘)  {
    $sth->execute($value);
}

其中的问号就是前面说的参数占位符了,它的意思就是告诉在准备执行资源的服务器:这个SQL的这个位置会有一个值,但是现在还不知道,等下执行的时候再告 诉你。 prepare了之后,用一个循环产生a-z的字符给变量$value,然后将$value在execute方法中作为一个参数传入,服务器那里会自动用 传入的值替换前面的"?"。需要提醒的是,传入的参数个数一定要和SQL中的占位符的数量一样。

1.3 读取记录

熟悉ADO的朋友一定知道里面有一个DataReader对象,DBI中读取数据的方法和它非常的相似。简单来说,就是单向、流式的读取数据,也就是每次只能向后读一条数据直到没有数据可以读取。

文章开头的例子中,用了 $sth->fetchrow_array() 方法来读取数据。其实DBI读取数据还有几种常见的方法,这几个方法是类似的,所不同的是返回记录的形式。

1.3.1 fetchrow_array

返回一个由字段的值组成的数组。该数组的第1个元素就是当前记录第1个字段的值。

while ( my @row = $sth->fetchrow_array() )  {
    print "$row[0], $row[1], $row[2]\n";
}

或者这样,不过要注意字段对应的顺序

while ( my ($id, $name, $time) = $sth->fetchrow_array() )  {
    print "$id, $name, $time\n";
}

1.3.2 fetchrow_arrayref

  返回由字段的值组成的数组的引用。同fetchrow_array的区别很明显,fetchrow_arrayref返回的数组的引用。

while ( my $row_ref = $sth->fetchrow_arrayref() ) {
    for (my $i = 0; $i < @{$row_ref}; $i++)       {
        print "$row_ref->[$i]\t";
    }
    print "\n";
}

这里要注意的是,如果要取字段的个数,需要把这个引用转成数组的形式获得 @{$row_ref} 。获取数组元素的值的时候,因为$row_ref是引用,因此需要使用->操作符。

1.3.3 fetchrow_hashref

  返回一个由”字段名-字段值”这样的”键-值”对组成的HASH表。关键的不同就是,只有这个方法可以通过一个字段名获得它的值,而不必关心这个字段是第几个字段。而前者只能依靠索引来访问值。不过缺点就是,效率要比前面两个差一些。

while ( my $record = $sth->fetchrow_hashref() ) {
    for my $field( keys %{$record} ) {
        print "$field: $record->{$field}\t";
    }
    print "\n";
}

这里需要复习一下HASH表的操作方法。keys操作符获取HASH的键(key)的数组,$record->{$field}获得HASH表中$field对应的值。注意这里同样是引用,因此要用->操作符。

使用上面三个方法可以基本解决问题了。此外,还有两个方法fetchall_arrayrefselectall_arrayref可以直接通过SQL一次性获取整个数据集,不过使用上稍微复杂一些,要涉及到 perl的scalar 操作符,这里就不赘述了。有兴趣的读者可以参考DBI的相关资料。

最后是收尾工作。

1.4 结束一个SQL会话

$sth->finish();

 1.5 断开数据库连接

$dbh->disconnect();

http://dbi.perl.org/

http://www.perl.com/pub/1999/10/DBI.html

时间: 2024-09-29 19:38:32

Perl学习笔记(十)--通过DBI访问数据库的相关文章

java jvm学习笔记十二(访问控制器的栈校验机制)

欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 本节源码:http://download.csdn.net/detail/yfqnihao/4863854 这一节,我们会简单的描述一下jvm访问控制器的栈校验机制. 这节课,我们还是以实践为主,什么是栈校验机制,讲一百遍不如你自己实际的代码一下然后验证一下,下面我们下把环境搭起来. 第一步,配置系统环境.(copy吧,少年) path=%JAVA_HOME%/bin JAVA_HOME=C:/Java/jdk1.6

Swift学习笔记十:属性

1.存储属性       1. 作为特定类或结构实例的一部分,存储属性存储着常量或者变量的值.存储属性可分为变量存储属性(关键字var描述)和常量存储属性(关键字let描述). struct student{ let name = "" var score = 0 } let a = student(name:"小笨狼",score:96)           注意:                ① 定义储存属性时,需要为每一个属性定义一个默认值.在初始化的时候,

虚拟机VMWare学习笔记十二 - 将物理机抓取成虚拟机

1. 安装VMware vCenter Converter Standalone Client 运行虚拟机,File -- Virtualize a Physical Machine 这时如果电脑中没有VMware vCenter Converter Standalone Client ,则会进行安装. 安装过程 之后图标会出现在桌面上,双击运行 选择连接到本地服务器,登陆 点击转换计算机 这个,可以将本地计算机抓取成虚拟机,也可以将其他可以访问的计算机(需知道管理员用户名及密码)抓取成虚拟机.

APUE 学习笔记(十) 高级I/O

1. Unix IPC(InterProcess Communication) 同一主机的各个进程间的IPC:管道.FIFO.消息队列.信号量.共享存储器 不同主机上的各个进程间IPC:socket套接字 2. 管道 管道进行IPC有两个局限: (1) 半双工,即数据只能在一个方向上流动 (2) 只能在具有公共祖先的进程之间使用.通常,一个管道由一个进程创建,然后该进程调用fork,此后 父子进程之间可以使用该管道 fstat函数对管道的每一端都返回一个FIFO类型的文件描述符,可以用S_ISF

C++学习笔记十六-模板和泛型编程(二)

C++学习笔记十六-模板和泛型编程(二) 16.4 类模板成员 1.模板作用域中模板类型的引用: 通常,当使用类模板的名字的时候,必须指定模板形参.这一规则有个例外:在类本身的作用域内部,可以使用类模板的非限定名.例如,在默认构造函数和复制构造函数的声明中,名字 Queue 是 Queue<Type> 缩写表示.实质上,编译器推断,当我们引用类的名字时,引用的是同一版本.因此,复制构造函数定义其实等价于: Queue<Type>(const Queue<Type> &a

《Hibernate学习笔记十》:多对多关联关系详解

<Hibernate学习笔记十>:多对多关联关系 前面介绍了一对一.多对一和一对多的关联关系在Hibernate应如何实现,这篇博文就来介绍下最后一种关联关系:多对多.多对多关联关系在我们现实生活中的例子实在是太多太多,最典型的就是老师和学生的例子:一个老师可以教多个学生,而一个学生又可以被多个老师来教. 了解一点数据库的我们都知道,在数据库中表示多对多的关联关系,是借助于中间表来解决的. 如下: 还是和以往的思路一样,每一种关联关系都分为单向关联和双向关联,我们每种都会进行介绍,对于单向和双

《Hibernate学习笔记十二》学生、课程、分数关系的设计与实现

<Hibernate学习笔记十二>学生.课程.分数关系的设计与实现 这个马士兵老师的Hibernate视频学习的一个题目,这里面要用到多对多.多对一的关联关系以及联合主键,因此觉得挺好的,自己写篇博文来记录下. 先考虑数据库表 1.学生表:为简单起见,只考虑了学生id和学生姓名,其中id为主键 2.课程表:为简单起见,只考虑了课程id和课程名称,其中id为主键 3.分数表 分数表有两种解决方案 3.1 第一种为:使用联合主键:student_id 和 course_id 3.2 第二种:不使用

laravel3学习笔记(十二)

原作者博客:ieqi.net ==================================================================================================== 请求反射 HTTP 协议本身是无状态性的,但是在应用中处理各种业务逻辑时我们必须要有状态的把控,这样,折中的办法就是将状态进行标记然后嵌入到 HTTP 协议的请求中,然后应用根据这些标记来进行状态的串联以及处理.所以我们就要对请求进行反射处理以获取请求信息, Lara

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

第十七篇:实例分析(3)--初探WDDM驱动学习笔记(十)

续: 还是记录一下, BltFuncs.cpp中的函数作用: CONVERT_32BPP_TO_16BPP 是将32bit的pixel转换成16bit的形式. 输入是DWORD 32位中, BYTE 0,1,2分别是RGB分量, 而BYTE3则是不用的 为了不减少color的范围, 所以,都是取RGB8,8,8的高RGB5, 6, 5位, 然后将这16位构成一个pixel. CONVERT_16BPP_TO_32BPP是将16bit的pixel转换成32bit的形式 输入是WORD 16BIT中