JDBC详解


1.概述

jdbc是什么?

JDBC英文名为:

Java Data Base Connectivity(Java数据库连接),从编程的角度来看,JDBC API是一组Java类和方法,它们允许将数据库调用嵌入到服务器应用程序中。更具体地说,JDBC规范是每个JDBC驱动程序供应商都必须实现的一组接口。驱动程序处理应用程序中的JDBC语句,并将它们包含的SQL参数路由到数据库引擎

简单说它就是JAVA与数据库的连接的桥梁或者插件,用JAVA代码就能操作数据库的增删改查、存储过程、事务等

该图说明了应用程序组件如何使用JDBC与数据库进行交互。

JDBC的结构如下图

img

JDBC的作用

  • 加载对应数据库驱动 (Load Driver)

  • 与数据库建立连接(connection)

  • 发送 操作数据库的语句(createStatement)

  • 执行并处理返回结果(executeQuery)

    这里写图片描述

    1-1

他们的流程图则是在下面

img

1-2

如上两个图可以十分清晰的看出来整个JDBC的运行方式.我们就一个一个的讲解

加载对应数据库驱动 (Load Driver)

这个部分是图1-1的①部分,图1-2的开始到Driver的那条线.

public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			Class.forName("oracle.jdbc.OracleDriver");//显式地加载 JDBC 驱动程序。
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} // 创建连接得部分	
	}

到这里你可能想问Class.forName("oracle.jdbc.OracleDriver")是啥.

这个就比较复杂,涉及到了反射相关的知识.在这里简述一下.(不看也没啥,反正JDBC里面把这句话背下来就行)


条子的拖堂时间

java是面向对象语言,最独特的特点就是一切皆为对象.

但是对象还是有区别的,主要分为两种.

一种是实例对象.(就是用new生成那个,你平时总用.)

一种则是Class对象(没错,就叫这个名字,首字母大写.不是我神经失常又写了一遍).

这个Class对象中包含的是每个类的运行时的类型信息.所有与类有关的信息全在里面.

其实我们的实例对象就是靠Class对象来创建的.

每当编译产生一个新类就产生一个Class对象.

可能你想问了,为什么我平时没见过这个Class对象?

这就对了,因为Class对象没有公共的构造方法,Class对象实在类加载时由java虚拟机以及通过类加载器中的defineClass方法自动构建的.所以你是没有办法声明Class对象的.

一个类加载到虚拟机需要以下三个步骤:

Class.forName("oracle.jdbc.OracleDriver");也是执行下面三个步骤.

  • 加载

    这是由类加载器(ClassLoader)执行的。通过一个类的全限定名来获取其定义的二进制字节流(Class字节码),将这个字节流所代表的静态存储结构转化为方法去的运行时数据接口,根据字节码在java堆中生成一个代表这个类的java.lang.Class对象。

  • 链接

    在链接阶段将验证Class文件中的字节流包含的信息是否符合当前虚拟机的要求,为静态域分配存储空间并设置类变量的初始值(默认的零值),并且如果必需的话,将常量池中的符号引用转化为直接引用。

  • 初始化

    到了此阶段,才真正开始执行类中定义的java程序代码。用于执行该类的静态初始器和静态初始块,如果该类有父类的话,则优先对其父类进行初始化。(赋值也是此阶段)

所有的类都是在对其第一次使用时,动态加载到JVM中的(懒加载)。当程序创建第一个对类的静态成员的引用时,就会加载这个类

而我们的Class.forName("oracle.jdbc.OracleDriver");的作用就是加载这个类,并返回与带有给定字符串名的类或接口相关联的 Class 对象.

 2、类的初始化过程与类的实例化过程的异同?

  类的初始化是指类加载过程中的初始化阶段对类变量按照程序猿的意图进行赋值的过程;而类的实例化是指在类完全加载到内存中后创建对象的过程。

初始化和实例化的区别

其实你只要看过oracle.jdbc.OracleDriver源码就知道,在其中有大量的静态变量.

 public static final char slash_character = '/';
    public static final char at_sign_character = '@';
    public static final char left_square_bracket_character = '[';
    public static final char right_square_bracket_character = ']';
    public static final String oracle_string = "oracle";
    public static final String protocol_string = "protocol";
    public static final String user_string = "user";
    public static final String password_string = "password";
    public static final String database_string = "database";
    public static final String server_string = "server";
