实例分析MySQL JDBC驱动
http://developer.51cto.com/art/200907/137823.htm
MySQL是一个中小型关系型数据库管理系统,目前使用的也比较广泛。为了对开发中间DAO层的问题能有更深的理解,在遇到问题的时候能够有更多的思路,于是研究了一下MySQL JDBC驱动的使用,并且在这过程中也发现了一直以来关于PreparedStatement常识理解上的错误,与大家分享。
?
- public?class?DBHelper?{??? ?
- ????public?static?Connection?getConnection()?{??? ?
- public?static?Connection?getConnection()?{??? ?
- ????????Connection?conn?=?null;??? ?
- ????????Connection?conn?=?null;??? ?
- ????????try?{??? ?
- try?{??? ?
- ????????????Class.forName("com.mysql.jdbc.Driver");??? ?
- ????????????Class.forName("com.mysql.jdbc.Driver");??? ?
- ????????????conn?=?DriverManager.getConnection("jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false",??? ?
- "jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false",??? ?
- ????????????????????"root",?"root");??? ?
- ????????????????????"root",?"root");??? ?
- ????????}?catch?(Exception?e)?{??? ?
- catch?(Exception?e)?{??? ?
- ????????????e.printStackTrace();??? ?
- ????????????e.printStackTrace();??? ?
- ????????}??? ?
- ????????}??? ?
- ????????return?conn;??? ?
- ????????return?conn;??? ?
- ????}??? ?
- ????}??? ?
- }??? ?
- }??? ?
- ?? ?
- ?? ?
- ????????/*dao中的方法*/?? ?
- ????????/*dao中的方法*/?? ?
- ????public?List?getAllAdvs()?{??? ?
- public?List?getAllAdvs()?{??? ?
- ??????????? ?
- ??????????? ?
- ????????Connection?conn?=?null;??? ?
- null;??? ?
- ????????ResultSet?rs?=?null;??? ?
- ????????ResultSet?rs?=?null;??? ?
- ????????PreparedStatement?stmt?=?null;??? ?
- null;??? ?
- ????????String?sql?=?"select?*?from?adv?where?id?=??";??? ?
- ????????String?sql?=?"select?*?from?adv?where?id?=??";??? ?
- ????????List?advs?=?new?ArrayList();??? ?
- new?ArrayList();??? ?
- ?? ?
- ?? ?
- ????????conn?=?DBHelper.getConnection();??? ?
- ????????conn?=?DBHelper.getConnection();??? ?
- ????????if?(conn?!=?null)?{??? ?
- ????????if?(conn?!=?null)?{??? ?
- ????????????try?{??? ?
- try?{??? ?
- ????????????????stmt?=?conn.prepareStatement(sql);??? ?
- ????????????????stmt?=?conn.prepareStatement(sql);??? ?
- ????????????????????????????????stmt.setInt(1,?new?Integer(1));??? ?
- 1,?new?Integer(1));??? ?
- ????????????????rs?=?stmt.executeQuery();??? ?
- ????????????????rs?=?stmt.executeQuery();??? ?
- ?? ?
- ?? ?
- ????????????????if?(rs?!=?null)?{??? ?
- ????????????????if?(rs?!=?null)?{??? ?
- ????????????????????while?(rs.next())?{??? ?
- while?(rs.next())?{??? ?
- ????????????????????????Adv?adv?=?new?Adv();??? ?
- ????????????????????????Adv?adv?=?new?Adv();??? ?
- ????????????????????????adv.setId(rs.getLong(1));??? ?
- 1));??? ?
- ????????????????????????adv.setName(rs.getString(2));??? ?
- ????????????????????????adv.setName(rs.getString(2));??? ?
- ????????????????????????adv.setDesc(rs.getString(3));??? ?
- 3));??? ?
- ????????????????????????adv.setPicUrl(rs.getString(4));??? ?
- ????????????????????????adv.setPicUrl(rs.getString(4));??? ?
- ?? ?
- ?? ?
- ????????????????????????advs.add(adv);??? ?
- ????????????????????????advs.add(adv);??? ?
- ????????????????????}??? ?
- ????????????????????}??? ?
- ????????????????}??? ?
- ????????????????}??? ?
- ????????????}?catch?(SQLException?e)?{??? ?
- catch?(SQLException?e)?{??? ?
- ????????????????e.printStackTrace();??? ?
- ????????????????e.printStackTrace();??? ?
- ????????????}?finally?{??? ?
- finally?{??? ?
- ????????????????try?{??? ?
- ????????????????try?{??? ?
- ????????????????????stmt.close();??? ?
- ????????????????????stmt.close();??? ?
- ????????????????????conn.close();??? ?
- ????????????????????conn.close();??? ?
- ????????????????}?catch?(SQLException?e)?{??? ?
- catch?(SQLException?e)?{??? ?
- ????????????????????e.printStackTrace();??? ?
- ????????????????????e.printStackTrace();??? ?
- ????????????????}??? ?
- ????????????????}??? ?
- ????????????}??? ?
- ????????????}??? ?
- ????????}??? ?
- ????????}??? ?
- ????????return?advs;??? ?
- ????????return?advs;??? ?
- ????}?? ?
- ????}?? ?
- public?class?DBHelper?{ ?
- public?class?DBHelper?{ ?
- ?public?static?Connection?getConnection()?{ ?
- public?static?Connection?getConnection()?{ ?
- ??Connection?conn?=?null; ?
- ??Connection?conn?=?null; ?
- ??try?{ ?
- try?{ ?
- ???Class.forName("com.mysql.jdbc.Driver"); ?
- ???Class.forName("com.mysql.jdbc.Driver"); ?
- ???conn?=?DriverManager.getConnection("jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false", ?
- "jdbc:mysql://localhost/ad?useUnicode=true&characterEncoding=GBK&jdbcCompliantTruncation=false", ?
- ?????"root",?"root"); ?
- ?????"root",?"root"); ?
- ??}?catch?(Exception?e)?{ ?
- catch?(Exception?e)?{ ?
- ???e.printStackTrace(); ?
- ???e.printStackTrace(); ?
- ??} ?
- ??} ?
- ??return?conn; ?
- ??return?conn; ?
- ?} ?
- ?} ?
- } ?
- } ?
- ?
- ?
- ????????/*dao中的方法*/?
- ????????/*dao中的方法*/?
- ?public?List?getAllAdvs()?{ ?
- public?List?getAllAdvs()?{ ?
- ?? ?
- ?? ?
- ??Connection?conn?=?null; ?
- null; ?
- ??ResultSet?rs?=?null; ?
- ??ResultSet?rs?=?null; ?
- ??PreparedStatement?stmt?=?null; ?
- null; ?
- ??String?sql?=?"select?*?from?adv?where?id?=??"; ?
- ??String?sql?=?"select?*?from?adv?where?id?=??"; ?
- ??List?advs?=?new?ArrayList(); ?
- new?ArrayList(); ?
- ?
- ?
- ??conn?=?DBHelper.getConnection(); ?
- ??conn?=?DBHelper.getConnection(); ?
- ??if?(conn?!=?null)?{ ?
- ??if?(conn?!=?null)?{ ?
- ???try?{ ?
- try?{ ?
- ????stmt?=?conn.prepareStatement(sql); ?
- ????stmt?=?conn.prepareStatement(sql); ?
- ????????????????????????????????stmt.setInt(1,?new?Integer(1)); ?
- 1,?new?Integer(1)); ?
- ????rs?=?stmt.executeQuery(); ?
- ????rs?=?stmt.executeQuery(); ?
- ?
- ?
- ????if?(rs?!=?null)?{ ?
- ????if?(rs?!=?null)?{ ?
- ?????while?(rs.next())?{ ?
- while?(rs.next())?{ ?
- ??????Adv?adv?=?new?Adv(); ?
- ??????Adv?adv?=?new?Adv(); ?
- ??????adv.setId(rs.getLong(1)); ?
- 1)); ?
- ??????adv.setName(rs.getString(2)); ?
- ??????adv.setName(rs.getString(2)); ?
- ??????adv.setDesc(rs.getString(3)); ?
- 3)); ?
- ??????adv.setPicUrl(rs.getString(4)); ?
- ??????adv.setPicUrl(rs.getString(4)); ?
- ?
- ?
- ??????advs.add(adv); ?
- ??????advs.add(adv); ?
- ?????} ?
- ?????} ?
- ????} ?
- ????} ?
- ???}?catch?(SQLException?e)?{ ?
- catch?(SQLException?e)?{ ?
- ????e.printStackTrace(); ?
- ????e.printStackTrace(); ?
- ???}?finally?{ ?
- finally?{ ?
- ????try?{ ?
- ????try?{ ?
- ?????stmt.close(); ?
- ?????stmt.close(); ?
- ?????conn.close(); ?
- ?????conn.close(); ?
- ????}?catch?(SQLException?e)?{ ?
- catch?(SQLException?e)?{ ?
- ?????e.printStackTrace(); ?
- ?????e.printStackTrace(); ?
- ????} ?
- ????} ?
- ???} ?
- ???} ?
- ??} ?
- ??} ?
- ??return?advs; ?
- ??return?advs; ?
- ?}?
- ?}?
- public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{??? ?
- public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{??? ?
- ????static?{??? ?
- static?{??? ?
- ????????try?{??? ?
- ????????try?{??? ?
- ????????????java.sql.DriverManager.registerDriver(new?Driver());??? ?
- new?Driver());??? ?
- ????????}?catch?(SQLException?E)?{??? ?
- ????????}?catch?(SQLException?E)?{??? ?
- ????????????throw?new?RuntimeException("Can't?register?driver!");??? ?
- throw?new?RuntimeException("Can't?register?driver!");??? ?
- ????????}??? ?
- ????????}??? ?
- ????}??? ?
- ????}??? ?
- ????public?Driver()?throws?SQLException?{??? ?
- ????public?Driver()?throws?SQLException?{??? ?
- ????}??? ?
- ????}??? ?
- }?? ?
- }?? ?
- public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{ ?
- public?class?Driver?extends?NonRegisteringDriver?implements?java.sql.Driver?{ ?
- ?static?{ ?
- ?static?{ ?
- ??try?{ ?
- try?{ ?
- ???java.sql.DriverManager.registerDriver(new?Driver()); ?
- ???java.sql.DriverManager.registerDriver(new?Driver()); ?
- ??}?catch?(SQLException?E)?{ ?
- catch?(SQLException?E)?{ ?
- ???throw?new?RuntimeException("Can't?register?driver!"); ?
- ???throw?new?RuntimeException("Can't?register?driver!"); ?
- ??} ?
- ??} ?
- ?} ?
- ?} ?
- ?public?Driver()?throws?SQLException?{ ?
- public?Driver()?throws?SQLException?{ ?
- ?} ?
- ?} ?
- }?
- }?
- ???public?static?synchronized?void?registerDriver(java.sql.Driver?driver)??? ?
- ???public?static?synchronized?void?registerDriver(java.sql.Driver?driver)??? ?
- throws?SQLException?{??? ?
- throws?SQLException?{??? ?
- if?(!initialized)?{??? ?
- if?(!initialized)?{??? ?
- ????initialize();??? ?
- ????initialize();??? ?
- }?????????? ?
- }?????????? ?
- DriverInfo?di?=?new?DriverInfo();???? ?
- new?DriverInfo();???? ?
- ??/*把driver的信息封装一下,组成一个DriverInfo对象*/?? ?
- ??/*把driver的信息封装一下,组成一个DriverInfo对象*/?? ?
- di.driver?=?driver;??? ?
- di.driver?=?driver;??? ?
- di.driverClass?=?driver.getClass();??? ?
- di.driverClass?=?driver.getClass();??? ?
- di.driverClassName?=?di.driverClass.getName();????? ?
- di.driverClassName?=?di.driverClass.getName();????? ?
- writeDrivers.addElement(di);???? ?
- writeDrivers.addElement(di);???? ?
- println("registerDriver:?"?+?di);???? ?
- "registerDriver:?"?+?di);???? ?
- readDrivers?=?(java.util.Vector)?writeDrivers.clone();???? ?
- readDrivers?=?(java.util.Vector)?writeDrivers.clone();???? ?
- ???}?? ?
- ???}?? ?
- ????public?static?synchronized?void?registerDriver(java.sql.Driver?driver) ?
- ????public?static?synchronized?void?registerDriver(java.sql.Driver?driver) ?
- ?throws?SQLException?{ ?
- throws?SQLException?{ ?
- ?if?(!initialized)?{ ?
- ?if?(!initialized)?{ ?
- ?????initialize(); ?
- ?????initialize(); ?
- ?}?????? ?
- ?}?????? ?
- ?DriverInfo?di?=?new?DriverInfo(); ?
- new?DriverInfo(); ?
- ???/*把driver的信息封装一下,组成一个DriverInfo对象*/?
- ???/*把driver的信息封装一下,组成一个DriverInfo对象*/?
- ?di.driver?=?driver; ?
- ?di.driver?=?driver; ?
- ?di.driverClass?=?driver.getClass(); ?
- ?di.driverClass?=?driver.getClass(); ?
- ?di.driverClassName?=?di.driverClass.getName(); ?
- ?di.driverClassName?=?di.driverClass.getName(); ?
- ?
- ?
- ?writeDrivers.addElement(di);? ?
- ?writeDrivers.addElement(di);? ?
- ?println("registerDriver:?"?+?di); ?
- ?println("registerDriver:?"?+?di); ?
- ?readDrivers?=?(java.util.Vector)?writeDrivers.clone(); ?
- ?readDrivers?=?(java.util.Vector)?writeDrivers.clone(); ?
- ?
- ?
- ????}?
- ????}?
- ???private?static?Connection?getConnection(??? ?
- ???private?static?Connection?getConnection(??? ?
- String?url,?java.util.Properties?info,?ClassLoader?callerCL)?throws?SQLException?{??? ?
- throws?SQLException?{??? ?
- java.util.Vector?drivers?=?null;??? ?
- java.util.Vector?drivers?=?null;??? ?
- ...??? ?
- ...??? ?
- if?(!initialized)?{??? ?
- if?(!initialized)?{??? ?
- ????initialize();??? ?
- ????initialize();??? ?
- }??? ?
- }??? ?
- ???/*取得连接使用的driver从readDrivers中取*/?? ?
- /*取得连接使用的driver从readDrivers中取*/?? ?
- synchronized?(DriverManager.class){???? ?
- synchronized?(DriverManager.class){???? ?
- ????drivers?=?readDrivers;????? ?
- ????drivers?=?readDrivers;????? ?
- ???????}??? ?
- ???????}??? ?
- ?? ?
- ?? ?
- SQLException?reason?=?null;??? ?
- SQLException?reason?=?null;??? ?
- for?(int?i?=?0;?i?<?drivers.size();?i++)?{??? ?
- for?(int?i?=?0;?i?<?drivers.size();?i++)?{??? ?
- ????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i);??? ?
- ????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i);??? ?
- ???????? ?
- ???????? ?
- ????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{??? ?
- ????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{??? ?
- ????continue;??? ?
- continue;??? ?
- ????}??? ?
- ????}??? ?
- ????try?{??? ?
- try?{??? ?
- ???????/*找到可供使用的驱动,连接数据库server*/?? ?
- ???????/*找到可供使用的驱动,连接数据库server*/?? ?
- ????Connection?result?=?di.driver.connect(url,?info);??? ?
- ????Connection?result?=?di.driver.connect(url,?info);??? ?
- ????if?(result?!=?null)?{??? ?
- ????if?(result?!=?null)?{??? ?
- ????????return?(result);??? ?
- return?(result);??? ?
- ????}??? ?
- ????}??? ?
- ????}?catch?(SQLException?ex)?{??? ?
- catch?(SQLException?ex)?{??? ?
- ????if?(reason?==?null)?{??? ?
- ????if?(reason?==?null)?{??? ?
- ????????reason?=?ex;??? ?
- ????????reason?=?ex;??? ?
- ????}??? ?
- ????}??? ?
- ????}??? ?
- ????}??? ?
- }??? ?
- }??? ?
- ?????? ?
- ?????? ?
- if?(reason?!=?null)????{??? ?
- if?(reason?!=?null)????{??? ?
- ????println("getConnection?failed:?"?+?reason);??? ?
- "getConnection?failed:?"?+?reason);??? ?
- ????throw?reason;??? ?
- ????throw?reason;??? ?
- }??????? ?
- }??????? ?
- throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001");??? ?
- throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001");??? ?
- ???}?? ?
- ???}?? ?
- ????private?static?Connection?getConnection( ?
- ????private?static?Connection?getConnection( ?
- ?String?url,?java.util.Properties?info,?ClassLoader?callerCL)?throws?SQLException?{ ?
- throws?SQLException?{ ?
- ?java.util.Vector?drivers?=?null; ?
- ?java.util.Vector?drivers?=?null; ?
- ?... ?
- ?... ?
- ?if?(!initialized)?{ ?
- ?if?(!initialized)?{ ?
- ?????initialize(); ?
- ?????initialize(); ?
- ?} ?
- ?} ?
- ????/*取得连接使用的driver从readDrivers中取*/?
- /*取得连接使用的driver从readDrivers中取*/?
- ?synchronized?(DriverManager.class){? ?
- ?synchronized?(DriverManager.class){? ?
- ?????drivers?=?readDrivers;?? ?
- ?????drivers?=?readDrivers;?? ?
- ????????} ?
- ????????} ?
- ?
- ?
- ?SQLException?reason?=?null; ?
- ?SQLException?reason?=?null; ?
- ?for?(int?i?=?0;?i?<?drivers.size();?i++)?{ ?
- for?(int?i?=?0;?i?<?drivers.size();?i++)?{ ?
- ?????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i); ?
- ?????DriverInfo?di?=?(DriverInfo)drivers.elementAt(i); ?
- ?????? ?
- ?????? ?
- ?????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{ ?
- ?????if?(?getCallerClass(callerCL,?di.driverClassName?)?!=?di.driverClass?)?{ ?
- ??continue; ?
- continue; ?
- ?????} ?
- ?????} ?
- ?????try?{ ?
- try?{ ?
- ????????/*找到可供使用的驱动,连接数据库server*/?
- ????????/*找到可供使用的驱动,连接数据库server*/?
- ??Connection?result?=?di.driver.connect(url,?info); ?
- ??Connection?result?=?di.driver.connect(url,?info); ?
- ??if?(result?!=?null)?{ ?
- ??if?(result?!=?null)?{ ?
- ??????return?(result); ?
- return?(result); ?
- ??} ?
- ??} ?
- ?????}?catch?(SQLException?ex)?{ ?
- catch?(SQLException?ex)?{ ?
- ??if?(reason?==?null)?{ ?
- ??if?(reason?==?null)?{ ?
- ??????reason?=?ex; ?
- ??????reason?=?ex; ?
- ??} ?
- ??} ?
- ?????} ?
- ?????} ?
- ?} ?
- ?} ?
- ???? ?
- ???? ?
- ?if?(reason?!=?null)????{ ?
- ?if?(reason?!=?null)????{ ?
- ?????println("getConnection?failed:?"?+?reason); ?
- "getConnection?failed:?"?+?reason); ?
- ?????throw?reason; ?
- ?????throw?reason; ?
- ?}???? ?
- ?}???? ?
- ?throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001"); ?
- ?throw?new?SQLException("No?suitable?driver?found?for?"+?url,?"08001"); ?
- ????}?
- ????}?
- public?java.sql.Connection?connect(String?url,?Properties?info)??? ?
- public?java.sql.Connection?connect(String?url,?Properties?info)??? ?
- ????????throws?SQLException?{??? ?
- throws?SQLException?{??? ?
- ????Properties?props?=?null;??? ?
- ????Properties?props?=?null;??? ?
- ????if?((props?=?parseURL(url,?info))?==?null)?{??? ?
- if?((props?=?parseURL(url,?info))?==?null)?{??? ?
- ????????return?null;??? ?
- ????????return?null;??? ?
- ????}??? ?
- ????}??? ?
- ?? ?
- ?? ?
- ????try?{??? ?
- try?{??? ?
- ????????Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props),??? ?
- ????????Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props),??? ?
- ????????????????port(props),?props,?database(props),?url);??? ?
- ????????????????port(props),?props,?database(props),?url);??? ?
- ?? ?
- ?? ?
- ????????return?newConn;??? ?
- return?newConn;??? ?
- ????}?catch?(SQLException?sqlEx)?{??? ?
- ????}?catch?(SQLException?sqlEx)?{??? ?
- ????????throw?sqlEx;??? ?
- throw?sqlEx;??? ?
- ????}?catch?(Exception?ex)?{??? ?
- ????}?catch?(Exception?ex)?{??? ?
- ????????throw?SQLError.createSQLException(...);??? ?
- throw?SQLError.createSQLException(...);??? ?
- ????}??? ?
- ????}??? ?
- }?? ?
- }?? ?
- ?public?java.sql.Connection?connect(String?url,?Properties?info) ?
- ?public?java.sql.Connection?connect(String?url,?Properties?info) ?
- ???throws?SQLException?{ ?
- throws?SQLException?{ ?
- ??Properties?props?=?null; ?
- ??Properties?props?=?null; ?
- ??if?((props?=?parseURL(url,?info))?==?null)?{ ?
- if?((props?=?parseURL(url,?info))?==?null)?{ ?
- ???return?null; ?
- ???return?null; ?
- ??} ?
- ??} ?
- ?
- ?
- ??try?{ ?
- try?{ ?
- ???Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props), ?
- ???Connection?newConn?=?new?com.mysql.jdbc.Connection(host(props), ?
- ?????port(props),?props,?database(props),?url); ?
- ?????port(props),?props,?database(props),?url); ?
- ?
- ?
- ???return?newConn; ?
- return?newConn; ?
- ??}?catch?(SQLException?sqlEx)?{ ?
- ??}?catch?(SQLException?sqlEx)?{ ?
- ???throw?sqlEx; ?
- throw?sqlEx; ?
- ??}?catch?(Exception?ex)?{ ?
- ??}?catch?(Exception?ex)?{ ?
- ???throw?SQLError.createSQLException(...); ?
- throw?SQLError.createSQLException(...); ?
- ??} ?
- ??} ?
- ?}?
- ?}?
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中的参数常量主要有以下几种:?
- TYPE_SCROLL_INSENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变不敏感。? ?
- TYPE_SCROLL_INSENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变不敏感。? ?
- TYPE_SCROLL_SENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变是敏感的。? ?
- TYPE_SCROLL_SENSITIVE:ResultSet的游标可以滚动,但对于resultSet下的数据改变是敏感的。? ?
- CONCUR_READ_ONLY:不可以更新的ResultSet的并发模式。? ?
- CONCUR_READ_ONLY:不可以更新的ResultSet的并发模式。? ?
- CONCUR_UPDATABLE:可以更新的ResultSet的并发模式。? ?
- CONCUR_UPDATABLE:可以更新的ResultSet的并发模式。? ?
- FETCH_FORWARD:按正向(即从第一个到最后一个)处理结果集中的行。? ?
- FETCH_FORWARD:按正向(即从第一个到最后一个)处理结果集中的行。? ?
- FETCH_REVERSE:按反向(即从最后一个到第一个)处理结果集中的行处理。? ?
- FETCH_REVERSE:按反向(即从最后一个到第一个)处理结果集中的行处理。? ?
- FETCH_UNKNOWN:结果集中的行的处理顺序未知。? ?
- FETCH_UNKNOWN:结果集中的行的处理顺序未知。? ?
- CLOSE_CURSORS_AT_COMMIT:调用Connection.commit方法时应该关闭?ResultSet?对? ?
- CLOSE_CURSORS_AT_COMMIT:调用Connection.commit方法时应该关闭?ResultSet?对? ?
- HOLD_CURSORS_OVER_COMMIT:调用Connection.commit方法时不应关闭ResultSet对象。?
- HOLD_CURSORS_OVER_COMMIT:调用Connection.commit方法时不应关闭ResultSet对象。?
- ????protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings,??? ?
- ????protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings,??? ?
- ????????????InputStream[]?batchedParameterStreams,?boolean[]?batchedIsStream,??? ?
- boolean[]?batchedIsStream,??? ?
- ????????????int[]?batchedStreamLengths)?throws?SQLException?{??? ?
- ????????????int[]?batchedStreamLengths)?throws?SQLException?{??? ?
- ????????//?从connection的IO中得到发送数据包,首先清空其中的数据??? ?
- //?从connection的IO中得到发送数据包,首先清空其中的数据??? ?
- ????????Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket();??? ?
- ????????Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket();??? ?
- ????????sendPacket.clear();??? ?
- ????????sendPacket.clear();??? ?
- ??????????? ?
- ??????????? ?
- ????????/*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。?? ?
- /*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。?? ?
- */?? ?
- */?? ?
- ????????sendPacket.writeByte((byte)?MysqlDefs.QUERY);??? ?
- byte)?MysqlDefs.QUERY);??? ?
- ?? ?
- ?? ?
- ????????boolean?useStreamLengths?=?this.connection??? ?
- boolean?useStreamLengths?=?this.connection??? ?
- ????????????????.getUseStreamLengthsInPrepStmts();??? ?
- ????????????????.getUseStreamLengthsInPrepStmts();??? ?
- ?? ?
- ?? ?
- ????????int?ensurePacketSize?=?0;??? ?
- ????????int?ensurePacketSize?=?0;??? ?
- ????????for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
- for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
- ????????????if?(batchedIsStream[i]?&&?useStreamLengths)?{??? ?
- ????????????if?(batchedIsStream[i]?&&?useStreamLengths)?{??? ?
- ????????????????ensurePacketSize?+=?batchedStreamLengths[i];??? ?
- ????????????????ensurePacketSize?+=?batchedStreamLengths[i];??? ?
- ????????????}??? ?
- ????????????}??? ?
- ????????}??? ?
- ????????}??? ?
- ?? ?
- ?? ?
- ????????/*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer?? ?
- /*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer?? ?
- */?? ?
- */?? ?
- ????????if?(ensurePacketSize?!=?0)?{??? ?
- if?(ensurePacketSize?!=?0)?{??? ?
- ????????????sendPacket.ensureCapacity(ensurePacketSize);??? ?
- ????????????sendPacket.ensureCapacity(ensurePacketSize);??? ?
- ????????}??? ?
- ????????}??? ?
- ?? ?
- ?? ?
- ????????/*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。?? ?
- /*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。?? ?
- */?? ?
- */?? ?
- ????????for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
- for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{??? ?
- ?? ?
- ?? ?
- ????????/*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。?? ?
- /*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。?? ?
- */?? ?
- */?? ?
- ????????????if?((batchedParameterStrings[i]?==?null)??? ?
- if?((batchedParameterStrings[i]?==?null)??? ?
- ????????????????????&&?(batchedParameterStreams[i]?==?null))?{??? ?
- ????????????????????&&?(batchedParameterStreams[i]?==?null))?{??? ?
- ????????????????throw?SQLError.createSQLException(Messages??? ?
- throw?SQLError.createSQLException(Messages??? ?
- ????????????????????????.getString("PreparedStatement.40")?//$NON-NLS-1$??? ?
- ????????????????????????.getString("PreparedStatement.40")?//$NON-NLS-1$??? ?
- ????????????????????????+?(i?+?1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS);??? ?
- 1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS);??? ?
- ????????????}??? ?
- ????????????}??? ?
- ?? ?
- ?? ?
- ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。?? ?
- ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。?? ?
- */?? ?
- */?? ?
- ????????????sendPacket.writeBytesNoNull(this.staticSqlStrings[i]);??? ?
- ????????????sendPacket.writeBytesNoNull(this.staticSqlStrings[i]);??? ?
- ?? ?
- ?? ?
- ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。?? ?
- ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。?? ?
- */?? ?
- */?? ?
- ????????????if?(batchedIsStream[i])?{??? ?
- ????????????if?(batchedIsStream[i])?{??? ?
- ????????????????streamToBytes(sendPacket,?batchedParameterStreams[i],?true,??? ?
- true,??? ?
- ????????????????????????batchedStreamLengths[i],?useStreamLengths);??? ?
- ????????????????????????batchedStreamLengths[i],?useStreamLengths);??? ?
- ????????????}?else?{??? ?
- else?{??? ?
- ??????????????? ?
- ??????????????? ?
- ????????/*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。?? ?
- /*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。?? ?
- */?? ?
- */?? ?
- ????sendPacket.writeBytesNoNull(batchedParameterStrings[i]);??? ?
- ????sendPacket.writeBytesNoNull(batchedParameterStrings[i]);??? ?
- ????????????}??? ?
- ????????????}??? ?
- ????????}??? ?
- ????????}??? ?
- ?? ?
- ?? ?
- ????????/*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。?? ?
- /*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。?? ?
- */?? ?
- */?? ?
- ????????sendPacket??? ?
- ????????sendPacket??? ?
- ????????????????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]);??? ?
- ????????????????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]);??? ?
- ?? ?
- ?? ?
- ????????return?sendPacket;??? ?
- ????????return?sendPacket;??? ?
- ????}?? ?
- ????}?? ?
- ?protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings, ?
- ?protected?Buffer?fillSendPacket(byte[][]?batchedParameterStrings, ?
- ???InputStream[]?batchedParameterStreams,?boolean[]?batchedIsStream, ?
- boolean[]?batchedIsStream, ?
- ???int[]?batchedStreamLengths)?throws?SQLException?{ ?
- ???int[]?batchedStreamLengths)?throws?SQLException?{ ?
- ????????//?从connection的IO中得到发送数据包,首先清空其中的数据 ?
- //?从connection的IO中得到发送数据包,首先清空其中的数据 ?
- ??Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket(); ?
- ??Buffer?sendPacket?=?this.connection.getIO().getSharedSendPacket(); ?
- ??sendPacket.clear(); ?
- ??sendPacket.clear(); ?
- ???????? ?
- ???????? ?
- ????????/*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。 ?
- /*?数据包的第一位为一个操作标识符(MysqlDefs.QUERY),表示驱动向服务器发送的连接的操作信号,包括有QUERY,?PING,?RELOAD,?SHUTDOWN,?PROCESS_INFO,?QUIT,?SLEEP等等,这个操作信号并不是针对sql语句操作而言的CRUD操作,从提供的几种参数来看,这个操作是针对服务器的一个操作。一般而言,使用到的都是MysqlDefs.QUERY,表示发送的是要执行sql语句的操作。 ?
- */?
- */?
- ??sendPacket.writeByte((byte)?MysqlDefs.QUERY); ?
- byte)?MysqlDefs.QUERY); ?
- ?
- ?
- ??boolean?useStreamLengths?=?this.connection ?
- boolean?useStreamLengths?=?this.connection ?
- ????.getUseStreamLengthsInPrepStmts(); ?
- ????.getUseStreamLengthsInPrepStmts(); ?
- ?
- ?
- ??int?ensurePacketSize?=?0; ?
- ??int?ensurePacketSize?=?0; ?
- ??for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
- for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
- ???if?(batchedIsStream[i]?&&?useStreamLengths)?{ ?
- ???if?(batchedIsStream[i]?&&?useStreamLengths)?{ ?
- ????ensurePacketSize?+=?batchedStreamLengths[i]; ?
- ????ensurePacketSize?+=?batchedStreamLengths[i]; ?
- ???} ?
- ???} ?
- ??} ?
- ??} ?
- ?
- ?
- ????????/*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer ?
- /*?判断这个sendPacket的byte?buffer够不够大,不够大的话,按照1.25倍来扩充buffer ?
- */?
- */?
- ??if?(ensurePacketSize?!=?0)?{ ?
- if?(ensurePacketSize?!=?0)?{ ?
- ???sendPacket.ensureCapacity(ensurePacketSize); ?
- ???sendPacket.ensureCapacity(ensurePacketSize); ?
- ??} ?
- ??} ?
- ?
- ?
- ????????/*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。 ?
- /*?遍历所有的参数。在prepareStatement阶段的new?ParseInfo()中,驱动曾经对sql语句进行过分割,如果含有以问号标识的参数占位符的话,就记录下这个占位符的位置,依据这个位置把sql分割成多段,放在了一个名为staticSql的字符串中。这里就开始把sql语句进行拼装,把staticSql和parameterValues进行组合,放在操作符的后面。 ?
- */?
- */?
- ??for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
- for?(int?i?=?0;?i?<?batchedParameterStrings.length;?i++)?{ ?
- ?
- ?
- ????????/*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。 ?
- /*?batchedParameterStrings就是parameterValues,batchedParameterStreams就是parameterStreams,如果两者都为null,说明在参数的设置过程中出了错,立即抛出错误。 ?
- */?
- */?
- ???if?((batchedParameterStrings[i]?==?null) ?
- if?((batchedParameterStrings[i]?==?null) ?
- ?????&&?(batchedParameterStreams[i]?==?null))?{ ?
- ?????&&?(batchedParameterStreams[i]?==?null))?{ ?
- ????throw?SQLError.createSQLException(Messages ?
- throw?SQLError.createSQLException(Messages ?
- ??????.getString("PreparedStatement.40")?//$NON-NLS-1$ ?
- ??????.getString("PreparedStatement.40")?//$NON-NLS-1$ ?
- ??????+?(i?+?1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS); ?
- 1),?SQLError.SQL_STATE_WRONG_NO_OF_PARAMETERS); ?
- ???} ?
- ???} ?
- ?
- ?
- ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。 ?
- ????????/*在sendPacket中加入staticSql数组中的元素,就是分割出来的没有”?”的sql语句,并把字符串转换成byte。 ?
- */?
- */?
- ???sendPacket.writeBytesNoNull(this.staticSqlStrings[i]); ?
- ???sendPacket.writeBytesNoNull(this.staticSqlStrings[i]); ?
- ?
- ?
- ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。 ?
- ????????/*?batchedIsStream就是isStream,如果参数是通过CallableStatement传递进来的话,batchedIsStream[i]==true,就用batchedParameterStreams中的值填充到问号占的参数位置中去。 ?
- */?
- */?
- ???if?(batchedIsStream[i])?{ ?
- ???if?(batchedIsStream[i])?{ ?
- ????streamToBytes(sendPacket,?batchedParameterStreams[i],?true, ?
- true, ?
- ??????batchedStreamLengths[i],?useStreamLengths); ?
- ??????batchedStreamLengths[i],?useStreamLengths); ?
- ???}?else?{ ?
- else?{ ?
- ??? ?
- ??? ?
- ????????/*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。 ?
- /*否则的话,就用batchedParameterStrings,也就是parameterValues来填充参数位置。在循环中,这个操作是跟在staticSql后面的,因此就把第i个参数加到了第i个staticSql段中。参考前面的staticSql的例子,发现当循环结束的时候,原始sql语句最后一个”?”之前的sql语句就拼成了正确的语句了。 ?
- */?
- */?
- ?sendPacket.writeBytesNoNull(batchedParameterStrings[i]); ?
- ?sendPacket.writeBytesNoNull(batchedParameterStrings[i]); ?
- ???} ?
- ???} ?
- ??} ?
- ??} ?
- ?
- ?
- ????????/*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。 ?
- /*由于在原始的包含问号的sql语句中,在最后一个”?”后面可能还有order?by等语句,因此staticSql数组中的元素个数一定比参数的个数多1,所以这里把staticSqlString中的最后一段sql语句放入sendPacket中。 ?
- */?
- */?
- ??sendPacket ?
- ??sendPacket ?
- ????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]); ?
- ????.writeBytesNoNull(this.staticSqlStrings[batchedParameterStrings.length]); ?
- ?
- ?
- ??return?sendPacket; ?
- ??return?sendPacket; ?
- ?}?
- ?}?
- while?(len?>=?this.maxThreeBytes)?{??? ?
- while?(len?>=?this.maxThreeBytes)?{??? ?
- ????this.packetSequence++;??? ?
- this.packetSequence++;??? ?
- ????/*设置包的开始位置*/?? ?
- ????/*设置包的开始位置*/?? ?
- ???headerPacket.setPosition(0);???? ?
- 0);???? ?
- ????/*设置这个数据包的大小,splitSize=255?*?255?*?255*/?? ?
- ????/*设置这个数据包的大小,splitSize=255?*?255?*?255*/?? ?
- ????headerPacket.writeLongInt(splitSize);???? ?
- ????headerPacket.writeLongInt(splitSize);???? ?
- ????/*设置数据包的序号*/?? ?
- ????/*设置数据包的序号*/?? ?
- ????headerPacket.writeByte(this.packetSequence);???? ?
- this.packetSequence);???? ?
- ????/*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?? ?
- ????/*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?? ?
- ????System.arraycopy(origPacketBytes,?originalPacketPos,??? ?
- ????System.arraycopy(origPacketBytes,?originalPacketPos,??? ?
- ????????headerPacketBytes,?4,?splitSize);??? ?
- ????????headerPacketBytes,?4,?splitSize);??? ?
- ?? ?
- ?? ?
- ????int?packetLen?=?splitSize?+?HEADER_LENGTH;??? ?
- ????int?packetLen?=?splitSize?+?HEADER_LENGTH;??? ?
- ????if?(!this.useCompression)?{??? ?
- if?(!this.useCompression)?{??? ?
- ????????this.mysqlOutput.write(headerPacketBytes,?0,??? ?
- ????????this.mysqlOutput.write(headerPacketBytes,?0,??? ?
- ????????????splitSize?+?HEADER_LENGTH);??? ?
- ????????????splitSize?+?HEADER_LENGTH);??? ?
- ????????this.mysqlOutput.flush();??? ?
- ????????this.mysqlOutput.flush();??? ?
- ????}?else?{??? ?
- else?{??? ?
- ????????Buffer?packetToSend;??? ?
- ????????Buffer?packetToSend;??? ?
- ?? ?
- ?? ?
- ????????headerPacket.setPosition(0);??? ?
- ????????headerPacket.setPosition(0);??? ?
- ????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH,??? ?
- ????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH,??? ?
- ????????????????splitSize,?HEADER_LENGTH);??? ?
- ????????????????splitSize,?HEADER_LENGTH);??? ?
- ????????packetLen?=?packetToSend.getPosition();??? ?
- ????????packetLen?=?packetToSend.getPosition();??? ?
- ????????/*往IO的output?stream中写数据*/?? ?
- ????????/*往IO的output?stream中写数据*/?? ?
- ????????this.mysqlOutput.write(packetToSend.getByteBuffer(),?0,??? ?
- this.mysqlOutput.write(packetToSend.getByteBuffer(),?0,??? ?
- ????????????packetLen);??? ?
- ????????????packetLen);??? ?
- ????????this.mysqlOutput.flush();??? ?
- this.mysqlOutput.flush();??? ?
- ????}??? ?
- ????}??? ?
- ?? ?
- ?? ?
- ????originalPacketPos?+=?splitSize;??? ?
- ????originalPacketPos?+=?splitSize;??? ?
- ????len?-=?splitSize;??? ?
- ????len?-=?splitSize;??? ?
- }?? ?
- }?? ?
- ????????????while?(len?>=?this.maxThreeBytes)?{ ?
- while?(len?>=?this.maxThreeBytes)?{ ?
- ????????????????this.packetSequence++; ?
- ????????????????this.packetSequence++; ?
- ????????????????/*设置包的开始位置*/?
- /*设置包的开始位置*/?
- ????①??????????headerPacket.setPosition(0);? ?
- ????①??????????headerPacket.setPosition(0);? ?
- ????????????????/*设置这个数据包的大小,splitSize=255?*?255?*?255*/?
- /*设置这个数据包的大小,splitSize=255?*?255?*?255*/?
- ????????????????headerPacket.writeLongInt(splitSize);? ?
- ????????????????headerPacket.writeLongInt(splitSize);? ?
- ????????????????/*设置数据包的序号*/?
- /*设置数据包的序号*/?
- ????????????????headerPacket.writeByte(this.packetSequence);? ?
- ????????????????headerPacket.writeByte(this.packetSequence);? ?
- ????????????????/*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?
- /*origPacketBytes就是sendPacket,所以这里就是把sendPacket中大小为255?*?255?*?255的数据放入headPacket中,headerPacketBytes是headPacket的byte?buffer*/?
- ????????????????System.arraycopy(origPacketBytes,?originalPacketPos, ?
- ????????????????System.arraycopy(origPacketBytes,?originalPacketPos, ?
- ????????????????????headerPacketBytes,?4,?splitSize); ?
- 4,?splitSize); ?
- ?
- ?
- ????????????????int?packetLen?=?splitSize?+?HEADER_LENGTH; ?
- int?packetLen?=?splitSize?+?HEADER_LENGTH; ?
- ????????????????if?(!this.useCompression)?{ ?
- ????????????????if?(!this.useCompression)?{ ?
- ????????????????????this.mysqlOutput.write(headerPacketBytes,?0, ?
- this.mysqlOutput.write(headerPacketBytes,?0, ?
- ????????????????????????splitSize?+?HEADER_LENGTH); ?
- ????????????????????????splitSize?+?HEADER_LENGTH); ?
- ????????????????????this.mysqlOutput.flush(); ?
- this.mysqlOutput.flush(); ?
- ????????????????}?else?{ ?
- ????????????????}?else?{ ?
- ????????????????????Buffer?packetToSend; ?
- ????????????????????Buffer?packetToSend; ?
- ?
- ?
- ????????????????????headerPacket.setPosition(0); ?
- 0); ?
- ????????????????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH, ?
- ????????????????????packetToSend?=?compressPacket(headerPacket,?HEADER_LENGTH, ?
- ????????????????????????????splitSize,?HEADER_LENGTH); ?
- ????????????????????????????splitSize,?HEADER_LENGTH); ?
- ????????????????????packetLen?=?packetToSend.getPosition(); ?
- ????????????????????packetLen?=?packetToSend.getPosition(); ?
- ????????????????????/*往IO的output?stream中写数据*/?
- /*往IO的output?stream中写数据*/?
- ????????????????????this.mysqlOutput.write(packetToSend.getByteBuffer(),?0, ?
- ????????????????????this.mysqlOutput.write(packetToSend.getByteBuffer(),?0, ?
- ????????????????????????packetLen); ?
- ????????????????????????packetLen); ?
- ????????????????????this.mysqlOutput.flush(); ?
- ????????????????????this.mysqlOutput.flush(); ?
- ????????????????} ?
- ????????????????} ?
- ?
- ?
- ????????????????originalPacketPos?+=?splitSize; ?
- ????????????????originalPacketPos?+=?splitSize; ?
- ????????????????len?-=?splitSize; ?
- ????????????????len?-=?splitSize; ?
- ????????????}?
- ????????????}?
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()来建立连接了。

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

一旦有了一个statement,就可以通过执行statement.executeQuery()并通过ResultSet对象读出查询结果(如果查询有返回结果的话)。
创建statement的方法一般都有重载,我们看下面的prepareStatement:
public java.sql.PreparedStatement prepareStatement(String sql,
?
如果没有指定resultSetType和resultSetConcurrency的话,会给它们默认设置一个值。?
prepareStatement的创建如下图所示:

在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的时序图再理一下思路就更清楚了。

至此,把resultSet一步步的返回给dao,接下来的过程,就是从resultSet中取出rowData,组合成我们自己需要的对象数据了。
总结一下,经过这次对mysql驱动的探索,我发现了更多关于mysql的底层细节,对于以后分析问题解决问题有很大帮助,当然,这里面还有很多细节文中没有写。另外一个就是对于PreparedStatement有了重新的认识,有些东西往往都是想当然得出来的结论,真相还是要靠实践来发现。