简单的学习JDBC

来源:互联网 发布:倒计时软件哪个好 编辑:程序博客网 时间:2024/05/21 17:00
为什么学习JDBC ?
 
     数据库编程是企业编程重要一部分,不可能不接触。在没有JDBC之前,使用的是ODBC,其实就是调用数据库厂家自己的API来做编程,可移植性差。自从有了JDBC,数据库的编程有了相对统一的编程模式。在这个基础上又有了hibernate这样的JAVA的数据持久化层,更加增加了程序可移植性。
     其实C++也有类似的框架,例如Sqlite。C++自己的问题就是可移植性差,导致现在使用C++做企业编程的人很少,Sqlite也基本没人用。至少我在C++上面使用postgresql时候都是直接调用postgresql的API。当然也可能TSC是小程序而且也没打算跨平台,那么效率和编程量就优先一些。


哪些JAVA程序使用JDBC?JDBC原理是什么?

     JDBC可以被使用在任何JAVA程序中,包括EJB、servlet、applet。在没有hibernate之前,都是手动编写JDBC程序调用SQL语句,然后使用结果集进行处理。
     一次书写,到处debug是JAVA的目标,也是JDBC的目标。JDBC封装了数据库的API,sql包中主要继承了JAVA的三部分(看书):exception、data、object。中间层使用JDBC驱动,底层还是数据库自己的协议。有些公司招聘就是招聘JDBC-ODBC驱动,主要招聘C,这个话题略过。


基本的JDBC如何使用?

     使用JDBC必须包括java.sql.*包。使用的基本流程见下。另外从这里也稍微看出来JAVA与C++的code style区别。1是{}在前导句下面;2是C++使用iterator时候使用++,而JAVA这里使用next;3是API的命名规范,第一个单词小写,后面的头一个字母大写,这也是规范的写法。可能平时我写的不规范吧。类名第一个字母就要大写。4是JAVA的class之后不需要分号,而C++的class由于与struct有关联,所以还是有分号。5是JAVA中栈上不分配对象,只有指针,所有对象都存在于堆,也就是程序中想要使用对象只有一种方法,那就是new出来。
     这个流程只是最简单的JDBC流程,另外还有认证的使用,SQL的修改等。下面也能看到JAVA面向对象的编程方法,所有的数据与操作都采用对象实现。例如con、sm、rs。如果使用C的话,就是连接、查询、使用、回写这种面向过程的想法。而在JAVA中,就是建立连接对象、使用连接对象建立上下文、使用上下文进行查询、使用查询结果、使用上下文回写结果集。
import java.sql.*
...
public class jdbcexp {
     public static void main(String args[]) {
          ...
          // 加载数据库包
          try
          {
               Class.forName("驱动公司的java包");     //import公司驱动包进来
          }
          catch(Exception e)
          {
               ...
          }
          // 连接数据库
          try
          {
               con = DriverManager.getConnection(url);     // step 1
               sm = con.createStatement();                      // step 2
               rs = sm.excuteQuarry("Sql语句");               // step 3
               while (rs.next())
               {
                    process(rs);                                         // step 4
               }
          }
          catch (SQLException e)
          {
          }
          finally
          {
               try
               {
                    rs.close();
                    sm.close();
                    con.close();                                        // step 5, 注意顺序。
               }
               catch (SQLException e)
               {}
          }
     }
}


高级JDBC使用?

     将SQL语言分布在java程序中,如上所写,不是好主意。这样有几个问题,一是移植性差,例如给oracal写的程序移植到sybase上面时候要修改SQL语句。二是控制分散在程序中,要修改逻辑会很复杂,例如现在要为querry语句加个filter,还需要在java程序中修改。
     采用分层与面向对象的思想,JDBC支持存储过程的使用。这样JDBC使用者只需要给出输入输出,同时也只关心输入输出。如果SQL工程师想要修改存储过程的逻辑,只需要修改相应的文件即可,也不需要告诉JAVA工程师。
     数据库提供两种方式的优化,一是prepared SQL,一是存储过程。PreparedStatement是Statement的子类,实现了prepared SQL,基本想法是将多个查询合并成一个查询计划。但是prepared SQL不能实现代码的分离。CallableStatement实现了存储过程,这个子类可以通过注册param与使用JDBC的存储过程的语法实现。
class jdbcexp 
{
     ...
     public void insert (Transaction tran, Student student)
     {
          try
          {
               DatabaseTransaction dbtran = (DatabaseTransaction)tran;
               Connection conn = dbtran.getConnection();
               CallableStatement stm = con.preparedCall("BEGIN
                                                                                     sp_insert students(?,?,?);
                                                                                END;");
               stm.setInt(1, student.getId());
               ...
               stm.excute();     // excute stm
               stm.close();       // close stm
               con.commit();    // commit con
               con.close();       // close con
          }
          catch (SQLException e)
          {
               e.printStackTrack();
          }
     }
}

