Java EE架构设计与开发实践
上QQ阅读APP看书,第一时间看更新

2.3 JDBC简介

Web应用程序常常需要和数据库交互,将数据保存到数据库,从数据库取出数据等。Web应用程序对数据库的操作主要是4种:插入记录、删除记录、更新记录、查询符合条件的记录,这4种操作常称为CRUD。现在的数据库主要是关系数据库。常见的关系数据库有Oracle、DB2、Microsoft SQL Server、MySQL等。Java应用程序要连接数据库就需要JDBC技术。

在介绍JDBC前先介绍在SQL常用的语句,详细的SQL语句和数据库操作请参见相应的数据库书籍。

2.3.1 常用的标准SQL语句

(1)创建数据库语句如下:

        Create database databaseName

上述语句会创建一个名字叫databaseName的数据库。

(2)删除数据库语句如下:

        Drop database databaseName

上述语句将删除databaseName数据库。

(3)创建表的语句格式如下:

        Create table tableName
        (column1 datatype[column_constraint],
        column1 datatype[column_constraint],
        …
          [Constrain primary key pk_table_name(column_n)]

以SQLServer数据库为例,用SQL语句创建用户表user,该表有id、name、password、email、age、birthday、money字段,数据库中字段的数据类型分别是int、varchar、varchar、varchar、int、datetime、float型。由于在数据库SQL Server中user是关键字,不允许用户直接使用,因此在user的两边加上[]。

        create table [user](id int, name varchar(50), password varchar(50), email
        varchar(50), age int, birthday datetime);

(4)删除表的语句如下:

        drop table tableName;

例如,以下语句用于删除表user。

        drop table [user];

(5)插入一条记录的语句格式如下:

        insert into tableName(column1,column2,……) values(value1,value2,……);

例如,向user表中插入一条记录。

        insert into [user](name,password,email,age,birthday)
        values('Funson','888','Funson@163.com',28,'1988-12-08',66.0);

(6)删除符合条件的一条或多条记录:

        delete from tableName [where …];

例如,删除user表中id是1的记录。

        delete from user where id=1;

如果去掉where子句,将删除user表中所有的记录。

(7)更新一条或多条记录:

        update tableName set columnName=newColumnValue;

例如,以下语句更新user表中id=1的password字段,字段原来的值是123,更新后为456。

        update [user] set password='456';

以上简要介绍了常用的SQL语句,为了能在Java程序中操作数据库,还需要使用JDBC。

2.3.2 JDBC结构

JDBC的全称是Java Database Connectivity,是一个应用程序编成接口(API),包括了许多类和接口,程序员通过使用JDBC可以方便地将SQL语句传送给几乎任何一种数据库。

简单地说,JDBC主要完成3件事:

与一个数据库建立连接;向数据库发送SQL语句;处理数据库返回的结果。具体操作步骤如下。

(1)向驱动程序管理器加载注册JDBC驱动程序。

(2)获得特定数据库的连接。

(3)得到SQL语句容器,并发送SQL语句。

(4)如果有结果集返回的话,处理结果集。

(5)关闭数据库连接。

Sun公司的JDBC规范定义了如何操作数据库的一组标准,数据库厂商要实现这些标准来完成真正的数据库操作。这有些像在Java语言中的接口和实现类,Sun公司的标准类似接口,数据库厂商的实现类似实现类。接口只是定义如何做某件事,但是不能真正做;实现类能真正能完成接口中定义的操作。

JDBC的体系结构,如图2-1所示,其包含4个组件:

图2-1 JDBC体系结构

(1)Java应用程序。Java应用程序负责用户与用户接口之间的JDBC交互操作,以及调用JDBC的对象方法以给出SQL语句并提取结果。

(2)JDBC驱动程序管理器。JDBC驱动程序管理器为应用程序加载和调用驱动程序。

(3)JDBC驱动程序。JDBC驱动程序执行JDBC对象方法的调用,发送SQL请求给指定的数据源,并将结果返回给应用程序。驱动程序也负责与任何访问数据源的必要软件层进行交互。

(4)数据源。数据源由数据集和与其相关联的环境组成,主要指各数据库厂商的数据库系统。

在Java应用程序中使用JDBC的API来访问数据库时,需要在系统环境变量CLASSPATH中加载某个具体的数据库的JDBC驱动,这样不管是什么数据库,只要有驱动,在Java程序中使用统一的类和接口就能完成对数据库的操作了。如图2-2所示为Java SQL驱动核心类与接口。

图2-2 JDBC驱动核心类与接口

总体而言,JDBC包含以下几大角色:Driver、DriverManager、Connection、Statement、ResultSet。

❑ 数据库驱动Driver:JDBC的驱动程序,通过指定的URL创建数据库连接。

❑ 驱动程序管理器DriverManager:DriverManager可以注册和删除加载的驱动程序,可以根据给定的URL获取符合URL协议的驱动Driver或者是建立Connection连接,进行数据库交互。获取连接对象Connection DriverManager.getConnection(连接字符串,用户名,密码),注册驱动程序DriverManager.registerDriver(new oracle.jdbc.driver. OracleDriver())。

❑ 连接对象Connection:Driver或者DriverManager根据连接的URL和参数信息创建Connection实例,用来维持和数据库的数据通信,如果没有销毁或者调用close()对象,此对象和数据库的对象会一直保持连接。

❑ 命令对象Statement:Connection创建Statement对象,表示需要执行的SQL语句或者存储过程。

❑ 结果对象ResultSet:表示Statement执行完SQL语句后返回的结果集。

2.3.3 JDBC驱动类型

JDBC数据库驱动程序Driver的4种类型如下。

❑ 类型1:JDBC-ODBC桥接器。

❑ 类型2:本机API Java驱动程序。

❑ 类型3:JDBC网络纯Java驱动程序。

❑ 类型4:本地协议纯Java驱动。

第一种驱动类型JDBC-ODBC桥接器:因为微软推出的ODBC比JDBC出现的较早,所以绝大多数的数据库都可以通过ODBC来访问,当Sun公司推出JDBC的时候,为了支持更多的数据库,提供了JDBC-ODBC桥。这样开发者就可以使用JDBC的API通过ODBC去访问数据库。可以看到通过JDBC-ODBC桥访问数据库需要经过多层调用,因此效率较低。但是在数据库没有提供JDBC驱动只提供ODBC驱动的情况下,只能通过这种方式访问数据库。例如,Java若要访问Microsoft Access数据库,则只能通过这种方法访问。其驱动程序为sun.jdbc.odbc.JdbcOdbcDriver,如图2-3所示。

图2-3 JDBC-ODBC桥接器

该方式缺点:增加了ODBC层后导致效率低。JDBC-ODBC桥不支持分布式(除非ODBC驱动本身支持分布式)。

第二种驱动类型本机API Java驱动程序:部分Java驱动程序直接将JDBC API翻译成具体数据库的API。效率比第一种驱动高,缺点是客户端需要安装具体数据库的驱动。用这种方式访问数据库需要在客户机上安装本地JDBC驱动和特定数据库厂商的本地API,如图2-4所示。

图2-4 本机API Java驱动程序

第三种驱动类型JDBC网络纯Java驱动程序:纯Java驱动程序将JDBC API转换成独立于数据库的协议。网络协议Java驱动程序是最好的驱动程序,因为它通常提供了最佳的性能,并允许开发者利用特定数据库的功能,如图2-5所示。

图2-5 JDBC网络纯Java驱动程序

Java应用程序通过JDBC网络纯Java驱动程序,将JDBC调用发送给应用程序服务器,应用程序服务器与数据库完成通信,从而完成请求。

第四种驱动类型本地协议纯Java驱动:Java应用程序通过纯Java驱动程序与支持JDBC的数据库直接通信。这种方式是效率最高的访问方式。访问不同厂商的数据库,需要不同的JDBC驱动程序。目前,几个主要的数据厂商(Oracle、Microsoft SQL Server、Sybase等)都提供了对JDBC的支持,如图2-6所示。

图2-6 本地协议纯Java驱动

2.3.4 常用数据库JDBC连接写法

在需要通过JDBC连接数据库系统时,需要以下两个步骤。

❑ 驱动程序类名:一个继承java.sql.Driver接口的类名,JDBC驱动程序管理器需要加载这个类来处理数据库驱动程序。

❑ 数据库URL:一个字符串,该字符串包含关于数据库连接的信息和其他配置属性。这个字符串有自己的格式,不同数据库之间存在不同的格式。

常见的JDBC数据库连接的驱动名称及URL如下。

(1)MySQL

驱动程序包:mysql-connector-java-5.1.18-bin.jar;

驱动程序类名:com.mysql.jdbc.Driver;

URL格式:jdbc:mysql://servername:port/database。

    Class.forName( " com.mysql.jdbc.Driver " );
    cn = DriverManager.getConnection(
    "jdbc:mysql://MyDbComputerName Or IP:3306/myDatabaseName", sUsr, sPwd );

(2)PostgreSQL

驱动程序包:pgjdbc2.jar;

驱动程序类名:org.postgresql.Driver;

URL格式:jdbc:postgresql:// servername / database。

    Class.forName( "org.postgresql.Driver" );
    cn = DriverManager.getConnection(
    "jdbc:postgresql://MyDbComputerNameOrIP/myDatabaseName", sUsr, sPwd );

(3)Oracle

驱动程序包:ojdbc6.jar;

驱动程序类名:oracle.jdbc.driver.OracleDriver;

URL格式:jdbc:oracle:thin:@<database>。

    Class.forName( "oracle.jdbc.driver.OracleDriver" );
    cn = DriverManager.getConnection(
    "jdbc:oracle:thin:@MyDbComputerName Or IP:1521:ORCL", sUsr, sPwd );

(4)Sybase

驱动程序包:jconn2.jar;

驱动程序类名:com.sybase.JDBC.SybDriver;

URL格式:JDBC:sybase:Tds: servername:5007/ database。

    Class.forName( "com.sybase. JDBC.SybDriver" );
    cn = DriverManager.getConnection(
    "jdbc:sybase:Tds:MyDbComputerName  Or  IP:5007/myDatabaseName  ",  sUsr,
    sPwd );
    //(Default-Username/Password: "dba"/"sql")

(5)Microsoft SQLServer

驱动程序包:sqljdbc4.jar;

驱动程序类名:com.microsoft.JDBC.sqlserver.SQLServerDriver;

URL格式:JDBC:microsoft:sqlserver:// servername:1433;DatabaseName= master。

    Class.forName( "com.microsoft.jdbc.sqlserver.SQLServerDriver" );
    cn = DriverManager.getConnection(
    "jdbc:microsoft:sqlserver://MyDbComputerName Or IP:1433;databaseName=master",
    sUsr, sPwd );

(6)Informix

驱动程序包:ifxjdbc.jar;

驱动程序类名:com.informix.JDBC.ifxDriver;

URL格式:JDBC:informix-sqli:localhost:1533/database:INFORMIXSERVER=myserver。

    Class.forName( " com.informix.JDBC.ifxDriver " );
    Connection cn = DriverManager.getConnection( " JDBC:informix-sqli:
    localhost:1533/ database:
    INFORMIXSERVER=myserver"user=testUser;password=testpassword”
    );

2.3.5 创建JDBC应用程序具体步骤

通过前面的JDBC知识的学习,下面通过建立一个JDBC应用程序的具体实例进一步掌握其用法,一般有6个步骤。

(1)导入包

需要有软件包包含数据库编程所需的JDBC类。大多数情况下,使用import java.sql.*就足够了,代码如下:

        //STEP 1. 导入所需包
        import java.sql.*;

(2)注册JDBC驱动程序

这一步需要初始化驱动程序,这样就可以打开与数据库的通信信道。以下是代码片段实现这一目标:

        //STEP 2: 注册JDBC驱动
        Class.forName("com.mysql.jdbc.Driver");  //连接MySQL数据库

(3)打开一个连接

这一步需要使用DriverManager.getConnection()方法创建一个Connection对象,它代表一个物理连接的数据库,代码如下:

        //STEP 3: 打开一个连接
        // Database credentials
        static final String USER = "username";
        static final String PASS = "password";
        System.out.println("Connecting to database…");
        conn = DriverManager.getConnection(DB_URL,USER,PASS);

(4)执行一个查询

这一步需要使用一个对象类型Statement或PreparedStatement构建,并提交一个SQL语句到数据库。代码如下:

        //STEP 4: 执行查询
        System.out.println("Creating statement…");
        stmt = conn.createStatement();
        String sql;
        sql = "SELECT id, first, last, age FROM Employees";
        ResultSet rs = stmt.executeQuery(sql);

如果有一个SQL UPDATE、INSERT或DELETE语句,那么需要下面的代码片段:

        //STEP 4: 执行查询
        System.out.println("Creating statement…");
        stmt = conn.createStatement();
        String sql;
        sql = "DELETE FROM Employees";
        ResultSet rs = stmt.executeUpdate(sql);

(5)从结果集中提取数据

这一步是必需的情况下,从数据库中获取数据。可以使用适当的ResultSet.getXXX()方法来检索数据结果

        //STEP 5: 从结果集中提取数据
        while(rs.next()){
            //Retrieve by column name
            int id  = rs.getInt("id");
            int age = rs.getInt("age");
            String first = rs.getString("first");
            String last = rs.getString("last");
            //Display values
            System.out.print("ID: " + id);
            System.out.print(", Age: " + age);
            System.out.print(", First: " + first);
            System.out.println(", Last: " + last);
        }

(6)清理环境

应该明确地关闭所有的数据库资源,对依赖于JVM的垃圾收集如下:

        //STEP 6:清理环境,关闭连接
        rs.close();
        stmt.close();
        conn.close();

再通过一个完整的JDBC应用程序理解上述6个步骤。基于上面的步骤,完成名为FirstJDBCExample的综合JDBC调用MySQL的应用示例代码,其他数据库连接可以以其作为模板而写出相应的JDBC代码。

        //STEP 1. 导入所需包
        import java.sql.*;
        public class FirstJDBCExample {
          //JDBC驱动名和数据库连接URL
          static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
          static final String DB_URL = "jdbc:mysql://localhost/EMP";
          //数据库连接凭据
          static final String USER = "username";
          static final String PASS = "password";
          public static void main(String[] args) {
          Connection conn = null;
          Statement stmt = null;
          try{
              //STEP 2: 注册JDBC驱动
              Class.forName("com.mysql.jdbc.Driver");
              //STEP 3: 打开连接
              System.out.println("Connecting to database…");
              conn = DriverManager.getConnection(DB_URL,USER,PASS);
              //STEP 4: 执行查询
              System.out.println("Creating statement…");
              stmt = conn.createStatement();
              String sql;
              sql = "SELECT id, first, last, age FROM Employees";
              ResultSet rs = stmt.executeQuery(sql);
              //STEP 5: 从结果集中检索数据
              while(rs.next()){
                //Retrieve by column name
                int id  = rs.getInt("id");
                int age = rs.getInt("age");
                String first = rs.getString("first");
                String last = rs.getString("last");
                //Display values
                System.out.print("ID: " + id);
                System.out.print(", Age: " + age);
                System.out.print(", First: " + first);
                System.out.println(", Last: " + last);
              }
              //STEP 6: 清理环境
              rs.close();
              stmt.close();
              conn.close();
            }catch(SQLException se){
              //处理错误JDBC
              se.printStackTrace();
            }catch(Exception e){
              //处理错误Class.forName
              e.printStackTrace();
            }finally{
              //最后关闭资源
              try{
                if(stmt!=null)
                    stmt.close();
              }catch(SQLException se2){
              }// nothing we can do
              try{
                if(conn!=null)
                    conn.close();
              }catch(SQLException se){
                se.printStackTrace();
              }//end finally try
            }//end try
            System.out.println("Goodbye!");
        }//end main
        }//end FirstJDBCExample

现在可以通过JDK直接来编译上面的例子,当然可以在MyEclipse中完成,具体如下:

    C:\>javac FirstJDBCExample.java
    C:\>

当运行FirstJDBCExample时,会产生以下结果:

    C:\>java FirstJDBCExample
    Connecting to database…
    Creating statement…
    ID: 100, Age: 18, First: Zara, Last: Ali
    ID: 101, Age: 25, First: Mahnaz, Last: Fatma
    ID: 102, Age: 30, First: Zaid, Last: Khan
    ID: 103, Age: 28, First: Sumit, Last: Mittal
    C:\>

注:完整的JDBC使用代码及常见数据库驱动包,参见本书配套代码资料。