//很多很多

源码

调用这个源码后,这些个代码会被直接被赋值.

同时还有在网上找到一个博文,其中发现

Class.forName(driver)的根本目的就是为了调用DriverManager.registerDriver。

jdbc中的class.forName详解

还有另外一篇博文,从mysql方面论证了这个情况,如下是MYSQL中的代码,可以看到也有一个同样的static代码块.

这个是图1-1JDBCDriver到DriverManager的那条线,图1-2 Driver到DriverManager那条线.

package com.mysql.jdbc    
   
public class Driver extends NonRegisteringDriver implements java.sql.Driver {    
 // ~ Static fields/initializers    
 // --------------------------------------------- //    
 // Register ourselves with the DriverManager    
 //    
 static {    
    t ry {    
              java.sql.DriverManager.registerDriver(new Driver());//将Driver注册给DriverManager    
          } catch (SQLException E) {    
              throw new RuntimeException("Can't register driver!");    
          }  //这个是图1-1JDBCDriver到DriverManager的那条线,图1-2Driver到DriverManager
     /**
     
  }    
// ~ Constructors    
 // -----------------------------------------------------------    
/**   
  * Construct a new driver and register it with DriverManager   
  *    
  * @throws SQLException   
  *             if a database error occurs.   
  */   
 public Driver() throws SQLException {    
     // Required for Class.forName().newInstance()    
 }    
}   
//从而通过Class.forName(DriverString)会向DriverManager注册该Driver类.所以可以直接调用.而Class.forName("").newInstance()则等于是将该Driver驱动类实例化,返回该类的一个实例,所以,如果只是取JDBC的Driver驱动,可以不必用newInstance().
————————————————
版权声明:本文为CSDN博主「jackterq」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jackterq/java/article/details/4480745
    
    

你可能要问了为什么这个直接加载了就行呢?不是要实例化才能调用其中的方法吗(也未必哈).只是加载到JVM中有啥用啊!!

解释就在下面:

如下是一段英文,讲解了如下内容,就是跟你讲,Driver只要注册进虚拟机就ok了,没必要生成实例.因为生成了实例你也用不到.

we just want to load the driver to jvm only, but not need to user the instance of driver, so call Class.forName(xxx.xx.xx) is enough, if you call Class.forName(xxx.xx.xx).newInstance(), the result will same as calling Class.forName(xxx.xx.xx), because Class.forName(xxx.xx.xx).newInstance() will load driver first, and then create instance, but the instacne you will never use in usual, so you need not to create it.
————————————————
版权声明:本文为CSDN博主「jackterq」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jackterq/java/article/details/4480745

其实这也解释了为什么

当然,他用的版本应该是jdbc4之前的.

所以加载Class.forName("oracle.jdbc.OracleDriver")的作用可以称之为为链接建立好准备,让之后的DriverManager.getConnection("jdbc:oracle:thin:@192.168.80.10:1521:orcl","system","aA107824");有运行的基础.

jdk6为什么不需要 执行了Class.forName这行代码了呢,是怎么回事?

大家先了解一下ServiceLoader 。

简单来说就是在驱动jar包配置文件中,指定oracle.jdbc.driver.OracleDriver(驱动实例)实现java.sql.Driver接口;然后DriverManager在初始化的时候,自动扫描所有jar包中实现了java.sql.Driver的类 ,并初始化 此实现类

//DriverManager
   static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
    private static void loadInitialDrivers() {
       ...
        
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                //搜索服务的实现类(驱动实例)
                ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
                Iterator<Driver> driversIterator = loadedDrivers.iterator();//这个明显实现了Iterator接口,可以迭代.也就是搜索所有驱动.
                try{
                    while(driversIterator.hasNext()) {
                        driversIterator.next();// 此处初始化  并注册了
                    }
                } catch(Throwable t) {
                // Do nothing
                }
                return null;
 
 
//ServiceLoader
       public S next() {
            if (acc == null) {
                return nextService();
            } else {
        ...
 
//ServiceLoader
       private S nextService() {
            ...
            try {
                c = Class.forName(cn, false, loader);//这个就是注册驱动的代码.看看和我们前一个部分长得像不像
            ...

也就是说 DriverManger借助 ServiceLoader 找到驱动 并注册了,所以不需要再手工注册

作者:氨基钠
链接:https://www.jianshu.com/p/d0d646b2070c
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

ok废话完了!


与数据库建立连接(connection)

Connection connection=DriverManager.getConnection(
    "jdbc:oracle:thin:@192.168.80.10:1521:orcl", //你的Oracle数据库URL
    // 192.168.80.10 这个部分改成你的数据库地址或者localhost : 1521//这个是端口号 : orcl //这个是实例名
    "system",//你的oracle数据库帐号
    "aA107824"//你的oracle数据库密码
);

作为新手,你记住这部分就可以了.


条子的拖堂时间

DriverManager的一些理论知识

作为初始化的一部分,DriverManager 类会尝试加载在 "jdbc.drivers" 系统属性中引用的驱动程序类。
    //这就是在上面那个拖堂时间讲的oracle.jdbc.OracleDriver实际上是一个驱动程序,被直接注册进DriverManger里,然后被DriverManger在初始化阶段加载
这允许用户自定义由他们的应用程序使用的 JDBC Driver.//没错你可以自己写一个驱动程序

DriverManager实现的功能

  • 连接功能

    你会发现实际上这个getConnection方法的主要执行部分在下面的private中,这也是一种很好的方法,可以保护自己的代码不被随便的改动.

       public static Connection getConnection(String url)
            throws SQLException {
    
            java.util.Properties info = new java.util.Properties();//这个是读取配置文件的类的实例
            return (getConnection(url, info, Reflection.getCallerClass()));
            //eflection.getCallerClass()可以得到调用者的类.这个方法是很好用的.
        }
    
        //  用于根据url、对应的属性信息在registeredDrivers中找到合适的注册的驱动创建数据库链接
        private static Connection getConnection(
            String url, java.util.Properties info, Class<?> caller) throws SQLException {
            /*
             * When callerCl is null, we should check the application's
             * (which is invoking this class indirectly)
             * classloader, so that the JDBC driver class outside rt.jar
             * can be loaded from here.
             */
            //这个意思如果为空,就说明并没有传入一个类加载器,那么就从线程上下获取加载器
            ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
            synchronized(DriverManager.class) {
                // synchronize loading of the correct classloader.
                if (callerCL == null) {
                     //获取线程上下文类加载器
                    callerCL = Thread.currentThread().getContextClassLoader();
                   
                }
            }
    //url没输入,报错
            if(url == null) {
                throw new SQLException("The url cannot be null", "08001");
            }
    
            println("DriverManager.getConnection("" + url + "")");
    
            // Walk through the loaded registeredDrivers attempting to make a connection.
            // Remember the first exception that gets raised so we can reraise it.
            SQLException reason = null;
    
            for(DriverInfo aDriver : registeredDrivers) {
                // If the caller does not have permission to load the driver then
                // skip it.
             //一个应用中有可能会有多个数据库驱动,需要判断数据库连接的调用者(调用getConnection()方法的对象)是否与驱动相匹配(别让Oracle调用了mysql的驱动)
                if(isDriverAllowed(aDriver.driver, callerCL)) {
                    try {
                        println("    trying " + aDriver.driver.getClass().getName());
                        Connection con = aDriver.driver.connect(url, info);
                        if (con != null) {
                            // Success!
                            println("getConnection returning " + aDriver.driver.getClass().getName());
                            return (con);
                        }
                    } catch (SQLException ex) {
                        if (reason == null) {
                            reason = ex;
                        }
                    }
    
                } else {
                    println("    skipping: " + aDriver.getClass().getName());
                }
    
            }
    
            // if we got here nobody could connect.
            if (reason != null)    {
                println("getConnection failed: " + reason);
                throw reason;
            }
    
            println("getConnection: no suitable driver found for "+ url);
            throw new SQLException("No suitable driver found for "+ url, "08001");
        }
    }
    

    如下这个内容是判断,你加载的驱动是否和调用类使用的是同一个类加载器.要是不使用同一个加载器,他们会相互不可见,进而无法使用.

    private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
            boolean result = false;
            if(driver != null) {
                Class<?> aClass = null;
                try {
                    aClass =  Class.forName(driver.getClass().getName(), true, classLoader);//方法获得类,该方法返回与给定字符串名的类或接口的Class对象,使用给定的类加载器进行加载,然后通过
                } catch (Exception ex) {
                    result = false;
                }
    
                 result = ( aClass == driver.getClass() ) ? true : false;//如果不是同一个加载器这个值不会相等.
            }
    
            return result;
        }
    

    整体的源码:

     @CallerSensitive
        public static Connection getConnection(String url)
            throws SQLException {
    
            java.util.Properties info = new java.util.Properties();//这个是读取配置文件的类的实例
            return (getConnection(url, info, Reflection.getCallerClass()));
            //eflection.getCallerClass()可以得到调用者的类.这个方法是很好用的.
        }
    
        //  用于根据url、对应的属性信息在registeredDrivers中找到合适的注册的驱动创建数据库链接
        private static Connection getConnection(
            String url, java.util.Properties info, Class<?> caller) throws SQLException {
            /*
             * When callerCl is null, we should check the application's
             * (which is invoking this class indirectly)
             * classloader, so that the JDBC driver class outside rt.jar
             * can be loaded from here.
             */
            //这个意思如果为空,就说明并没有注册驱动程序,需要检查.
            ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
            synchronized(DriverManager.class) {
                // synchronize loading of the correct classloader.
                if (callerCL == null) {
                    callerCL = Thread.currentThread().getContextClassLoader();
                }
            }
    
            if(url == null) {
                throw new SQLException("The url cannot be null", "08001");
            }
    
            println("DriverManager.getConnection("" + url + "")");
    
            // Walk through the loaded registeredDrivers attempting to make a connection.
            // Remember the first exception that gets raised so we can reraise it.
            SQLException reason = null;
    
            for(DriverInfo aDriver : registeredDrivers) {
                // If the caller does not have permission to load the driver then
                // skip it.
             //一个应用中有可能会有多个数据库驱动,需要判断数据库连接的调用者(调用getConnection()方法的对象)是否与驱动相匹配
                if(isDriverAllowed(aDriver.driver, callerCL)) {
                    try {
                        println("    trying " + aDriver.driver.getClass().getName());
                        Connection con = aDriver.driver.connect(url, info);
                        if (con != null) {
                            // Success!
                            println("getConnection returning " + aDriver.driver.getClass().getName());
                            return (con);
                        }
                    } catch (SQLException ex) {
                        if (reason == null) {
                            reason = ex;
                        }
                    }
    
                } else {
                    println("    skipping: " + aDriver.getClass().getName());
                }
    
            }
    
            // if we got here nobody could connect.
            if (reason != null)    {
                println("getConnection failed: " + reason);
                throw reason;
            }
    
            println("getConnection: no suitable driver found for "+ url);
            throw new SQLException("No suitable driver found for "+ url, "08001");
        }
    }
    
    //一个应用中有可能会有多个数据库驱动,需要判断数据库连接的调用者(调用getConnection()方法的对象)是否与驱动相匹配
    private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
            boolean result = false;
            if(driver != null) {
                Class<?> aClass = null;
                try {
                    aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
                } catch (Exception ex) {
                    result = false;
                }
    
                 result = ( aClass == driver.getClass() ) ? true : false;
            }
    
            return result;
        }
    
    

DriverManager的源码

/**管理一个集合JDBC驱动的基础服务
注意:在新的JDBC2.0api中实现了新的DataSource接口,提供了另一种链接数据源的方式。
使用DataSource的对象是首选方案
*/
public class DriverManager {

    // 注册了JDBC驱动的集合,记不记得上面讲的注册过程.这个就是那个形成的东西
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
    
  
    /**
    通过检查jdcb.properties加载初始化JDBC驱动
     */
    static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }

/*
*对外使用提供数据库连接的方法,
*重点说明Reflection.getCallerClass()方法,该方法返回调用者的类
*/
    @CallerSensitive
    public static Connection getConnection(String url)
        throws SQLException {

        java.util.Properties info = new java.util.Properties();
        return (getConnection(url, info, Reflection.getCallerClass()));
    }

    //  用于根据url、对应的属性信息在registeredDrivers中找到合适的注册的驱动创建数据库链接
    private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {
        /*
         * When callerCl is null, we should check the application's
         * (which is invoking this class indirectly)
         * classloader, so that the JDBC driver class outside rt.jar
         * can be loaded from here.
         */
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
            // synchronize loading of the correct classloader.
            if (callerCL == null) {
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }

        if(url == null) {
            throw new SQLException("The url cannot be null", "08001");
        }

        println("DriverManager.getConnection("" + url + "")");

        // Walk through the loaded registeredDrivers attempting to make a connection.
        // Remember the first exception that gets raised so we can reraise it.
        SQLException reason = null;

        for(DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
         //一个应用中有可能会有多个数据库驱动,需要判断数据库连接的调用者(调用getConnection()方法的对象)是否与驱动相匹配
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }

        // if we got here nobody could connect.
        if (reason != null)    {
            println("getConnection failed: " + reason);
            throw reason;
        }

        println("getConnection: no suitable driver found for "+ url);
        throw new SQLException("No suitable driver found for "+ url, "08001");
    }
}


private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
        boolean result = false;
        if(driver != null) {
            Class<?> aClass = null;
            try {
                aClass =  Class.forName(driver.getClass().getName(), true, classLoader);
            } catch (Exception ex) {
                result = false;
            }

             result = ( aClass == driver.getClass() ) ? true : false;
        }