     另一个JDBC支持的高级特性是动态存取,也就是数据持久化层的程序员并不知道上层应用会传递什么下来,也不知道应用会执行什么样的操作,JDBC采用了两种meta data实现。
     java.sql.ResultSetMetaData extand了ResultSet,通过提供结果集属性的一些信息,使得程序员能根据不同的结果采取不同的方法。java.sql.DatabaseMetaData也是extend了Connection,通过提供属性信息方式,来实现动态特性。最后如下实现了一个动态存储的示例。

import java.sql.*
/**
*    使用JDBC实现数据库基本操作:
*     commit、go(将缓冲区内容送往数据库)、quit、reset、rollback、show version
*    读程序的话从main开始向上读。
*/
class SqlAppExp {
     private bool connected;
     private Connection con;     // 其实不用初始化
     
     @method
     private void processRes(Result res)
        throw SQLException
     {
        // 这个方法是从元数据中操作SQL,基本是使用meta的API实现
        try
        {
            ResultSetMetaData meta = res.getMetaData();
            // 最终表格显示成如下形式:
            // 第一列  |   第二列
            // 值      |   值
            ...
            int cols = meta.getColumnCount();
            for (i=1; i<cols; i++)
            {
                process meta.getColumnXXX();
            }
        }
        catch
        {
        }
     }
     
     @method
     private void executeStm(String sql, Connection con)
        throw SQLException
     {
        Statement stm = null;
        try
        {
            stm = createStatement();
            if (stm.execute(sql))
            {   
                // 如果有结果集
                ProcessRes(stm.getResultSet());
            }
            else
            {
                // 如果没有结果集
                num = stm.getUpdateCount();
                ...
            }
        }
        catch (SQLException e)
        {
            throw e;
        }
        finally
        {
            if (stm != null)    // JAVA中最好不要使用C++的if(stm)这样的语句
            {
                try
                {
                    stm.close();
                }
                catch(SQLException e)
                {
                    process e ;
                }
            }
        }
     }
     
     public static void main(String args[])
     {
          // some io before
          // connect to database
          try
          {
               Class.forName(driver);     // RTTI机制
               con = DriverManage.getConnection(url, props);
          }
          catch (SQLException e)
          {
               System.out.println("Can't connect to database");
               return ;
          }
          catch (ClassNotFoundException e)
          {
               System.out.println("Missing database driver.");
               return ;
          }
          // connect OK
          System.out.println("Connection OK.");
          connected = true;
          reader = new java.io.InputStreamReader(System in);     // 与下面一起,是装饰者模式的应用
          input = new java.io.BufferReader(reader);     // 首先将system in装饰为io stream,然后装饰为buffer
          while (connected)
          {
               // omit io process
               if (cmd.equals("commit"))
               {
                    try
                    {
                         con.commit();
                    }
                    catch (SQLException e)
                    {
                         System.out.println("failed in commit");
                    }
               }
               else if (cmd.equals("go"))
               {
                    if (!buffer.equals(""))
                    {
                         try
                         {
                              executeStm(buffer, connection);
                         }
                         catch (SQLException e)
                         {
                              System.out.println(e.getMessage());
                         }
                    }
               }
               else if (cmd.equals("quit"))
               {
                    connected = false;
                    continue ;
               }
               else if (cmd.equals("reset"))
               {
                    buffer = "";     // 如果是C++程序,还要释放buffer先(SAFE_FREE(buffer)),然后再给buffer开辟新空间,C++程序员真辛苦
                    ...
                    continue ;
               }
               else if (cmd.equals("rollback"))
               {
                    try
                    {
                         con.rollback();
                    }
                    ...
               }
               else if (cmd.startsWith("show"))
               {
                    some check here;
                    DatabaseMetaData meta;
                    try
                    {
                         meta = con.getMetaData();
                         process cmd here;
                         if (cmd.equals("version"))
                         {
                              showVersion(meta);     // 这是自定义的函数
                         }
                    }
                    catch (SQLException e)
                    {
                         System.out.println("载入元数据失败," + e.getMessage());     // 这个提示比较重要
                    }
               }
               else     // 如果输入的不是命令,那么就是SQL语句,将其加入缓冲区buffer就好,这就是元数据
               {
                    buffer += input;
                    ...
                    continue;
               }
               // close connection
               try
               {
                    con.close();
               }
               catch (SQLException e)
               {
                    System.out.println("");
               }
]         }
     }
}


后续还要做什么?

     学习JDBC只是开始,了解JDBC之后才能更好的学习JAVA的数据持化技术,例如JEE、hibernate。JDBC只是提供面向大多数数据库的适配层,更高级的持久化技术还包括buffer技术、数据库优化、面向对象数据库的应用、分布式数据库的应用等。



















0 0
原创粉丝点击