读书人

范例分析MySQL JDBC驱动

发布时间: 2012-09-16 17:33:16 作者: rapoo

实例分析MySQL JDBC驱动

http://developer.51cto.com/art/200907/137823.htm

MySQL是一个中小型关系型数据库管理系统,目前使用的也比较广泛。为了对开发中间DAO层的问题能有更深的理解,在遇到问题的时候能够有更多的思路,于是研究了一下MySQL JDBC驱动的使用,并且在这过程中也发现了一直以来关于PreparedStatement常识理解上的错误,与大家分享。

?

  • public?class?DBHelper?{??? ?
      public?class?DBHelper?{??? ?
    1. ????public?static?Connection?getConnection()?{??? ?
    1. public?static?Connection?getConnection()?{??? ?
    1. ????????Connection?conn?=?null;??? ?
      ????????Connection?conn?=?null;??? ?
    1. ????????try?{??? ?
    1. try?{??? ?
    1. ????????????Class.forName("com.mysql.jdbc.Driver");??? ?
      ????????????Class.forName("com.mysql.jdbc.Driver");??? ?
    1. ????????????conn?=?DriverManager.getConnection("jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false",??? ?
    1. "jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false",??? ?
    1. ????????????????????"root",?"root");??? ?
      ????????????????????"root",?"root");??? ?
    1. ????????}?catch?(Exception?e)?{??? ?
    1. catch?(Exception?e)?{??? ?
    1. ????????????e.printStackTrace();??? ?
    1. ????????????e.printStackTrace();??? ?
    1. ????????}??? ?
    1. ????????}??? ?
    1. ????????return?conn;??? ?
      ????????return?conn;??? ?
    1. ????}??? ?
    1. ????}??? ?
    1. }??? ?
    1. }??? ?
    1. ?? ?
    1. ?? ?
    1. ????????/*dao中的方法*/?? ?
      ????????/*dao中的方法*/?? ?
    1. ????public?List?getAllAdvs()?{??? ?
    1. public?List?getAllAdvs()?{??? ?
    1. ??????????? ?
    1. ??????????? ?
    1. ????????Connection?conn?=?null;??? ?
    1. null;??? ?
    1. ????????ResultSet?rs?=?null;??? ?
      ????????ResultSet?rs?=?null;??? ?
    1. ????????PreparedStatement?stmt?=?null;??? ?
    1. null;??? ?
    1. ????????String?sql?=?"select?*?from?adv?where?id?=??";??? ?
      ????????String?sql?=?"select?*?from?adv?where?id?=??";??? ?
    1. ????????List?advs?=?new?ArrayList();??? ?
    1. new?ArrayList();??? ?
    1. ?? ?
    1. ?? ?
    1. ????????conn?=?DBHelper.getConnection();??? ?
    1. ????????conn?=?DBHelper.getConnection();??? ?
    1. ????????if?(conn?!=?null)?{??? ?
      ????????if?(conn?!=?null)?{??? ?
    1. ????????????try?{??? ?
    1. try?{??? ?
    1. ????????????????stmt?=?conn.prepareStatement(sql);??? ?
    1. ????????????????stmt?=?conn.prepareStatement(sql);??? ?
    1. ????????????????????????????????stmt.setInt(1,?new?Integer(1));??? ?
    1. 1,?new?Integer(1));??? ?
    1. ????????????????rs?=?stmt.executeQuery();??? ?
    1. ????????????????rs?=?stmt.executeQuery();??? ?
    1. ?? ?
    1. ?? ?
    1. ????????????????if?(rs?!=?null)?{??? ?
      ????????????????if?(rs?!=?null)?{??? ?
    1. ????????????????????while?(rs.next())?{??? ?
    1. while?(rs.next())?{??? ?
    1. ????????????????????????Adv?adv?=?new?Adv();??? ?
      ????????????????????????Adv?adv?=?new?Adv();??? ?
    1. ????????????????????????adv.setId(rs.getLong(1));??? ?
    1. 1));??? ?
    1. ????????????????????????adv.setName(rs.getString(2));??? ?
      ????????????????????????adv.setName(rs.getString(2));??? ?
    1. ????????????????????????adv.setDesc(rs.getString(3));??? ?
    1. 3));??? ?
    1. ????????????????????????adv.setPicUrl(rs.getString(4));??? ?
      ????????????????????????adv.setPicUrl(rs.getString(4));??? ?
    1. ?? ?
    1. ?? ?
    1. ????????????????????????advs.add(adv);??? ?
    1. ????????????????????????advs.add(adv);??? ?
    1. ????????????????????}??? ?
    1. ????????????????????}??? ?
    1. ????????????????}??? ?
    1. ????????????????}??? ?
    1. ????????????}?catch?(SQLException?e)?{??? ?
    1. catch?(SQLException?e)?{??? ?
    1. ????????????????e.printStackTrace();??? ?
    1. ????????????????e.printStackTrace();??? ?
    1. ????????????}?finally?{??? ?
    1. finally?{??? ?
    1. ????????????????try?{??? ?
      ????????????????try?{??? ?
    1. ????????????????????stmt.close();??? ?
    1. ????????????????????stmt.close();??? ?
    1. ????????????????????conn.close();??? ?
    1. ????????????????????conn.close();??? ?
    1. ????????????????}?catch?(SQLException?e)?{??? ?
    1. catch?(SQLException?e)?{??? ?
    1. ????????????????????e.printStackTrace();??? ?
    1. ????????????????????e.printStackTrace();??? ?
    1. ????????????????}??? ?
    1. ????????????????}??? ?
    1. ????????????}??? ?
    1. ????????????}??? ?
    1. ????????}??? ?
    1. ????????}??? ?
    1. ????????return?advs;??? ?
      ????????return?advs;??? ?
    1. ????}?? ?
    1. ????}?? ?
    1. public?class?DBHelper?{ ?
      public?class?DBHelper?{ ?
    1. ?public?static?Connection?getConnection()?{ ?
    1. public?static?Connection?getConnection()?{ ?
    1. ??Connection?conn?=?null; ?
      ??Connection?conn?=?null; ?
    1. ??try?{ ?
    1. try?{ ?
    1. ???Class.forName("com.mysql.jdbc.Driver"); ?
      ???Class.forName("com.mysql.jdbc.Driver"); ?
    1. ???conn?=?DriverManager.getConnection("jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false", ?
    1. "jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false", ?
    1. ?????"root",?"root"); ?
      ?????"root",?"root"); ?
    1. ??}?catch?(Exception?e)?{ ?
    1. catch?(Exception?e)?{ ?
    1. ???e.printStackTrace(); ?
    1. ???e.printStackTrace(); ?
    1. ??} ?
    1. ??} ?
    1. ??return?conn; ?
      ??return?conn; ?
    1. ?} ?
    1. ?} ?
    1. } ?
    1. } ?
    1. ?
    1. ?
    1. ????????/*dao中的方法*/?
      ????????/*dao中的方法*/?
    1. ?public?List?getAllAdvs()?{ ?
    1. public?List?getAllAdvs()?{ ?
    1. ?? ?
    1. ?? ?
    1. ??Connection?conn?=?null; ?
    1. null; ?
    1. ??ResultSet?rs?=?null; ?
      ??ResultSet?rs?=?null; ?
    1. ??PreparedStatement?stmt?=?null; ?
    1. null; ?
    1. ??String?sql?=?"select?*?from?adv?where?id?=??"; ?
      ??String?sql?=?"select?*?from?adv?where?id?=??"; ?
    1. ??List?advs?=?new?ArrayList(); ?
    1. new?ArrayList(); ?
    1. ?
    1. ?
    1. ??conn?=?DBHelper.getConnection(); ?
    1. ??conn?=?DBHelper.getConnection(); ?
    1. ??if?(conn?!=?null)?{ ?
      ??if?(conn?!=?null)?{ ?
    1. ???try?{ ?
    1. try?{ ?
    1. ????stmt?=?conn.prepareStatement(sql); ?
    1. ????stmt?=?conn.prepareStatement(sql); ?
    1. ????????????????????????????????stmt.setInt(1,?new?Integer(1)); ?
    1. 1,?new?Integer(1)); ?
    1. ????rs?=?stmt.executeQuery(); ?
    1. ????rs?=?stmt.executeQuery(); ?
    1. ?
    1. ?
    1. ????if?(rs?!=?null)?{ ?
      ????if?(rs?!=?null)?{ ?
    1. ?????while?(rs.next())?{ ?
    1. while?(rs.next())?{ ?
    1. ??????Adv?adv?=?new?Adv(); ?
      ??????Adv?adv?=?new?Adv(); ?
    1. ??????adv.setId(rs.getLong(1)); ?
    1. 1)); ?
    1. ??????adv.setName(rs.getString(2)); ?
      ??????adv.setName(rs.getString(2)); ?
    1. ??????adv.setDesc(rs.getString(3)); ?
    1. 3)); ?
    1. ??????adv.setPicUrl(rs.getString(4)); ?
      ??????adv.setPicUrl(rs.getString(4)); ?
    1. ?
    1. ?
    1. ??????advs.add(adv); ?
    1. ??????advs.add(adv); ?
    1. ?????} ?
    1. ?????} ?
    1. ????} ?
    1. ????} ?
    1. ???}?catch?(SQLException?e)?{ ?
    1. catch?(SQLException?e)?{ ?
    1. ????e.printStackTrace(); ?
    1. ????e.printStackTrace(); ?
    1. ???}?finally?{ ?
    1. finally?{ ?
    1. ????try?{ ?
      ????try?{ ?
    1. ?????stmt.close(); ?
    1. ?????stmt.close(); ?
    1. ?????conn.close(); ?
    1. ?????conn.close(); ?
    1. ????}?catch?(SQLException?e)?{ ?
    1. catch?(SQLException?e)?{ ?
    1. ?????e.printStackTrace(); ?
    1. ?????e.printStackTrace(); ?
    1. ????} ?
    1. ????} ?
    1. ???} ?
    1. ???} ?
    1. ??} ?
    1. ??} ?
    1. ??return?advs; ?
      ??return?advs; ?
    1. ?}?
    1. ?}?
      1. public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{??? ?
        public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{??? ?
      1. ????static?{??? ?
      1. static?{??? ?
      1. ????????try?{??? ?
        ????????try?{??? ?
      1. ????????????java.sql.DriverManager.registerDriver(new?Driver());??? ?
      1. new?Driver());??? ?
      1. ????????}?catch?(SQLException?E)?{??? ?
        ????????}?catch?(SQLException?E)?{??? ?
      1. ????????????throw?new?RuntimeException("Can't?register?driver!");??? ?
      1. throw?new?RuntimeException("Can't?register?driver!");??? ?
      1. ????????}??? ?
      1. ????????}??? ?
      1. ????}??? ?
      1. ????}??? ?
      1. ????public?Driver()?throws?SQLException?{??? ?
        ????public?Driver()?throws?SQLException?{??? ?
      1. ????}??? ?
      1. ????}??? ?
      1. }?? ?
      1. }?? ?
      1. public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{ ?
      1. public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{ ?
      1. ?static?{ ?
        ?static?{ ?
      1. ??try?{ ?
      1. try?{ ?
      1. ???java.sql.DriverManager.registerDriver(new?Driver()); ?
        ???java.sql.DriverManager.registerDriver(new?Driver()); ?
      1. ??}?catch?(SQLException?E)?{ ?
      1. catch?(SQLException?E)?{ ?
      1. ???throw?new?RuntimeException("Can't?register?driver!"); ?
        ???throw?new?RuntimeException("Can't?register?driver!"); ?
      1. ??} ?
      1. ??} ?
      1. ?} ?
      1. ?} ?
      1. ?public?Driver()?throws?SQLException?{ ?
      1. public?Driver()?throws?SQLException?{ ?
      1. ?} ?
      1. ?} ?
      1. }?
      1. }?
        1. ???public?static?synchronized?void?registerDriver(java.sql.Driver?driver)??? ?
          ???public?static?synchronized?void?registerDriver(java.sql.Driver?driver)??? ?
        1. throws?SQLException?{??? ?
        1. throws?SQLException?{??? ?
        1. if?(!initialized)?{??? ?
          if?(!initialized)?{??? ?
        1. ????initialize();??? ?
        1. ????initialize();??? ?
        1. }?????????? ?
        1. }?????????? ?
        1. DriverInfo?di?=?new?DriverInfo();???? ?
        1. new?DriverInfo();???? ?
        1. ??/*把driver的信息封装一下,组成一个DriverInfo对象*/?? ?
          ??/*把driver的信息封装一下,组成一个DriverInfo对象*/?? ?
        1. di.driver?=?driver;??? ?
        1. di.driver?=?driver;??? ?
        1. di.driverClass?=?driver.getClass();??? ?
        1. di.driverClass?=?driver.getClass();??? ?
        1. di.driverClassName?=?di.driverClass.getName();????? ?
        1. di.driverClassName?=?di.driverClass.getName();????? ?
        1. writeDrivers.addElement(di);???? ?
        1. writeDrivers.addElement(di);???? ?
        1. println("registerDriver:?"?+?di);???? ?
        1. "registerDriver:?"?+?di);???? ?
        1. readDrivers?=?(java.util.Vector)?writeDrivers.clone();???? ?
        1. readDrivers?=?(java.util.Vector)?writeDrivers.clone();???? ?
        1. ???}?? ?
        1. ???}?? ?
        1. ????public?static?synchronized?void?registerDriver(java.sql.Driver?driver) ?
          ????public?static?synchronized?void?registerDriver(java.sql.Driver?driver) ?
        1. ?throws?SQLException?{ ?
        1. throws?SQLException?{ ?
        1. ?if?(!initialized)?{ ?
          ?if?(!initialized)?{ ?
        1. ?????initialize(); ?
        1. ?????initialize(); ?
        1. ?}?????? ?
        1. ?}?????? ?
        1. ?DriverInfo?di?=?new?DriverInfo(); ?
        1. new?DriverInfo(); ?
        1. ???/*把driver的信息封装一下,组成一个DriverInfo对象*/?
          ???/*把driver的信息封装一下,组成一个DriverInfo对象*/?
        1. ?di.driver?=?driver; ?
        1. ?di.driver?=?driver; ?
        1. ?di.driverClass?=?driver.getClass(); ?
        1. ?di.driverClass?=?driver.getClass(); ?
        1. ?di.driverClassName?=?di.driverClass.getName(); ?
        1. ?di.driverClassName?=?di.driverClass.getName(); ?
        1. ?
        1. ?
        1. ?writeDrivers.addElement(di);? ?
        1. ?writeDrivers.addElement(di);? ?
        1. ?println("registerDriver:?"?+?di); ?
          ?println("registerDriver:?"?+?di); ?
        1. ?readDrivers?=?(java.util.Vector)?writeDrivers.clone(); ?
        1. ?readDrivers?=?(java.util.Vector)?writeDrivers.clone(); ?
        1. ?
        1. ?
        1. ????}?
        1. ????}?
          至于驱动的集合writeDrivers和readDrivers,很有趣的是,无论是registerDriver还是deregisterDriver,都是先对writeDrivers中的数据进行添加或者删除,然后再把writeDrivers中的驱动都拷贝到readDrivers中,但每次取出driver却从来不从writeDrivers中取,都是通过readDrivers来获得。我认为可以这样理解,writeDrivers只负责注册driver与注销driver,而readDrivers只负责提供可用的driver,只有当writeDrivers中准备好了驱动,这些驱动才是可以使用的,所以才能被copy至readDrivers中以备使用。这样一来,对内的注册注销与对外的提供使用就分开来了。
          1. ???private?static?Connection?getConnection(??? ?
            ???private?static?Connection?getConnection(??? ?
          1. String?url,?java.util.Properties?info,?ClassLoader?callerCL)?throws?SQLException?{??? ?
          1. throws?SQLException?{??? ?
          1. java.util.Vector?drivers?=?null;??? ?
            java.util.Vector?drivers?=?null;??? ?
          1. ...??? ?
          1. ...??? ?
          1. if?(!initialized)?{??? ?
            if?(!initialized)?{??? ?
          1. ????initialize();??? ?
          1. ????initialize();??? ?
          1. }??? ?
          1. }??? ?
          1. ???/*取得连接使用的driver从readDrivers中取*/?? ?
          1. /*取得连接使用的driver从readDrivers中取*/?? ?
          1. synchronized?(DriverManager.class){???? ?
            synchronized?(DriverManager.class){???? ?
          1. ????drivers?=?readDrivers;????? ?
          1. ????drivers?=?readDrivers;????? ?
          1. ???????}??? ?
          1. ???????}??? ?
          1. ?? ?
          1. ?? ?
          1. SQLException?reason?=?null;??? ?
            SQLException?reason?=?null;??? ?
          1. for?(int?i?=?0;?i?<?drivers.size();?i++)?{??? ?
          1. for?(int?i?=?0;?i?<?drivers.size();?i++)?{??? ?
          1. ????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i);??? ?
          1. ????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i);??? ?
          1. ???????? ?
          1. ???????? ?
          1. ????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{??? ?
            ????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{??? ?
          1. ????continue;??? ?
          1. continue;??? ?
          1. ????}??? ?
          1. ????}??? ?
          1. ????try?{??? ?
          1. try?{??? ?
          1. ???????/*找到可供使用的驱动,连接数据库server*/?? ?
            ???????/*找到可供使用的驱动,连接数据库server*/?? ?
          1. ????Connection?result?=?di.driver.connect(url,?info);??? ?
          1. ????Connection?result?=?di.driver.connect(url,?info);??? ?
          1. ????if?(result?!=?null)?{??? ?
            ????if?(result?!=?null)?{??? ?
          1. ????????return?(result);??? ?
          1. return?(result);??? ?
          1. ????}??? ?
          1. ????}??? ?
          1. ????}?catch?(SQLException?ex)?{??? ?
          1. catch?(SQLException?ex)?{??? ?
          1. ????if?(reason?==?null)?{??? ?
            ????if?(reason?==?null)?{??? ?
          1. ????????reason?=?ex;??? ?
          1. ????????reason?=?ex;??? ?
          1. ????}??? ?
          1. ????}??? ?
          1. ????}??? ?
          1. ????}??? ?
          1. }??? ?
          1. }??? ?
          1. ?????? ?
          1. ?????? ?
          1. if?(reason?!=?null)????{??? ?
            if?(reason?!=?null)????{??? ?
          1. ????println("getConnection?failed:?"?+?reason);??? ?
          1. "getConnection?failed:?"?+?reason);??? ?
          1. ????throw?reason;??? ?
            ????throw?reason;??? ?
          1. }??????? ?
          1. }??????? ?
          1. throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001");??? ?
            throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001");??? ?
          1. ???}?? ?
          1. ???}?? ?
          1. ????private?static?Connection?getConnection( ?
            ????private?static?Connection?getConnection( ?
          1. ?String?url,?java.util.Properties?info,?ClassLoader?callerCL)?throws?SQLException?{ ?
          1. throws?SQLException?{ ?
          1. ?java.util.Vector?drivers?=?null; ?
            ?java.util.Vector?drivers?=?null; ?
          1. ?... ?
          1. ?... ?
          1. ?if?(!initialized)?{ ?
            ?if?(!initialized)?{ ?
          1. ?????initialize(); ?
          1. ?????initialize(); ?
          1. ?} ?
          1. ?} ?
          1. ????/*取得连接使用的driver从readDrivers中取*/?
          1. /*取得连接使用的driver从readDrivers中取*/?
          1. ?synchronized?(DriverManager.class){? ?
            ?synchronized?(DriverManager.class){? ?
          1. ?????drivers?=?readDrivers;?? ?
          1. ?????drivers?=?readDrivers;?? ?
          1. ????????} ?
          1. ????????} ?
          1. ?
          1. ?
          1. ?SQLException?reason?=?null; ?
            ?SQLException?reason?=?null; ?
          1. ?for?(int?i?=?0;?i?<?drivers.size();?i++)?{ ?
          1. for?(int?i?=?0;?i?<?drivers.size();?i++)?{ ?
          1. ?????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i); ?
          1. ?????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i); ?
          1. ?????? ?
          1. ?????? ?
          1. ?????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{ ?
            ?????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{ ?
          1. ??continue; ?
          1. continue; ?
          1. ?????} ?
          1. ?????} ?
          1. ?????try?{ ?
          1. try?{ ?
          1. ????????/*找到可供使用的驱动,连接数据库server*/?
            ????????/*找到可供使用的驱动,连接数据库server*/?
          1. ??Connection?result?=?di.driver.connect(url,?info); ?
          1. ??Connection?result?=?di.driver.connect(url,?info); ?
          1. ??if?(result?!=?null)?{ ?
            ??if?(result?!=?null)?{ ?
          1. ??????return?(result); ?
          1. return?(result); ?
          1. ??} ?
          1. ??} ?
          1. ?????}?catch?(SQLException?ex)?{ ?
          1. catch?(SQLException?ex)?{ ?
          1. ??if?(reason?==?null)?{ ?
            ??if?(reason?==?null)?{ ?
          1. ??????reason?=?ex; ?
          1. ??????reason?=?ex; ?
          1. ??} ?
          1. ??} ?
          1. ?????} ?
          1. ?????} ?
          1. ?} ?
          1. ?} ?
          1. ???? ?
          1. ???? ?
          1. ?if?(reason?!=?null)????{ ?
            ?if?(reason?!=?null)????{ ?
          1. ?????println("getConnection?failed:?"?+?reason); ?
          1. "getConnection?failed:?"?+?reason); ?
          1. ?????throw?reason; ?
            ?????throw?reason; ?
          1. ?}???? ?
          1. ?}???? ?
          1. ?throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001"); ?
            ?throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001"); ?
          1. ????}?
          1. ????}?
            1. public?java.sql.Connection?connect(String?url,?Properties?info)??? ?
              public?java.sql.Connection?connect(String?url,?Properties?info)??? ?
            1. ????????throws?SQLException?{??? ?
            1. throws?SQLException?{??? ?
            1. ????Properties?props?=?null;??? ?
              ????Properties?props?=?null;??? ?
            1. ????if?((props?=?parseURL(url,?info))?==?null)?{??? ?
            1. if?((props?=?parseURL(url,?info))?==?null)?{??? ?
            1. ????????return?null;??? ?
              ????????return?null;??? ?
            1. ????}??? ?
            1. ????}??? ?
            1. ?? ?
            1. ?? ?
            1. ????try?{??? ?
            1. try?{??? ?
            1. ????????Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props),??? ?
              ????????Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props),??? ?
            1. ????????????????port(props),?props,?database(props),?url);??? ?
            1. ????????????????port(props),?props,?database(props),?url);??? ?
            1. ?? ?
            1. ?? ?
            1. ????????return?newConn;??? ?
            1. return?newConn;??? ?
            1. ????}?catch?(SQLException?sqlEx)?{??? ?
              ????}?catch?(SQLException?sqlEx)?{??? ?
            1. ????????throw?sqlEx;??? ?
            1. throw?sqlEx;??? ?
            1. ????}?catch?(Exception?ex)?{??? ?
              ????}?catch?(Exception?ex)?{??? ?
            1. ????????throw?SQLError.createSQLException(...);??? ?
            1. throw?SQLError.createSQLException(...);??? ?
            1. ????}??? ?
            1. ????}??? ?
            1. }?? ?
            1. }?? ?
            1. ?public?java.sql.Connection?connect(String?url,?Properties?info) ?
              ?public?java.sql.Connection?connect(String?url,?Properties?info) ?
            1. ???throws?SQLException?{ ?
            1. throws?SQLException?{ ?
            1. ??Properties?props?=?null; ?
              ??Properties?props?=?null; ?
            1. ??if?((props?=?parseURL(url,?info))?==?null)?{ ?
            1. if?((props?=?parseURL(url,?info))?==?null)?{ ?
            1. ???return?null; ?
              ???return?null; ?
            1. ??} ?
            1. ??} ?
            1. ?
            1. ?
            1. ??try?{ ?
            1. try?{ ?
            1. ???Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props), ?
              ???Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props), ?
            1. ?????port(props),?props,?database(props),?url); ?
            1. ?????port(props),?props,?database(props),?url); ?
            1. ?
            1. ?
            1. ???return?newConn; ?
            1. return?newConn; ?
            1. ??}?catch?(SQLException?sqlEx)?{ ?
              ??}?catch?(SQLException?sqlEx)?{ ?
            1. ???throw?sqlEx; ?
            1. throw?sqlEx; ?
            1. ??}?catch?(Exception?ex)?{ ?
              ??}?catch?(Exception?ex)?{ ?
            1. ???throw?SQLError.createSQLException(...); ?
            1. throw?SQLError.createSQLException(...); ?
            1. ??} ?
            1. ??} ?
            1. ?}?
            1. ?}?
              2、PreparedStatement stmt = conn.prepareStatement(sql);使用得到的connection创建一个Statement。Statement有许多种,我们常用的就是PreparedStatement,用于执行预编译好的SQL语句,CallableStatement用于调用数据库的存储过程。它们的继承关系如下图所示。Java代码?public java.sql.PreparedStatement prepareStatement(String sql)???throws SQLException {???return prepareStatement(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY,???java.sql.ResultSet.CONCUR_READ_ONLY);???}???
              public java.sql.PreparedStatement prepareStatement(String sql,???
              int resultSetType, int resultSetConcurrency) throws SQLException;??
              public java.sql.PreparedStatement prepareStatement(String sql)
              throws SQLException {
              return prepareStatement(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY,
              java.sql.ResultSet.CONCUR_READ_ONLY);
              }public java.sql.PreparedStatement prepareStatement(String sql,???int resultSetType, int resultSetConcurrency) throws SQLException;??public java.sql.PreparedStatement prepareStatement(String sql)throws SQLException {return prepareStatement(sql, java.sql.ResultSet.TYPE_FORWARD_ONLY,java.sql.ResultSet.CONCUR_READ_ONLY);}int resultSetType, int resultSetConcurrency) throws SQLException;ResultSet中的参数常量主要有以下几种:?
              1. TYPE_SCROLL_INSENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变不敏感。? ?
              1. TYPE_SCROLL_INSENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变不敏感。? ?
              1. TYPE_SCROLL_SENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变是敏感的。? ?
              1. TYPE_SCROLL_SENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变是敏感的。? ?
              1. CONCUR_READ_ONLY:不可以更新的ResultSet的并发模式。? ?
              1. CONCUR_READ_ONLY:不可以更新的ResultSet的并发模式。? ?
              1. CONCUR_UPDATABLE:可以更新的ResultSet的并发模式。? ?
              1. CONCUR_UPDATABLE:可以更新的ResultSet的并发模式。? ?
              1. FETCH_FORWARD:按正向(即从第一个到最后一个)处理结果集中的行。? ?
              1. FETCH_FORWARD:按正向(即从第一个到最后一个)处理结果集中的行。? ?
              1. FETCH_REVERSE:按反向(即从最后一个到第一个)处理结果集中的行处理。? ?
              1. FETCH_REVERSE:按反向(即从最后一个到第一个)处理结果集中的行处理。? ?
              1. FETCH_UNKNOWN:结果集中的行的处理顺序未知。? ?
              1. FETCH_UNKNOWN:结果集中的行的处理顺序未知。? ?
              1. CLOSE_CURSORS_AT_COMMIT:调用Connection.commit方法时应该关闭?ResultSet?对? ?
              1. CLOSE_CURSORS_AT_COMMIT:调用Connection.commit方法时应该关闭?ResultSet?对? ?
              1. HOLD_CURSORS_OVER_COMMIT:调用Connection.commit方法时不应关闭ResultSet对象。?
              1. HOLD_CURSORS_OVER_COMMIT:调用Connection.commit方法时不应关闭ResultSet对象。?
                3、stmt.setInt(1, new Integer(1));4、ResultSet rs = stmt.executeQuery(); 一切准备就绪,开始执行查询罗!
                1. ????protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings,??? ?
                  ????protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings,??? ?
                1. ????????????InputStream[]?batchedParameterStreams,?boolean[]?batchedIsStream,??? ?
                1. boolean[]?batchedIsStream,??? ?
                1. ????????????int[]?batchedStreamLengths)?throws?SQLException?{??? ?
                  ????????????int[]?batchedStreamLengths)?throws?SQLException?{??? ?
                1. ????????//?从connection的IO中得到发送数据包,首先清空其中的数据??? ?
                1. //?从connection的IO中得到发送数据包,首先清空其中的数据??? ?
                1. ????????Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket();??? ?
                  ????????Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket();??? ?
                1. ????????sendPacket.clear();??? ?
                1. ????????sendPacket.clear();??? ?
                1. ??????????? ?
                1. ??????????? ?
                1. ????????/*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。?? ?
                1. /*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。?? ?
                1. */?? ?
                1. */?? ?
                1. ????????sendPacket.writeByte((byte)?MysqlDefs.QUERY);??? ?
                1. byte)?MysqlDefs.QUERY);??? ?
                1. ?? ?
                1. ?? ?
                1. ????????boolean?useStreamLengths?=?this.connection??? ?
                1. boolean?useStreamLengths?=?this.connection??? ?
                1. ????????????????.getUseStreamLengthsInPrepStmts();??? ?
                1. ????????????????.getUseStreamLengthsInPrepStmts();??? ?
                1. ?? ?
                1. ?? ?
                1. ????????int?ensurePacketSize?=?0;??? ?
                  ????????int?ensurePacketSize?=?0;??? ?
                1. ????????for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
                1. for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
                1. ????????????if?(batchedIsStream[i]?&&?useStreamLengths)?{??? ?
                  ????????????if?(batchedIsStream[i]?&&?useStreamLengths)?{??? ?
                1. ????????????????ensurePacketSize?+=?batchedStreamLengths[i];??? ?
                1. ????????????????ensurePacketSize?+=?batchedStreamLengths[i];??? ?
                1. ????????????}??? ?
                1. ????????????}??? ?
                1. ????????}??? ?
                1. ????????}??? ?
                1. ?? ?
                1. ?? ?
                1. ????????/*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer?? ?
                1. /*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer?? ?
                1. */?? ?
                1. */?? ?
                1. ????????if?(ensurePacketSize?!=?0)?{??? ?
                1. if?(ensurePacketSize?!=?0)?{??? ?
                1. ????????????sendPacket.ensureCapacity(ensurePacketSize);??? ?
                1. ????????????sendPacket.ensureCapacity(ensurePacketSize);??? ?
                1. ????????}??? ?
                1. ????????}??? ?
                1. ?? ?
                1. ?? ?
                1. ????????/*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。?? ?
                1. /*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。?? ?
                1. */?? ?
                1. */?? ?
                1. ????????for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
                1. for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
                1. ?? ?
                1. ?? ?
                1. ????????/*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。?? ?
                1. /*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。?? ?
                1. */?? ?
                1. */?? ?
                1. ????????????if?((batchedParameterStrings[i]?==?null)??? ?
                1. if?((batchedParameterStrings[i]?==?null)??? ?
                1. ????????????????????&&?(batchedParameterStreams[i]?==?null))?{??? ?
                  ????????????????????&&?(batchedParameterStreams[i]?==?null))?{??? ?
                1. ????????????????throw?SQLError.createSQLException(Messages??? ?
                1. throw?SQLError.createSQLException(Messages??? ?
                1. ????????????????????????.getString("PreparedStatement.40")?//$NON-NLS-1$??? ?
                  ????????????????????????.getString("PreparedStatement.40")?//$NON-NLS-1$??? ?
                1. ????????????????????????+?(i?+?1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS);??? ?
                1. 1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS);??? ?
                1. ????????????}??? ?
                1. ????????????}??? ?
                1. ?? ?
                1. ?? ?
                1. ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。?? ?
                  ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。?? ?
                1. */?? ?
                1. */?? ?
                1. ????????????sendPacket.writeBytesNoNull(this.staticSqlStrings[i]);??? ?
                  ????????????sendPacket.writeBytesNoNull(this.staticSqlStrings[i]);??? ?
                1. ?? ?
                1. ?? ?
                1. ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。?? ?
                  ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。?? ?
                1. */?? ?
                1. */?? ?
                1. ????????????if?(batchedIsStream[i])?{??? ?
                  ????????????if?(batchedIsStream[i])?{??? ?
                1. ????????????????streamToBytes(sendPacket,?batchedParameterStreams[i],?true,??? ?
                1. true,??? ?
                1. ????????????????????????batchedStreamLengths[i],?useStreamLengths);??? ?
                1. ????????????????????????batchedStreamLengths[i],?useStreamLengths);??? ?
                1. ????????????}?else?{??? ?
                1. else?{??? ?
                1. ??????????????? ?
                1. ??????????????? ?
                1. ????????/*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。?? ?
                1. /*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。?? ?
                1. */?? ?
                1. */?? ?
                1. ????sendPacket.writeBytesNoNull(batchedParameterStrings[i]);??? ?
                1. ????sendPacket.writeBytesNoNull(batchedParameterStrings[i]);??? ?
                1. ????????????}??? ?
                1. ????????????}??? ?
                1. ????????}??? ?
                1. ????????}??? ?
                1. ?? ?
                1. ?? ?
                1. ????????/*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。?? ?
                1. /*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。?? ?
                1. */?? ?
                1. */?? ?
                1. ????????sendPacket??? ?
                1. ????????sendPacket??? ?
                1. ????????????????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]);??? ?
                  ????????????????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]);??? ?
                1. ?? ?
                1. ?? ?
                1. ????????return?sendPacket;??? ?
                  ????????return?sendPacket;??? ?
                1. ????}?? ?
                1. ????}?? ?
                1. ?protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings, ?
                  ?protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings, ?
                1. ???InputStream[]?batchedParameterStreams,?boolean[]?batchedIsStream, ?
                1. boolean[]?batchedIsStream, ?
                1. ???int[]?batchedStreamLengths)?throws?SQLException?{ ?
                  ???int[]?batchedStreamLengths)?throws?SQLException?{ ?
                1. ????????//?从connection的IO中得到发送数据包,首先清空其中的数据 ?
                1. //?从connection的IO中得到发送数据包,首先清空其中的数据 ?
                1. ??Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket(); ?
                  ??Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket(); ?
                1. ??sendPacket.clear(); ?
                1. ??sendPacket.clear(); ?
                1. ???????? ?
                1. ???????? ?
                1. ????????/*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。 ?
                1. /*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。 ?
                1. */?
                1. */?
                1. ??sendPacket.writeByte((byte)?MysqlDefs.QUERY); ?
                1. byte)?MysqlDefs.QUERY); ?
                1. ?
                1. ?
                1. ??boolean?useStreamLengths?=?this.connection ?
                1. boolean?useStreamLengths?=?this.connection ?
                1. ????.getUseStreamLengthsInPrepStmts(); ?
                1. ????.getUseStreamLengthsInPrepStmts(); ?
                1. ?
                1. ?
                1. ??int?ensurePacketSize?=?0; ?
                  ??int?ensurePacketSize?=?0; ?
                1. ??for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
                1. for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
                1. ???if?(batchedIsStream[i]?&&?useStreamLengths)?{ ?
                  ???if?(batchedIsStream[i]?&&?useStreamLengths)?{ ?
                1. ????ensurePacketSize?+=?batchedStreamLengths[i]; ?
                1. ????ensurePacketSize?+=?batchedStreamLengths[i]; ?
                1. ???} ?
                1. ???} ?
                1. ??} ?
                1. ??} ?
                1. ?
                1. ?
                1. ????????/*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer ?
                1. /*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer ?
                1. */?
                1. */?
                1. ??if?(ensurePacketSize?!=?0)?{ ?
                1. if?(ensurePacketSize?!=?0)?{ ?
                1. ???sendPacket.ensureCapacity(ensurePacketSize); ?
                1. ???sendPacket.ensureCapacity(ensurePacketSize); ?
                1. ??} ?
                1. ??} ?
                1. ?
                1. ?
                1. ????????/*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。 ?
                1. /*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。 ?
                1. */?
                1. */?
                1. ??for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
                1. for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
                1. ?
                1. ?
                1. ????????/*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。 ?
                1. /*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。 ?
                1. */?
                1. */?
                1. ???if?((batchedParameterStrings[i]?==?null) ?
                1. if?((batchedParameterStrings[i]?==?null) ?
                1. ?????&&?(batchedParameterStreams[i]?==?null))?{ ?
                  ?????&&?(batchedParameterStreams[i]?==?null))?{ ?
                1. ????throw?SQLError.createSQLException(Messages ?
                1. throw?SQLError.createSQLException(Messages ?
                1. ??????.getString("PreparedStatement.40")?//$NON-NLS-1$ ?
                  ??????.getString("PreparedStatement.40")?//$NON-NLS-1$ ?
                1. ??????+?(i?+?1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS); ?
                1. 1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS); ?
                1. ???} ?
                1. ???} ?
                1. ?
                1. ?
                1. ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。 ?
                  ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。 ?
                1. */?
                1. */?
                1. ???sendPacket.writeBytesNoNull(this.staticSqlStrings[i]); ?
                  ???sendPacket.writeBytesNoNull(this.staticSqlStrings[i]); ?
                1. ?
                1. ?
                1. ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。 ?
                  ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。 ?
                1. */?
                1. */?
                1. ???if?(batchedIsStream[i])?{ ?
                  ???if?(batchedIsStream[i])?{ ?
                1. ????streamToBytes(sendPacket,?batchedParameterStreams[i],?true, ?
                1. true, ?
                1. ??????batchedStreamLengths[i],?useStreamLengths); ?
                1. ??????batchedStreamLengths[i],?useStreamLengths); ?
                1. ???}?else?{ ?
                1. else?{ ?
                1. ??? ?
                1. ??? ?
                1. ????????/*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。 ?
                1. /*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。 ?
                1. */?
                1. */?
                1. ?sendPacket.writeBytesNoNull(batchedParameterStrings[i]); ?
                1. ?sendPacket.writeBytesNoNull(batchedParameterStrings[i]); ?
                1. ???} ?
                1. ???} ?
                1. ??} ?
                1. ??} ?
                1. ?
                1. ?
                1. ????????/*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。 ?
                1. /*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。 ?
                1. */?
                1. */?
                1. ??sendPacket ?
                1. ??sendPacket ?
                1. ????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]); ?
                  ????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]); ?
                1. ?
                1. ?
                1. ??return?sendPacket; ?
                  ??return?sendPacket; ?
                1. ?}?
                1. ?}?
                  但是并不是说PreparedStatement除了给我们带来高效率就没有其他作用了,它还有非常好的其他作用:?i. 极大的提高了sql语句的安全性,可以防止sql注入?ii. 代码结构清晰,易于理解,便于维护。i. 设置当前数据库连接,并调用connection的execSQL来执行查询.然后继续把要发送的查询包,就是之间组装完毕的sendPacket传递进入MysqlIO的sqlQueryDirect()。?ii. 接下来就要往server端发送我们的查询指令啦(sendCommand),说到发送数据,不禁要问,如果这个待发送的数据包超级大,难道每次都是一次性的发送吗?当然不是,如果数据包超过规定的最大值的话,就会把它分割一下,分成几个不超过最大值的数据包来发送。?所以可以肯定,在分割的过程中,除了最后一个数据包,其他数据包的大小都是一样的。那就这样的数据包直接切割了进行发送的话,假如现在被分成了三个数据包,发送给mysql server,服务器怎么知道那个包是第一个呢,它读数据该从什么地方开始读呢,这都是问题,所以,我们要给每个数据包的前面加上一点属性标志,这个标志一共占了4个byte。从代码①处开始就是头标识位的设置。第一位表示数据包的开始位置,就是数据存放的起始位置,一般都设置为0,就是从第一个位置开始。第二和第三个字节标识了这个数据包的大小,注意的是,这个大小是出去标识的4个字节的大小,对于非最后一个数据包来说,这个大小都是一样的,就是splitSize,也就是maxThreeBytes,它的值是255 * 255 * 255。?最后一个字节中存放的就是数据包的编号了,从0开始递增。?在标识位设置完毕之后,就可以把255 * 255 * 255大小的数据从我们准备好的待发送数据包中copy出来了,注意,前4位已经是标识位了,所以应该从第五个位置开始copy数据。?在数据包都装配完毕之后,就可以往socket的outputSteam中发送数据了。接下来的事情,就是由mysql服务器接收数据并解析,执行查询了。
                  1. while?(len?>=?this.maxThreeBytes)?{??? ?
                    while?(len?>=?this.maxThreeBytes)?{??? ?
                  1. ????this.packetSequence++;??? ?
                  1. this.packetSequence++;??? ?
                  1. ????/*设置包的开始位置*/?? ?
                    ????/*设置包的开始位置*/?? ?
                  1. ???headerPacket.setPosition(0);???? ?
                  1. 0);???? ?
                  1. ????/*设置这个数据包的大小,splitSize=255?*?255?*?255*/?? ?
                    ????/*设置这个数据包的大小,splitSize=255?*?255?*?255*/?? ?
                  1. ????headerPacket.writeLongInt(splitSize);???? ?
                  1. ????headerPacket.writeLongInt(splitSize);???? ?
                  1. ????/*设置数据包的序号*/?? ?
                    ????/*设置数据包的序号*/?? ?
                  1. ????headerPacket.writeByte(this.packetSequence);???? ?
                  1. this.packetSequence);???? ?
                  1. ????/*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?? ?
                    ????/*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?? ?
                  1. ????System.arraycopy(origPacketBytes,?originalPacketPos,??? ?
                  1. ????System.arraycopy(origPacketBytes,?originalPacketPos,??? ?
                  1. ????????headerPacketBytes,?4,?splitSize);??? ?
                    ????????headerPacketBytes,?4,?splitSize);??? ?
                  1. ?? ?
                  1. ?? ?
                  1. ????int?packetLen?=?splitSize?+?HEADER_LENGTH;??? ?
                    ????int?packetLen?=?splitSize?+?HEADER_LENGTH;??? ?
                  1. ????if?(!this.useCompression)?{??? ?
                  1. if?(!this.useCompression)?{??? ?
                  1. ????????this.mysqlOutput.write(headerPacketBytes,?0,??? ?
                    ????????this.mysqlOutput.write(headerPacketBytes,?0,??? ?
                  1. ????????????splitSize?+?HEADER_LENGTH);??? ?
                  1. ????????????splitSize?+?HEADER_LENGTH);??? ?
                  1. ????????this.mysqlOutput.flush();??? ?
                    ????????this.mysqlOutput.flush();??? ?
                  1. ????}?else?{??? ?
                  1. else?{??? ?
                  1. ????????Buffer?packetToSend;??? ?
                  1. ????????Buffer?packetToSend;??? ?
                  1. ?? ?
                  1. ?? ?
                  1. ????????headerPacket.setPosition(0);??? ?
                    ????????headerPacket.setPosition(0);??? ?
                  1. ????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH,??? ?
                  1. ????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH,??? ?
                  1. ????????????????splitSize,?HEADER_LENGTH);??? ?
                  1. ????????????????splitSize,?HEADER_LENGTH);??? ?
                  1. ????????packetLen?=?packetToSend.getPosition();??? ?
                  1. ????????packetLen?=?packetToSend.getPosition();??? ?
                  1. ????????/*往IO的output?stream中写数据*/?? ?
                    ????????/*往IO的output?stream中写数据*/?? ?
                  1. ????????this.mysqlOutput.write(packetToSend.getByteBuffer(),?0,??? ?
                  1. this.mysqlOutput.write(packetToSend.getByteBuffer(),?0,??? ?
                  1. ????????????packetLen);??? ?
                  1. ????????????packetLen);??? ?
                  1. ????????this.mysqlOutput.flush();??? ?
                  1. this.mysqlOutput.flush();??? ?
                  1. ????}??? ?
                  1. ????}??? ?
                  1. ?? ?
                  1. ?? ?
                  1. ????originalPacketPos?+=?splitSize;??? ?
                  1. ????originalPacketPos?+=?splitSize;??? ?
                  1. ????len?-=?splitSize;??? ?
                  1. ????len?-=?splitSize;??? ?
                  1. }?? ?
                  1. }?? ?
                  1. ????????????while?(len?>=?this.maxThreeBytes)?{ ?
                  1. while?(len?>=?this.maxThreeBytes)?{ ?
                  1. ????????????????this.packetSequence++; ?
                    ????????????????this.packetSequence++; ?
                  1. ????????????????/*设置包的开始位置*/?
                  1. /*设置包的开始位置*/?
                  1. ????①??????????headerPacket.setPosition(0);? ?
                    ????①??????????headerPacket.setPosition(0);? ?
                  1. ????????????????/*设置这个数据包的大小,splitSize=255?*?255?*?255*/?
                  1. /*设置这个数据包的大小,splitSize=255?*?255?*?255*/?
                  1. ????????????????headerPacket.writeLongInt(splitSize);? ?
                  1. ????????????????headerPacket.writeLongInt(splitSize);? ?
                  1. ????????????????/*设置数据包的序号*/?
                  1. /*设置数据包的序号*/?
                  1. ????????????????headerPacket.writeByte(this.packetSequence);? ?
                    ????????????????headerPacket.writeByte(this.packetSequence);? ?
                  1. ????????????????/*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?
                  1. /*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?
                  1. ????????????????System.arraycopy(origPacketBytes,?originalPacketPos, ?
                  1. ????????????????System.arraycopy(origPacketBytes,?originalPacketPos, ?
                  1. ????????????????????headerPacketBytes,?4,?splitSize); ?
                  1. 4,?splitSize); ?
                  1. ?
                  1. ?
                  1. ????????????????int?packetLen?=?splitSize?+?HEADER_LENGTH; ?
                  1. int?packetLen?=?splitSize?+?HEADER_LENGTH; ?
                  1. ????????????????if?(!this.useCompression)?{ ?
                    ????????????????if?(!this.useCompression)?{ ?
                  1. ????????????????????this.mysqlOutput.write(headerPacketBytes,?0, ?
                  1. this.mysqlOutput.write(headerPacketBytes,?0, ?
                  1. ????????????????????????splitSize?+?HEADER_LENGTH); ?
                  1. ????????????????????????splitSize?+?HEADER_LENGTH); ?
                  1. ????????????????????this.mysqlOutput.flush(); ?
                  1. this.mysqlOutput.flush(); ?
                  1. ????????????????}?else?{ ?
                    ????????????????}?else?{ ?
                  1. ????????????????????Buffer?packetToSend; ?
                  1. ????????????????????Buffer?packetToSend; ?
                  1. ?
                  1. ?
                  1. ????????????????????headerPacket.setPosition(0); ?
                  1. 0); ?
                  1. ????????????????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH, ?
                  1. ????????????????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH, ?
                  1. ????????????????????????????splitSize,?HEADER_LENGTH); ?
                  1. ????????????????????????????splitSize,?HEADER_LENGTH); ?
                  1. ????????????????????packetLen?=?packetToSend.getPosition(); ?
                  1. ????????????????????packetLen?=?packetToSend.getPosition(); ?
                  1. ????????????????????/*往IO的output?stream中写数据*/?
                  1. /*往IO的output?stream中写数据*/?
                  1. ????????????????????this.mysqlOutput.write(packetToSend.getByteBuffer(),?0, ?
                    ????????????????????this.mysqlOutput.write(packetToSend.getByteBuffer(),?0, ?
                  1. ????????????????????????packetLen); ?
                  1. ????????????????????????packetLen); ?
                  1. ????????????????????this.mysqlOutput.flush(); ?
                    ????????????????????this.mysqlOutput.flush(); ?
                  1. ????????????????} ?
                  1. ????????????????} ?
                  1. ?
                  1. ?
                  1. ????????????????originalPacketPos?+=?splitSize; ?
                  1. ????????????????originalPacketPos?+=?splitSize; ?
                  1. ????????????????len?-=?splitSize; ?
                  1. ????????????????len?-=?splitSize; ?
                  1. ????????????}?
                  1. ????????????}?

                    1、首先我们看到要的到一个数据库连接,得到数据库连接这部分放在DBHelper类中的getConnection方法中实现。Class.forName("com.mysql.jdbc.Driver");用来加载mysql的jdbc驱动。

                    Mysql的Driver类实现了java.sql.Driver接口,任何数据库提供商的驱动类都必须实现这个接口。在DriverManager类中使用的都是接口Driver类型的驱动,也就是说驱动的使用不依赖于具体的实现,这无疑给我们的使用带来很大的方便。如果需要换用其他的数据库的话,只需要把Class.forName()中的参数换掉就可以了,可以说是非常方便的。

                    在com.mysql.jdbc.Driver类中,除了构造方法,就是一个static的方法体,它调用了DriverManager的registerDriver()方法,这个方法会加载所有系统提供的驱动,并把它们都假如到具体的驱动类中,当然现在就是mysql的Driver。在这里我们第一次看到了DriverManager类,这个类中提供了jdbc连接的主要操作,创建连接就是在这里完成的,可以说这是一个管理驱动的工具类。

                    注册驱动首先就是初始化,然后把驱动的信息封装一下放进一个叫做DriverInfo的驱动信息类中,最后放入一个驱动的集合中。初始化工作主要是完成所有驱动的加载。?

                    第二步就要根据url和用户名,密码来获得数据库的连接了。url一般都是这样的格式:jdbc:protocol://host_name:port/db_name?parameter_name=param_value。开头部分的protocal是对应于不同的数据库提供商的协议,例如mysql的就是mysql。

                    DriverManager中有重载了四个getConnection(),因为我们有用户名和密码,就把用户和密码存放在Properties中,最后进入终极getConnection(),如下:

                    Initialize()简直无所不在,DriverManager中只要使用driver之前,就要检查一下有没有初始化,非常小心。然后开始遍历所有驱动,直到找到一个可用的驱动,用这个驱动来取得一个数据库连接,最后返回这个连接。当然,这是正常的情况,从上面我们可以看到,程序中对异常的处理很仔细。如果连接失败,会记录抛出的第一个异常信息,如果没有找到合适的驱动,就抛出一个08001的错误。

                    现在重点就是假如一切正常,就应该从driver.connect()返回一个数据库连接,所以我们来看看如何通过url提供的数据库。

                    很简洁的写法,就是新建了一个mysql的connection,host, port, database给它传进入,让它去连接就对了,props里面是些什么东西呢,就是把url拆解一下,什么host,什么数据库名,然后url后面的一股脑的参数,再把用户跟密码也都放进入,反正就是所有的连接数据都放进入了。

                    在com.mysql.jdbc.Connection的构造方法里面,会先做一些连接的初始化操作,例如创建PreparedStatement的cache,创建日志等等。然后就进入createNewIO()来建立连接了。

                    范例分析MySQL JDBC驱动

                    从时序图中可以看到,createNewIO()就是新建了一个com.mysql.jdbc.MysqlIO,利用com.mysql.jdbc.StandardSocketFactory来创建一个socket。然后就由这个mySqlIO来与MySql服务器进行握手(doHandshake()),这个doHandshake主要用来初始化与Mysql server的连接,负责登陆服务器和处理连接错误。在其中会分析所连接的mysql server的版本,根据不同的版本以及是否使用SSL加密数据都有不同的处理方式,并把要传输给数据库server的数据都放在一个叫做packet的buffer中,调用send()方法往outputStream中写入要发送的数据。


                    范例分析MySQL JDBC驱动

                    一旦有了一个statement,就可以通过执行statement.executeQuery()并通过ResultSet对象读出查询结果(如果查询有返回结果的话)。

                    创建statement的方法一般都有重载,我们看下面的prepareStatement:


                    public java.sql.PreparedStatement prepareStatement(String sql,

                    ?

                    如果没有指定resultSetType和resultSetConcurrency的话,会给它们默认设置一个值。?

                    prepareStatement的创建如下图所示:

                    范例分析MySQL JDBC驱动

                    在new ParseInfo中,会对这个sql语句进行分析,例如看看这个sql是什么语句;有没有limit条件语句,还有一个重要的工作,如果使用的是PreparedStatement来准备sql语句的话,会在这里把sql语句进行分解。我们知道PreparedStatement对象在实例化创建时就被设置了一个sql语句,使用PreparedStatement对象执行的sql语句在首次发送到数据库时,sql语句就会被编译,这样当多次执行同一个sql语句时,mysql就不用每次都去编译sql语句了。

                    这个sql语句如果包含参数的话,可以用问号(”?”)来为参数进行占位,而不需要立即为参数赋值,而在语句执行之前,必须通过适当的set***()来为问号处的参数赋值。New ParseInfo()中,包含了参数的sql语句就会被分解为多段,放在staticSql中,以便需要设置参数时定位参数的位置。假如sql语句为“select * from adv where id = ? and name = ?”的话,那么staticSql中的元素就是3个,staticSql[3]={ ”select * from adv where id = ”, ” and name = ” , ””}。注意数组中最后一个元素,在这个例子中是””,因为我的例子里面最后一个就是”?”,如果sql语句是这样的“select * from adv where id = ? and name = ? order by id”的话,staticSql就变成是这样的{ ”select * from adv where id = ”, ” and name = ” , ” order by id”}。


                    设置sql语句中的参数值。

                    对于参数而言,PreparedStatement中一共有四个变量来储存它们,分别是

                    a) byte[][] parameterValues:参数转换为byte后的值。

                    b) InputStream[] parameterStreams:只有在调用存储过程batch(CallableStatement)的时候才会用到它,否则它的数组中的值设置为null。

                    c) boolean[] isStream:是否为stream的标志,如果调用的是preparedStatement,isStream数组中的值均为false,若调用的是CallableStatement,则均设置为true。

                    d) boolean[] isNull:标识参数是否为空,设置为false。

                    这四个变量的一维数组的大小都是一样的,sql语句中有几个待set的参数(几个问号),一维的元素个数就是多大。?

                    a) 检查preparedStatement是否已关闭,如果已关闭,抛出一个SQLError.SQL_STATE_CONNECTION_NOT_OPEN的错误。

                    b) fillSendPacket:创建数据包,其中包含了要发送到服务器的查询。

                    这个sendPacket就是mysql驱动要发送给数据库服务器的协议数据。一般来说,协议的数据格式有两种,一种是二进制流的格式,还有一种是文本的格式。文本协议就是基本上人可以直接阅读的协议,一般是用ascii字符集,也有用utf8格式的,优点是便于理解,读起来方便,扩充容易,缺点就是解析的时候比较麻烦,而且占用的空间比较大,冗余的数据比较多。二进制格式话,就需要服务器与客户端协议规定固定的数据结构,哪个位置放什么数据,如果单独看协议内容的话,很难理解数据含义,优点就是数据量小,解析的时候只要根据固定位置的值就能知道具体标识什么意义。

                    在这里使用的是二进制流的格式,也就是说协议中的数据格式是固定的,而且都要转换成二进制。格式为第一个byte标识操作信号,后面开始就是完整的sql语句的二进制流,请看下面的代码分析。

                    ?

                    假如sql语句为“select * from adv where id = ?”的话,这个sendPacket中第一个byte的值就是3(MysqlDefs.QUERY的int值),后面接着的就是填充了参数值的完整的sql语句字符串(例如:select * from adv where id = 1)转换成的byte格式。

                    于是,我们看到,好像sql语句在这里就已经不是带”?”的preparedStatement,而是在驱动里面把参数替代到”?”中,再把完整的sql语句发送给mysql server来编译,那么尽管只是参数改变,但对于mysql server来说,每次都是新的sql语句,都要进行编译的。这与我们之前一直理解的PreparedStatement完全不一样。照理来说,应该把带”?”的sql语句发送给数据库server,由mysql server来编译这个带”?”的sql语句,然后用实际的参数来替代”?”,这样才是实现了sql语句只编译一次的效果。sql语句预编译的功能取决于server端,oracle就是支持sql预编译的。

                    所以说,从mysql驱动的PreparedStatement里面,好像我们并没有看到mysql支持预编译功能的证据。(实际测试也表明,如果server没有预编译功能的话,PreparedStatement和Statement的效率几乎一样,甚至当使用次数不多的时候,PreparedStatement比Statement还要慢一些)。?

                    2009-07-02增加(感谢gembler):其实,在mysql5上的版本是支持预编译sql功能的。我用的驱动是5.0.6的,在com.mysql.jdbc.Connection中有一个参数useServerPreparedStmts,表明是否使用预编译功能,所以如果把useServerPreparedStmts置为true的话,mysql驱动可以通过PreparedStatement的子类ServerPreparedStatement来实现真正的PreparedStatement的功能。在这个类的serverExecute方法里面,就负责告诉server,用现在提供的参数来动态绑定到编译好的sql语句上。所以说,ServerPreparedStatement才是真正实现了所谓prepare statement。

                    c) 设置当前的数据库名,并把之前的数据库名记录下来,在查询完成之后还要恢复原状。

                    d) 检查一下之前是否有缓存的数据,如果不久之前执行过这个查询,并且缓存了数据的话,就直接从缓存中取出。

                    e) 如果sql查询没有限制条件的话,为其设置默认的返回行数,若preparedStatement中已经设置了maxRows的话,就使用它。

                    f) executeInternal:执行查询。?


                    iii. 通过readAllResults方法读取查询结果。这个读取的过程与发送过程相反,如果接收到的数据包有多个的话,通过IO不断读取,并根据第packet第4个位置上的序号来组装这些packet。然后把读到的数据组装成resultSet中的rowData,这个结果就是我们要的查询结果了。

                    结合下面的executeQuery的时序图再理一下思路就更清楚了。

                    范例分析MySQL JDBC驱动

                    至此,把resultSet一步步的返回给dao,接下来的过程,就是从resultSet中取出rowData,组合成我们自己需要的对象数据了。

                    总结一下,经过这次对mysql驱动的探索,我发现了更多关于mysql的底层细节,对于以后分析问题解决问题有很大帮助,当然,这里面还有很多细节文中没有写。另外一个就是对于PreparedStatement有了重新的认识,有些东西往往都是想当然得出来的结论,真相还是要靠实践来发现。

                  1. 读书人网 >其他数据库

                    热点推荐