        return result;
    }

//根据URL从registeredDrivers 中获得驱动,根据Reflection.getCallerClass()返回的调用者类,在registeredDrivers 中进行匹配
//API文档:试图查找能理解给定 URL 的驱动程序。DriverManager 试图从已注册的驱动程序集中选择一个适当的驱动程序。
  @CallerSensitive
    public static Driver getDriver(String url)
        throws SQLException {

        println("DriverManager.getDriver("" + url + "")");

        Class<?> callerClass = Reflection.getCallerClass();

        // Walk through the loaded registeredDrivers attempting to locate someone
        // who understands the given URL.
        for (DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerClass)) {
                try {
                    if(aDriver.driver.acceptsURL(url)) {
                        // Success!
                        println("getDriver returning " + aDriver.driver.getClass().getName());
                    return (aDriver.driver);
                    }

                } catch(SQLException sqe) {
                    // Drop through and try the next driver.
                }
            } else {
                println("    skipping: " + aDriver.driver.getClass().getName());
            }

        }

        println("getDriver: no suitable driver");
        throw new SQLException("No suitable driver", "08001");
    }


/*
*注册数据驱动,使用同步方式,最终保存在CopyOnWriteArrayList的集合中
*/
    public static synchronized void registerDriver(java.sql.Driver driver,
            DriverAction da)
        throws SQLException {

        /* Register the driver if it has not already been added to our list */
        if(driver != null) {
            registeredDrivers.addIfAbsent(new DriverInfo(driver, da));
        } else {
            // This is for compatibility with the original DriverManager
            throw new NullPointerException();
        }

        println("registerDriver: " + driver);

    }

