zoukankan      html  css  js  c++  java
  • (二)JDBC 连接数据库

    要取得数据库连接,必须有几个操作:

     注册Driver 实现对象

     取得Connection 实现对象

     关闭Connection 实现对象

      1. 注册Driver 实现对象

      下面看一下Driver接口文档说明:

      每个驱动程序类必须实现的接口。

      Java SQL 框架允许多个数据库驱动程序。

      每个驱动程序都应该提供一个实现 Driver 接口的类。

      DriverManager 会试着加载尽可能多的它可以找到的驱动程序,然后,对于任何给定连接请求,它会让每个驱动程序依次试着连接到目标 URL。

      强烈建议每个 Driver 类应该是小型的并且是单独的,这样就可以在不必引入大量支持代码的情况下加载和查询 Driver 类。

      在加载某一 Driver 类时,它应该创建自己的实例并向 DriverManager 注册该实例。这意味着用户可以通过调用以下程序加载和注册一个驱动程序 Class.forName("foo.bah.Driver")。

      -----------------------------------------------------------------------------------------------------------------------------------------------

      这意味着当加载了实现Driver接口的类的时候,它将会自动调用DriverManager. registerDriver()方法,将该驱动注册到驱动管理器当中去。下面是mysql驱动实现类的部分代码:

      

    View Code
    public class Driver extends NonRegisteringDriver
    implements java.sql.Driver {
    static {
    try {
    java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
    throw new RuntimeException("Can't register driver!");
    }
    }
    }

      可以看出,在static 区块中进行了注册Driver 实例的操作,而static 区块会在加载.class 文件时执行。使用JDBC 时,要求加载.class 文件的方式有四种:

      (1) 使用Class.forName()。

      (2) 自行创建Driver 接口实现类的实例。

      (3) 启动JVM 时指定jdbc.drivers 属性。

      (4) 设置JAR 中 /services/java.sql.Driver 文件。

      第一种方式刚才已经说明。第二种方式就是直接编写代码:

      java.sql.Driver driver = new com.mysql.jdbc.Driver();

      由于创建对象属于对类的主动使用,会自动加载类的class文件,自然也就会运行类的静态区块完成驱动程序注册。

      第三种方式就是运行java 命令时如下:

      > java –Djdbc.drivers=com.mysql.jdbc.Driver;ooo.XXXDriver

      你的应用程序可能同时连接多个厂商的数据库,所以DriverManager 也可以注册多个驱动程序实例。以上方式如果需要指定多个驱动程序类时,就是用分号隔开。

      第四种方式则是Java SE 6 之后JDBC 4.0 的新特性,只要在驱动程序实现的JAR文件/services 文件夹中,放置一个java.sql.Driver 文件,当中编写Driver 接口的实现类名称全名,DriverManager 会自动读取这个文件并找到指定类进行注册。

    首先看一下DriverManager的registerDriver方法:

    View Code
    public static synchronized void registerDriver(java.sql.Driver driver)
        throws SQLException {
        if (!initialized) {
            initialize();
        }
         // DriverInfo的一个存放Driver信息的实体类有3个属性
         // Driver         driver;
        //Class          driverClass;
        //String         driverClassName;
        DriverInfo di = new DriverInfo();
        
        di.driver = driver;
        di.driverClass = driver.getClass();
        di.driverClassName = di.driverClass.getName();
    
        // Not Required -- drivers.addElement(di);
    
        writeDrivers.addElement(di); 
        println("registerDriver: " + di);
        
        /* update the read copy of drivers vector */
        readDrivers = (java.util.Vector) writeDrivers.clone();
    
        }

      initialized静态变量表示是否初始化过驱动。

      下面是initialize()方法 的具体内容:

    View Code
    static void initialize() {
    
            if (initialized) {
    
                return;
    
            }
    
            initialized = true;
    
            loadInitialDrivers();
    
            println("JDBC DriverManager initialized");
    
        }

      如果initialized为真的时候直接return,如果为假则加载驱动执行

      loadInitialDrivers方法:

    View Code
    private static void loadInitialDrivers() {
    
            String drivers;
    
            try {
    
           drivers = (String) java.security.AccessController.doPrivileged(
    
          new sun.security.action.GetPropertyAction("jdbc.drivers"));
    
            } catch (Exception ex) {
    
                drivers = null;
    
    //如果不指定系统的jdbc.drivers的时候drivers值设置为null
    
            }
    
          
    
        DriverService ds = new DriverService();
    
        java.security.AccessController.doPrivileged(ds);   
    
              
    
             println("DriverManager.initialize: jdbc.drivers = " + drivers);
    
            if (drivers == null) {
    
             //此时如果drivers为null直接返回
    
                return;
    
            }
    
          //当drivers不为null的时候,截取驱动类全名,并且反射加载设置的驱动
    
            while (drivers.length() != 0) {
    
                int x = drivers.indexOf(':');
    
                String driver;
    
                if (x < 0) {
    
                    driver = drivers;
    
                    drivers = "";
    
                } else {
    
                    driver = drivers.substring(0, x);
    
                    drivers = drivers.substring(x+1);
    
                }
    
                if (driver.length() == 0) {
    
                    continue;
    
                }
    
                try {
    
                    println("DriverManager.Initialize: loading " + driver);
    
                    Class.forName(driver, true,
    
                   ClassLoader.getSystemClassLoader());
    
                } catch (Exception ex) {
    
                    println("DriverManager.Initialize: load failed: " + ex);
    
                }
    
            }
    
        }

      registerDriver方法的下半部分:

      writeDrivers.addElement(di);

      readDrivers = (java.util.Vector) writeDrivers.clone();

      下面是writeDrivers和readDrivers的定义

      private static java.util.Vector writeDrivers = new java.util.Vector();

      private static java.util.Vector readDrivers = new java.util.Vector();

      将驱动存放在Vector当中。

      2.  取得Connection 实现对象

      Connection 接口的实现对象,是数据库连接代表对象。要取得Connection 实现对象,可以通过DriverManager 的getConnection():

      Connection conn = DriverManager.getConnection(jdbcUrl, username, password);除了基本的用户名、密码之外,还必须提供JDBC URL,其定义了连接数据库协议、子协议、数据源标识。

      实际上除了“协议”在JDBC URL 中总是jdbc 开始之外,JDBC URL 格式各家数据库都不相同,必须查询数据库产品使用手册。以MySQL 为例,“子协议”是桥接的驱动程序、数据库产品名称或连接机制。例如,若使用MySQL,子协议名称是 mysql。“数据源标识”标出数据库的地址、端口、名称、用户、密码等信息。举个例子来说,MySQL 的JDBC URL 编写方式如下:

      jdbc:mysql://主机名称:连接端口/数据库名称?参数=值&参数=值

      主机名称可以是本机(localhost)或其他连接主机名称、地址,MySQL 连接端口默认为3306。例如,要连接demo 数据库,并指明用户名与密码,可以这样指定:

      jdbc:mysql://localhost:3306/demo?user=root&password=123456

      如果要使用中文访问,还必须给定参数useUnicode 及characterEncoding,表

      明是否使用Unicode,并指定字符编码方式。例如(假设数据库表格编码使用UTF8):

      jdbc:mysql://localhost:3306/demo?user=root&password=123&useUnicode=true&characterEncoding=UTF8

      如果要直接通过DriverManager 的getConnection()连接数据库,一个比较完整的代码段如下:

    View Code
    private static String url = "jdbc:oracle:thin:@127.0.0.1:1521:ORCL";
    
        private static String user = "scott";
    
        private static String password = "tiger";
    
     
    
        public static Connection createconn()
    
        {
    
            Connection connection = null;
    
            try
    
            {
    
                Class.forName("oracle.jdbc.driver.OracleDriver");
    
                connection = DriverManager.getConnection(url, user, password);
    
            }
    
            catch (ClassNotFoundException e)
    
            {
    
                e.printStackTrace();
    
            }
    
            catch (SQLException e)
    
            {
    
                e.printStackTrace();
    
            }
    
            return connection;
    
        }

      SQLException 是在处理JDBC 时经常遇到的一个异常对象,为数据库操作过程发生错误时的代表对象。SQLException 是检查异常(Checked Exception) , 必须使用try...catch 明确处理,在异常发生时尝试关闭相关资源。

      下面让我们看一下DriverManager的getConnection的全过程以便于更加了解JDBC的获取连接。

      下面是getConnection()方法代码:

      getConnection()方法有3个重载方法,我们选3个参数的方法进行分析,别的方法基本类似。

    View Code
    public static Connection getConnection(String url,
    
       String user, String password) throws SQLException {
    
            java.util.Properties info = new java.util.Properties();
    
       ClassLoader callerCL = DriverManager.getCallerClassLoader();
    
     
    
       if (user != null) {
    
           info.put("user", user);
    
       }
    
       if (password != null) {
    
           info.put("password", password);
    
       }
    
    //以上操作是将user和password加入到info配置当中
    
            return (getConnection(url, info, callerCL));
    
        }

      下面是getConnection()重载的私有方法部分代码

    View Code
    private static Connection getConnection(
    
       String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
    
       java.util.Vector drivers = null;
    
       
    
       省略一些代码
    
     
    
       synchronized (DriverManager.class){
    
                // 将克隆出来的赋值给drivers
    
           drivers = readDrivers; 
    
            }
    
     
    
       SQLException reason = null;
    
       for (int i = 0; i < drivers.size(); i++) {
    
           DriverInfo di = (DriverInfo)drivers.elementAt(i);
    
         
    
           // 如果该驱动不能被加载则跳过它.
    
           if ( getCallerClass(callerCL, di.driverClassName ) != di.driverClass ) {
    
          println("    skipping: " + di);
    
          continue;
    
           }
    
           try {
    
          println("    trying " + di);
    
          Connection result = di.driver.connect(url, info);
    
          if (result != null) {
    
              // Success!
    
              println("getConnection returning " + di);
    
              return (result);
    
          }
    
           } catch (SQLException ex) {
    
          if (reason == null) {
    
              reason = ex;
    
          }
    
           }
    
       }
    
       
    
       省略一些代码

      可以看出主要是循环遍历drivers,并且看具体driver的connect方法返回结果,如果不为null则直接返回。

      由于DriverManager 可以注册多个驱动,这样就需要解决如何找到正确的驱动进行解析URL。每个 JDBC 驱动程序使用一个专门的 JDBC URL作为自我标识的一种方法,所以循环遍历drivers就可以找到正确的驱动进行解析URL,如果都没有则会抛出异常。

      3. 关闭Connection 实现对象

      取得Connection 对象之后,可以使用isClosed()方法测试与数据库的连接是否关闭。在操作完数据库之后,若确定不再需要连接,则必须使用close()来关闭与数据库的连接,以释放连接时相关的必要资源,如连接相关对象、授权资源等。

  • 相关阅读:
    HDOJ1003 MaxSum【逆推】
    HDOJ1698 Just a hook【线段树成段更新lazy标志】武科大ACM暑期集训队选拔赛4题
    HDOJ1102 Constructing Roads【最小生成树】武科大ACM暑期集训队选拔赛1题
    POJ2828 Buy Tickets【线段树,逆序遍历】
    HDOJ1215 ( 七夕节 )【居然还可以这么解~】
    HDOJ1089HDOJ1096【格式练习】
    HDOJ1233 ( 还是畅通工程 ) 【最小生成树,kruscal】
    HDOJ1035 ( Robot Motion ) 【递归】
    POJ3468 A Simple Problem with Integers【线段树 成段更新+求和 lazy标志】
    HDOJ1216 Assistance Required【打表】武科大ACM暑期集训队选拔赛7题
  • 原文地址:https://www.cnblogs.com/renchunxiao/p/3009390.html
Copyright © 2011-2022 走看看