说一下使用jdbc时涉及到的一些基本的接口和类
java.sql.Driver
是数据库驱动接口,com.mysql.jdbc.Driver是mysql对应的驱动,由数据库供应商实现,用于提供驱动,实现了java.sql.Driver接口。
java.sql.DriverManager
管理驱动的类,可以使用DriverManager通过驱动来获取数据库连接。
java.sql.Connection
对数据库连接进行管理的接口,一个Connection就相当于一个通往对应数据库的通道。
对以上几个做一个详细介绍,直接看源码:
//com.mysql.jdbc.Driver 实现了 java.sql.Driver接口
public class Driver extends NonRegisteringDriver implements java.sql.Driver {//向驱动管理器注册自己static {try {java.sql.DriverManager.registerDriver(new Driver());} catch (SQLException E) {throw new RuntimeException("Can't register driver!");}}//构造一个 com.mysql.jdbc.Driver 用于注册public Driver() throws SQLException {// Required for Class.forName().newInstance()}
}// 驱动管理器类中,看一下如何注册驱动、获取数据库连接的
public class DriverManager {//注册驱动最终调用的方法public static synchronized void registerDriver(java.sql.Driver driver, DriverAction da) throws SQLException {//如果驱动程序还没有添加到列表 registeredDrivers 中,请注册它if(driver != null) {registeredDrivers.addIfAbsent(new DriverInfo(driver, da));} else {throw new NullPointerException();}}//获取连接最终调用的方法private static Connection getConnection( String url, java.util.Properties info, Class<?> caller) throws SQLException {//当callerCl为null时,我们应该检查应用程序(它间接调用这个类)的类加载器,//这样就可以从这里加载rt.jar外部的JDBC驱动程序类。ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;synchronized(DriverManager.class) {if (callerCL == null) {callerCL = Thread.currentThread().getContextClassLoader();}}// 遍历试图建立连接的已加载的 registeredDrivers。 for(DriverInfo aDriver : registeredDrivers) {// 如果调用方没有加载驱动程序的权限,那么跳过它。if(isDriverAllowed(aDriver.driver, callerCL)) {Connection con = aDriver.driver.connect(url, info);if (con != null) { return (con);}}} }
}
java.sql.Statement
对数据库操作的一个接口,可以发送sql、执行sql,它是先组装sql,然后发送sql查询结果,因此存在缺陷,其缺陷在于它发送的sql是将参数拼接完之后再进行编译的,所以容易发生sql注入攻击的危险,一般不用,这里不做详细介绍。
何为sql注入攻击,例如:发送的如下SQL
"SELECT * FROM USER WHERE USER_NAME = "+ USER_NAME +"AND PWD = "+PWD;
这时我这样设置:USER_NAME = user | PWD = 111 or 1=1,则SQL就会变成
SELECT * FROM USER WHERE USER_NAME = user AND PWD = 111 or 1=1
这样就直接规避掉了用户名和密码的校验。
java.sql.PreparedStatement
对数据库操作的一个接口,可以发送sql、执行sql,在获取PreparedStatement对象时,就已经将sql发送出去编译成了可执行的sql语句,也就是常说的预编译,SQL中使用占位符的方式来表示参数,占位符的地方只是参数,不能所作sql中固定的语法
例如:发送的sql="SELECT * FROM USER WHERE USER_NAME = ? AND PWD = ?";
然后再另外使用方法的方式去设置 ? 占位符处的参数,防止了sql注入的风险,通过Connection接口的connection.prepareStatement(sql)方法获取PreparedStatement,具体实现调用的是 com.mysql.jdbc.ConnectionImpl 中的方法。
java.sql.CallableStatement
和 PreparedStatement 功能大致相同,只是CallableStatement对象可以用于执行存储过程,而PreparedStatement只可以执行基本的SQL语句。
java.sql.ResultSet
用于存储查询返回的结果集,对于mysql来说,最终是通过com.mysql.jdbc.PreparedStatement中的方法获取的ResultSet对象。
java.sql.DatabaseMetaData
此对象用于获取数据库的整体综合信息,可以使用Connection对象的connection.getMetaData()方法直接获取。
java.sql.ResultSetMetaData
用于获取关于ResultSet对象中列的类型和属性信息,通过ResultSet对象的resultSet.getMetaData()方法直接获取。
java.sql.Types
这个类中定义了用于标识SQL类型的常量,称为JDBC类型。
这里总结一下:开发者使用jdbc操作数据库时,添加驱动时需要添加对应数据库厂商提供的驱动包中的Driver,而后具体操作时,直接调用 java.sql.* 包中接口的方法即可,最终底层调用的是对应数据库厂商提供的com.*.jdbc.*包中的实现类中的方法,数据库厂商提供的驱动包实现了java.sql.*包中接口的方法,这就是代码层面上的jdbc。java提供一组接口,数据库厂商实现这些接口,根据自身的特点编写不同的实现,而程序员只需使用java中的接口即可,利用了多态的方式。