connection是一个接口,这个由DriverManger产生的东西有着数量众多的方法

Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.80.10:1521:orcl", "system","aA107824");
connection.SetAtuoCommit(true);//设置为自动提交状态
System.out.println(connection.getAutoCommit());// 检索此 Connection 对象的当前自动提交模式。
//true
 Statement statement=connection.createStatement();//创建一个statement对象,之后会讲
int count = statement.executeUpdate("insert into student values(5,'郭美美','女',58,'北京市海淀区')");
connection.commit();//手动提交代码
connection.rollback();//手动回滚更改
connection.close()://立刻关闭这个资源
connection.isclose();//true



发送 操作数据库的语句(createStatement)

这个部分就是到了创Statement的地方了

 try {
		  Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@192.168.80.10:1521:orcl","system","aA107824");
		  Statement statement=conn.createStatement();
	  }catch (SQLException e) {
		// TODO: handle exception
	e.printStackTrace();
	  }

新手看到这里就可以了

构建Statement的方法有很多种,这里挑两个主要讲

  • createStatement()方法
  • PreparedStatement()方法
  • 这两个方法最后返回的对象也是不同的

先来讲createStatement()方法.

这个方法分为很多个参数,从无参到很多参数都有,我们找一个全的讲.

Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
					ResultSet.CONCUR_UPDATABLE);

你可以发现这个方法里面有两个参数int resultSetTypeint resultSetConcurrency

  • resultSetType可填写的内容如下

    • TYPE_FORWARD_ONLYResultSet指针只能安装列顺序向前移动,也就是说在取得name列之后,将不能再返回获取id列的值
    • TYPE_SCROLL_INSENSITIVEResultSet指针可以前后移动,INSENSITIVE表示不及时更新,就是如果数据库里的数据修改过,并不在ResultSet中反映出来;
    • TYPE_SCROLL_SENSITIVEResultSet指针可以前后移动,SENSITIVE表示及时跟踪数据库的更新,以便更改ResultSet中的数据。
  • int resultSetConcurrency:可填写的内容如下

    • ResultSet.CONCUR_READ_ONLY

    • ResultSet.CONCUR_UPDATABLE


    当然讲到这里就要返回对象了 satement对象

    Statement 是 Java 执行数据库操作的一个重要接口,用于在已经建立数据库连接的基础上,向数据库发送要执行的SQL语句。Statement对象,用于执行不带参数的简单SQL语句。
    
    

Statement子接口有:CallableStatement, PreparedStatement。

Statement 接口提供了执行语句和获取结果的基本方法。PreparedStatement 接口添加了处理 IN 参数的方法;而 CallableStatement 添加了处理 OUT 参数的方法。


这也是图1-1和图1-2的最后一个部分**执行并处理返回结果(executeQuery)**

 `satement`对象的方法比较少,比较简单.

最主要的就是下面得这个方法,其作用是用各种方式向数据库发送SQL语句.

```java
//executeUpdate方法,向数据库传递增删改的SQL语句
int count = statement.executeUpdate("insert into student values(20,'郭美美','女',58,'北京市海淀区')");
//返回从数据库搜索的数据,用ResultSet格式存储.
ResultSet resultSet=statement.executeQuery("select*from student");
//获取结果集合的行数,该数是根据此 Statement 对象生成的 ResultSet 对象的默认获取大小。
statement.getFetchSize();//1,因为只插入了一条数据
//获取从数据库表获取行的方向,该方向是根据此 Statement 对象生成的结果集合的默认值。
statement.getFetchDirection()//1000,这个应该是一个常量,就是正向的意思
    //关闭staement对象,释放占有的jdbc资源,而不是等连接关闭的时候
 statement.close();   

在来讲PreparedStatement()方法

PreparedStatement是一种预编译的方法,可以有效地防止SQL注入的危险,所以在正常的情况下大部分都使用这个方法而不是createStatement()

这个方法不能一个个方法的讲解,会很乱.所以看一下下面得代码.

其中PreparedStatement statement2 = connection.prepareStatement("update student set sname=? where sid=? ");方法是用来创建一个PreparedStatement对象的.在这里面的问号就类似于参数.不填入数据,等着之后由程序员进行设置.

statement2.setString(1, "许佳琪");这句代码就是设置这个参数中的内容.第一个参数是?所在的位置.比如第一个?就填1,第二个?就填2.然后这个?所在位置的属性也决定了使用什么方法.比如在student表中sname是varchar2类型,那么这个时候就要用setString()方法.如果是个SID呢?

当然就是用setInt方法了.

这个在下面的例子中可以看出来.

但是光是设定了这个sql语句是没有效果的.

还要用excute()方法将这个语句发送到数据库中去才有效果.

一个小栗子:

	PreparedStatement statement2 = connection.prepareStatement("update student set sname=? where sid=? ");// 有一个预编译的过程.
			statement2.setString(1, "许佳琪");// 设置String的数据类型
			statement2.setInt(2, 4);// 设置int的数值类型,第一个参数是?所在的位置,比如sname=?是第一个?,sid=?是第二个问好.
//		   statement2.executeUpdate("insert into student values(3,'K律','女',57,'北京市')");//插入升级语句
			statement2.execute();// 似乎是必须有这一步,要不然发送不上去
			System.out.println("是否是自动提交模式" + connection.getAutoCommit());// getAutoCommit()用来判断是否是用来提交的
            connection.commit();

两个方法有什么不同?

其实主要是因为有一个预编译的过程

PreparedStatement和createStatement的不同.


以上就是JDBC的详解内容。相信你看了这个内容,就能对JDBC有一个比较深入的了解。

原文地址:https://www.cnblogs.com/yanzezhong/p/12678639.html