• maven之构建jdbc连oracle的四种方式实例和注册驱动源码浅析


       还是先来看看参考吧

    关于ServiceLoader的解释  http://blog.csdn.net/hintcnuie/article/details/37922089

    oracle数据库手册下载   很好的资源 强烈推荐   http://docs.oracle.com/cd/E11882_01/nav/portal_5.htm

    还有oracle官网下载的jdbc源码  http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html

    还有maven配置oracle的jdbc依赖  http://www.cnblogs.com/leiOOlei/archive/2013/10/21/3380568.html


    好的  还是看看 oracle官网的描述 

    Java Database Connectivity (JDBC) is a Java standard that provides the interface for connecting from Java to relational databases. The JDBC standard is defined by Sun Microsystems and implemented through the standard java.sql interfaces. This allows individual providers to implement and extend the standard with their own JDBC drivers. JDBC is based on the X/Open SQL Call Level Interface (CLI). JDBC 4.0 complies with the SQL 2003 standard.

    恩 就不翻译了 很简单 关键是 翻译了 也不太到位 哎

    oracle 按照功能与用途  支持了四种类型的驱动

    In addition to supporting the standard JDBC application programming interfaces (APIs), Oracle drivers have extensions to support Oracle-specific data types and to enhance performance.
    Oracle provides the following JDBC drivers:
    ■Thin driver
    It is a pure Java driver used on the client-side, without an Oracle client installation. It can be used with both applets and applications.
    ■Oracle Call Interface (OCI) driver
    It is used on the client-side with an Oracle client installation. It can be used only with applications.
    ■Server-side Thin driver
    It is functionally similar to the client-side Thin driver. However, it is used for code that runs on the database server and needs to access another session either on the same server or on a remote server on any tier.
    ■Server-side internal driver
    It is used for code that runs on the database server and accesses the same session. That is, the code runs and accesses data from a single Oracle session.


    还有一处 是oracle的jdbc的javadoc的 觉得也不错 贴出来 看看

    Oralce provides four types of JDBC driver.
    
    Thin Driver, a 100% Java driver for client-side use without an Oracle installation, particularly with applets. The Thin driver type is thin. To connect user scott with password tiger to a database with SID (system identifier) orcl through port 1521 of host myhost, using the Thin driver, you would write :
      Connection conn = DriverManager.getConnection
      ("jdbc:oracle:thin:@myhost:1521:orcl", "scott", "tiger");
      
    OCI Driver for client-side use with an Oracle client installation. The OCI driver type is oci. To connect user scott with password tiger to a database with SID (system identifier) orcl through port 1521 of host myhost, using the OCI driver, you would write :
      Connection conn = DriverManager.getConnection
      ("jdbc:oracle:oci:@myhost:1521:orcl", "scott", "tiger");
      
    Note that you can also specify the database by a TNSNAMES entry. You can find the available TNSNAMES entries listed in the file tnsnames.ora on the client computer from which you are connecting. For example, if you want to connect to the database on host myhost as user scott with password tiger that has a TNSNAMES entry of MyHostString, enter:
      Connection conn = DriverManager.getConnection
      ("jdbc:oracle:oci8:@MyHostString","scott","tiger");
      
    If your JDBC client and Oracle server are running on the same machine, the OCI driver can use IPC (InterProcess Communication) to connect to the database instead of a network connection. An IPC connection is much faster than a network connection.
      Connection conn = DriverManager.getConnection
      ("jdbc:oracle:oci8:@","scott","tiger");
      
    Server-Side Thin Driver, which is functionally the same as the client-side Thin driver, but is for code that runs inside an Oracle server and needs to access a remote server, including middle-tier scenarios. The Server-Side Thin driver type is thin and there is no difference in your code between using the Thin driver from a client application or from inside a server.
    Server-Side Internal Driver for code that runs inside the target server, that is, inside the Oracle server that it must access. The Server-Side Internal driver type is kprb and it actually runs within a default session. You are already "connected". Therefore the connection should never be closed.
    To access the default connection, write:
      DriverManager.getConnection("jdbc:oracle:kprb:");
      or:
      DriverManager.getConnection("jdbc:default:connection:");
      
    You can also use the Oracle-specific defaultConnection() method of the OracleDriver class which is generally recommended:
      OracleDriver ora = new OracleDriver();
      Connection conn = ora.defaultConnection();



    上面是  官方描述 很权威啊 下面是自己的总结  

    /**
     * 测试oracle 的三种连接方式 
     * 三种连接方式在使用上 没有太多的不一样 只是每个方式的使用定位  实现方式不一样
     * thin--多使用在web开发 通过tcp/ip的socket与服务器oracle的tcp/ip的socket监听器进行连接  进而与oracle服务器进行通信 属于第4类驱动 独立于平台的
     * oci--不太适合使用在web端 ,因为oracle call interface 通过jni调用本地oracle客户端的c库 从而实现与服务器oracle进行通信 属于第2类驱动
     * kprb(server-side internal driver)--为oracle服务器端内部的驱动 用于嵌入在服务器oracle中的java程序/jsp代码与oracle进行通信 连接使用当前会话用户名与密码 这个连接也不用关闭 使用的是kprb的c库进行通信
     * 还有一种 server-side thin  ----用于oracle服务器端内部需要访问远程服务器时使用或者是同一个数据库不同的session访问 例如调用中间件 与client thin没有太多的区别
     * @author Administrator
     *
     */

    还有一张oracle jdbc的驱动和oracle数据库的 关系图 



    好吧 还是来看看具体的例子吧

    1、客户端thin协议 也就是我们常用的jdbc:oracle:thin:@localhost:1521:orcl  

    thin--多使用在web开发 通过tcp/ip的socket与服务器oracle的tcp/ip的socket监听器进行连接  进而与oracle服务器进行通信 属于第4类驱动 独立于平台的

    package com.undergrowth.jdbc.thin;
    
    import java.sql.Connection;
    import java.sql.Driver;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Enumeration;
    import java.util.Iterator;
    import java.util.ServiceLoader;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import oracle.jdbc.OracleDriver;
    import oracle.jdbc.pool.OracleDataSource;
    
    /**
     * 测试连接oracle的thin协议
     * 来源于oracle的ojdbc6的例子
     * @author Administrator
     *
     */
    public class ThinTest {
    	
    	static final String connect_string = "jdbc:oracle:thin:u1/u1@//localhost:1521/orcl";
        static final Logger LOGGER=LoggerFactory.getLogger(ThinTest.class);
    	// This is the kind of string you would use if going through the
    	// Oracle 8 connection manager which lets you run the database on a
    	// different host than the Web Server. See the on-line documentation
    	// for more information.
    	// static final String connect_string =
    	// "jdbc:oracle:thin:hr/hr@(description=(address_list=(address=(protocol=tcp)(host=localhost)(port=1610))(address=(protocol=tcp)(host=localhost)(port=1521)))(source_route=yes)(connect_data=(service_name=orcl.oracle.com)))";
    
    	// The query we will execute
    	static final String query = "select 'Hello JDBC: ' || to_char(sysdate,'yyyy-mm-dd') from dual";
    	Connection conn;;
    	
    	StringBuffer output=new StringBuffer();
    	
    	public String testThin(){
    		try {
    
    			// See if we need to open the connection to the database
    			if (conn == null) {
    				// Create a OracleDataSource instance and set URL
    				OracleDataSource ods = new OracleDataSource();
    				ods.setURL(connect_string);
    
    				// Connect to the databse
    				output.append("Connecting to " + connect_string + "
    ");
    				conn = ods.getConnection();
    				output.append("Connected
    ");
    			}
    
    			// Create a statement
    			Statement stmt = conn.createStatement();
    
    			// Execute the query
    			output.append("Executing query " + query + "
    ");
    			ResultSet rset = stmt.executeQuery(query);
    
    			// Dump the result
    			while (rset.next())
    				output.append(rset.getString(1) + "
    ");
    
    			// We're done
    			output.append("done.
    ");
    			LOGGER.info(output.toString());
    		} catch (Exception e) {
    			e.printStackTrace();
    			// Oops
    			output.append(e.getMessage() + "
    ");
    			LOGGER.info(output.toString());
    		}finally{
    			if(conn!=null)
    			{
    				try {
    					conn.close();
    					conn=null;
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    		return output.toString();
    	}
    	
    	/**
    	 * 使用DriverManager进行注册驱动
    	 * @return
    	 */
    	public String testThinDriverManager(){
    		try {
    			output=new StringBuffer();
    			LOGGER.info("开始使用DriverManager进行驱动注册");	
    			//注册oracle jdbc驱动
    			//DriverManager.registerDriver(new OracleDriver());
    			Enumeration<Driver> driversEnumeration=DriverManager.getDrivers();
    			while(driversEnumeration.hasMoreElements()){
    				System.out.println(driversEnumeration.nextElement().toString());
    			}
    			if (conn == null) { 
    				// Create a OracleDataSource instance and set URL
    				//这里为什么不要  DriverManager.registerDriver(new OracleDriver())  这么一句话  哈哈  里面有很多学问啊
    				//简单的说 就是 DriverManager在类加载的时候 在一个静态块中执行了loadInitialDrivers方法 此方法使用
    				//ServiceLoader.load(Driver.class)的方式加载了位于ojdbc6-11.2.0.jar包下的meta-inf/services/java.sql.Driver文件中的oracle.jdbc.OracleDriver的驱动
    				//那为什么加载了oracle.jdbc.OracleDriver的驱动 就不需要注册了呢  原因在于 OracleDriver也有一个静态块里面有一个  DriverManager.registerDriver(m_defaultDriver);
    				//所以无需注册了
    				conn=DriverManager.getConnection(connect_string);
    				// Connect to the databse
    				output.append("Connecting to " + connect_string + "
    ");
    				output.append("Connected
    ");
    			}
    
    			// Create a statement
    			Statement stmt = conn.createStatement();
    
    			// Execute the query
    			output.append("Executing query " + query + "
    ");
    			ResultSet rset = stmt.executeQuery(query);
    
    			// Dump the result
    			while (rset.next())
    				output.append(rset.getString(1) + "
    ");
    
    			// We're done
    			output.append("done.
    ");
    			LOGGER.info(output.toString());
    		} catch (Exception e) {
    			e.printStackTrace();
    			// Oops
    			output.append(e.getMessage() + "
    ");
    			LOGGER.info(output.toString());
    		}finally{
    			if(conn!=null)
    			{
    				try {
    					conn.close();
    					conn=null;
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			}
    		}
    		return output.toString();
    	}
    	
    	
    }
    


    上面有一段 个人觉得大家可以研究下 还是很有作用的

    if (conn == null) { 
    				// Create a OracleDataSource instance and set URL
    				//这里为什么不要  DriverManager.registerDriver(new OracleDriver())  这么一句话  哈哈  里面有很多学问啊
    				//简单的说 就是 DriverManager在类加载的时候 在一个静态块中执行了loadInitialDrivers方法 此方法使用
    				//ServiceLoader.load(Driver.class)的方式加载了位于ojdbc6-11.2.0.jar包下的meta-inf/services/java.sql.Driver文件中的oracle.jdbc.OracleDriver的驱动
    				//那为什么加载了oracle.jdbc.OracleDriver的驱动 就不需要注册了呢  原因在于 OracleDriver也有一个静态块里面有一个  DriverManager.registerDriver(m_defaultDriver);
    				//所以无需注册了
    				conn=DriverManager.getConnection(connect_string);
    				// Connect to the databse
    				output.append("Connecting to " + connect_string + "
    ");
    				output.append("Connected
    ");
    			}

    看到上面的代码片段 我没有使用DriverManager.register或者是Class.forName进行驱动的注册  但是却依旧可以连接上oracle数据库  其实看看源码 和我上面的注释 就知道原因了 哈哈

    对于上面的  补充一下

    If you are using JSE 6 and later, then there is no need to explicitly load the JDBC driver. This means that the Java run-time loads the driver when needed and you need not include Class.forName("oracle.jdbc.OracleDriver") or new oracle.jdbc.OracleDriver() in your code. But if you are using J2SE 5.0, then you need to load the JDBC driver explicitly.




    2、oci协议

    oci--不太适合使用在web端 ,因为oracle call interface 通过jni调用本地oracle客户端的c库 从而实现与服务器oracle进行通信 属于第2类驱动

    //常规的写法
    		 /*String url = "jdbc:oracle:oci:@localhost:1521:orcl";*/
    		//如果客户端和服务器在同一台电脑上  使用ipc 进行通信  如下
    		/* String url ="jdbc:oracle:oci:@";*/
    		 //使用oracleAdministratorproduct11.2.0dbhome_1NETWORKADMIN	nsnames.ora 中的连接项进行连接  
    		 String url ="jdbc:oracle:oci8:@ORCL";
    看到上面  oci协议有3中写法 分别对应与不同的情况 

    第一种   常用方法  jdbc:oracle:oci:@localhost:1521:orcl

    第二种 仅适用于 oracle客户端和oracle服务器在同一台电脑上 使用内部进程间进行通信

    第三种 使用tns的配置连接

    package com.undergrowth.jdbc.oci;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Properties;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import oracle.jdbc.oci.OracleOCIConnection;
    import oracle.jdbc.pool.OracleOCIConnectionPool;
    
    /**
     * 测试oracle的oci协议
     * 来源oracle的ojdbc例子
     * @author Administrator
     *
     */
    public class OciTest {
    	
    	final static Logger LOGGER=LoggerFactory.getLogger(OciTest.class);
    	
    	public boolean testOci(){
    		boolean b=true;
    		OracleOCIConnectionPool cpool=null;
    		OracleOCIConnection conn1=null,conn2=null;
    		ResultSet rset  =null;
    		Statement stmt =null;
    		//常规的写法
    		 /*String url = "jdbc:oracle:oci:@localhost:1521:orcl";*/
    		//如果客户端和服务器在同一台电脑上  使用ipc 进行通信  如下
    		/* String url ="jdbc:oracle:oci:@";*/
    		 //使用oracleAdministratorproduct11.2.0dbhome_1NETWORKADMIN	nsnames.ora 中的连接项进行连接  
    		 String url ="jdbc:oracle:oci8:@ORCL";
    		    try {
    		      String url1 = System.getProperty("JDBC_URL");
    		      if (url1 != null)
    		        url = url1;
    		      
    		      // Create an OracleOCIConnectionPool instance with
    			    // default configuration
    			     cpool = new OracleOCIConnectionPool
    			                                         ("u1", "u1", url, null);
    
    			    // Print out the default configuration for the
    			    // OracleOCIConnectionPool
    			    LOGGER.info
    			           ("-- The default configuration for the OracleOCIConnectionPool --");
    			    displayPoolConfig(cpool);
    
    			    // Get a connection from the pool
    			     conn1 = (OracleOCIConnection)
    			                                  cpool.getConnection("u1", "u1");
    
    			    // Create a Statement
    			     stmt = conn1.createStatement ();
    
    			    // Select the ID, NAME, birthday, age column from the student table
    			     rset = stmt.executeQuery ("SELECT ID, NAME, birthday, age FROM student st WHERE st.id<10");
    
    			    // Iterate through the result and print the  student table
    			    LOGGER.info
    			           ("-- Use the connection from the OracleOCIConnectionPool --");
    			    while (rset.next ())
    			      LOGGER.info (rset.getString (1) + " " + rset.getString (2));
    
    			    LOGGER.info
    			           ("-- Use another connection from the OracleOCIConnectionPool --");
    
    			    // Get another connection from the pool
    			    // with different userID and password
    			     conn2 = (OracleOCIConnection)
    			                                cpool.getConnection("u2", "u2");
    
    			    // Create a Statement
    			    stmt = conn2.createStatement ();
    
    			    // Select the USER from DUAL to test the connection
    			    rset = stmt.executeQuery ("select to_char(sysdate,'yyyy-mm-dd') from DUAL");
    
    			    // Iterate through the result and print it out 
    			    rset.next ();
    			    LOGGER.info (rset.getString (1));
    
    			    // Reconfigure the OracleOCIConnectionPool in case the performance
    			    // is too bad. This might happen when many users are trying to connect
    			    // at the same time. In this case, increase MAX_LIMIT to some larger
    			    // number, and also increase INCREMENT to a positive number.
    
    			    Properties p  = new Properties();
    			    p.put (OracleOCIConnectionPool.CONNPOOL_MIN_LIMIT,
    			           Integer.toString(cpool.getMinLimit()));
    			    p.put (OracleOCIConnectionPool.CONNPOOL_MAX_LIMIT,
    			           Integer.toString(cpool.getMaxLimit() * 2)) ;
    			    if (cpool.getConnectionIncrement() > 0)
    			        // Keep the old value
    			        p.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT,
    			               Integer.toString(cpool.getConnectionIncrement()));
    			    else
    			        // Set it to a number larger than 0
    			        p.put (OracleOCIConnectionPool.CONNPOOL_INCREMENT, "1") ;
    			    
    			    // Enable the new configuration
    			    cpool.setPoolConfig(p);
    
    			    // Print out the current configuration for the
    			    // OracleOCIConnectionPool
    			    LOGGER.info
    			           ("-- The new configuration for the OracleOCIConnectionPool --");
    			    displayPoolConfig(cpool);
    
    			   
    		      
    		    } catch (Exception e) {
    		      // If there is any security exception, ignore it
    		      // and use the default
    		    	b=false;
    		    }finally{
    		    	 // Close the RseultSet
    			    try {
    					rset.close();
    					rset = null;
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			    
    
    			    // Close the Statement
    			    try {
    					stmt.close();
    					 stmt = null;
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			   
    
    			    // Close the connections
    			    try {
    					conn1.close();
    					 conn1 = null;
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			    try {
    					conn2.close();
    					conn2 = null;
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			   
    			    // Close the OracleOCIConnectionPool
    			    try {
    					cpool.close();
    					 cpool = null;
    				} catch (SQLException e) {
    					// TODO Auto-generated catch block
    					e.printStackTrace();
    				}
    			   
    		    }
    
    		  
    		    
    		    return b;
    		  }
    	
    		// Display the current status of the OracleOCIConnectionPool
    		private  void displayPoolConfig (OracleOCIConnectionPool cpool)
    		    throws SQLException
    		{
    		  LOGGER.info (" Min poolsize Limit: " + cpool.getMinLimit());
    		  LOGGER.info (" Max poolsize Limit: " + cpool.getMaxLimit());
    		  LOGGER.info (" Connection Increment: " +
    		                        cpool.getConnectionIncrement());
    		  LOGGER.info (" NoWait: " + cpool.getNoWait());
    		  LOGGER.info (" Timeout: " + cpool.getTimeout());
    		  LOGGER.info (" PoolSize: " + cpool.getPoolSize());
    		  LOGGER.info (" ActiveSize: " + cpool.getActiveSize());
    		}
    
    	
    }
    


    3、kprb协议

    kprb(server-side internal driver)--为oracle服务器端内部的驱动 用于嵌入在服务器oracle中的java程序/jsp代码与oracle进行通信 连接使用当前会话用户名与密码 这个连接也不用关闭 使用的是kprb的c库进行通信

    package com.undergrowth.jdbc.kprb;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * 测试oracle的kprb协议
     * 来源oracle的安装文件 oracleAdministratorproduct11.2.0dbhome_1javavmdemoexamplesjsprocasicasic_kprb
     * @author Administrator
     * 测试表
     * 
     * create table employee (enum int, ename varchar2(20), 
       position varchar2(20), salary int);
    
    insert into employee values (100, 'John Doe', 'Secretary', 40000);
    insert into employee values (101, 'Jane Johnson', 'Engineer', 60000);
    
      
       
    
     */
    
    public class KprbTest {
    	 
    	
    	//final static Logger LOGGER=LoggerFactory.getLogger(KprbTest.class);
    	
    	/*
    	   * update the position and salary of an employee with the
    	   * given employee number
    	   *
    	   * Here, emp_num and raise are IN parameters; position is an IN/OUT 
    	   * parameter; salary is an OUT parameter.
    	   *
    	   */
    	  public static void updatePositionSalary(int emp_num, String[] position, 
    	                           int[] salary, int raise)   
    	  {
    	    String pos = null;
    	    int sal = 0;
    	    Connection conn = null;
    	    Statement stmt = null;
    	    PreparedStatement pstmt = null;
    
    	    try
    	    {
    	      // create connection and statement
    	      DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver ());
    	      conn = DriverManager.getConnection("jdbc:oracle:kprb:");
    	      stmt = conn.createStatement();
    
    	      pstmt = conn.prepareStatement("UPDATE EMPLOYEE SET POSITION = ?, " +
    	              " SALARY = SALARY + ? WHERE ENUM = ?");
    
    	      // set up bind values and execute the update
    	      pstmt.setString(1, position[0]);
    	      pstmt.setInt(2, raise);
    	      pstmt.setInt(3, emp_num);
    	      pstmt.execute();
    
    	      // retrieve the updated position and salary to verify that
    	      // the data has been updated in the database
    	      ResultSet rset = stmt.executeQuery(
    	         "SELECT POSITION, SALARY FROM EMPLOYEE WHERE ENUM = " + emp_num);
    
    	      while (rset.next()) 
    	      {
    	        pos = rset.getString ("position");
    	        sal = rset.getInt ("salary");
    	      }
    	    }catch(SQLException sqlException){
    	    	//LOGGER.error(sqlException.getMessage());
    	    	System.out.println(sqlException.getMessage());
    	    }finally
    	    {
    	      try {
    			if(stmt!=null) stmt.close();
    		} catch (SQLException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    	      position[0] = pos; 
    	      salary[0] = sal; 
    	      //LOGGER.info("ENUM:"+emp_num+"	 position:"+pos+"	salary:"+sal);
    	      System.out.println("ENUM:"+emp_num+"	 position:"+pos+"	salary:"+sal);
    	    }
    	  }
    }
    

    基于kprb的测试方式 有点特殊 由于其用途所决定的

    如下‘

    /*
    		 * kprb的测试方法 有点特殊 由于其用途所决定
    		 * 1、编写好KprbTest.java  编译成KprbTest.class文件
    		 * 2、将编译好的KprbTest.class加载到oracle服务器中  作为oracle的模式对象之一    
    		 *    loadjava -r -f -o -user u1/u1@orcl KprbTest.class
    		 *    查看是否加载成功 SELECT uo.* from User_Objects uo WHERE uo.OBJECT_NAME LIKE '%KprbTest%';
    		 * 3、使用存储过程或者函数进行包装你的   KprbTest.class
    		 *   create or replace procedure annualReview (enum IN number, 
    				positon IN OUT varchar2, sal OUT number, raise IN number) as
    	          	language java name 'com.undergrowth.jdbc.kprb.KprbTest.
    	          	updatePositionSalary(int, java.lang.String[], int[], int)';
    				/
    		   4、test annualReview存储过程 即可看到结果
    		    begin
    			  -- Call the procedure
    			  annualreview(enum => :enum,
    			               positon => :positon,
    			               sal => :sal,
    			               raise => :raise);
    				end;
    		 */



    4、附测试类

    package com.undergrowth;
    
    import java.sql.SQLException;
    import java.util.ServiceLoader;
    
    import com.undergrowth.jdbc.kprb.KprbTest;
    import com.undergrowth.jdbc.message.IMessage;
    import com.undergrowth.jdbc.oci.OciTest;
    import com.undergrowth.jdbc.thin.ThinTest;
    
    import junit.framework.TestCase;
    /**
     * 测试oracle 的三种连接方式 
     * 三种连接方式在使用上 没有太多的不一样 只是每个方式的使用定位  实现方式不一样
     * thin--多使用在web开发 通过tcp/ip的socket与服务器oracle的tcp/ip的socket监听器进行连接  进而与oracle服务器进行通信 属于第4类驱动 独立于平台的
     * oci--不太适合使用在web端 ,因为oracle call interface 通过jni调用本地oracle客户端的c库 从而实现与服务器oracle进行通信 属于第2类驱动
     * kprb(server-side internal driver)--为oracle服务器端内部的驱动 用于嵌入在服务器oracle中的java程序/jsp代码与oracle进行通信 连接使用当前会话用户名与密码 这个连接也不用关闭 使用的是kprb的c库进行通信
     * 还有一种 server-side thin  ----用于oracle服务器端内部需要访问远程服务器时使用或者是同一个数据库不同的session访问 例如调用中间件 与client thin没有太多的区别
     * @author Administrator
     *
     */
    public class OracleJdbcTest extends TestCase {
    
    	public void testTestThin() {
    		ThinTest tt=new ThinTest();
    		String actual=tt.testThin();
    		assertNotSame("", actual);
    		
    		 actual=tt.testThinDriverManager();
    		 assertNotSame("", actual);
    	}
    	
    	public void testTestOci() {
    		OciTest tt=new OciTest();
    		Boolean condition=tt.testOci();
    		assertTrue(condition);
    	}
    	
    	public void testKprbTest() {
    		/*
    		 * kprb的测试方法 有点特殊 由于其用途所决定
    		 * 1、编写好KprbTest.java  编译成KprbTest.class文件
    		 * 2、将编译好的KprbTest.class加载到oracle服务器中  作为oracle的模式对象之一    
    		 *    loadjava -r -f -o -user u1/u1@orcl KprbTest.class
    		 *    查看是否加载成功 SELECT uo.* from User_Objects uo WHERE uo.OBJECT_NAME LIKE '%KprbTest%';
    		 * 3、使用存储过程或者函数进行包装你的   KprbTest.class
    		 *   create or replace procedure annualReview (enum IN number, 
    				positon IN OUT varchar2, sal OUT number, raise IN number) as
    	          	language java name 'com.undergrowth.jdbc.kprb.KprbTest.
    	          	updatePositionSalary(int, java.lang.String[], int[], int)';
    				/
    		   4、test annualReview存储过程 即可看到结果
    		    begin
    			  -- Call the procedure
    			  annualreview(enum => :enum,
    			               positon => :positon,
    			               sal => :sal,
    			               raise => :raise);
    				end;
    		 */
    		/*KprbTest tt=new KprbTest();
    		int[] salary=new int[1];
    		String[] position=new String[1];
    		tt.updatePositionSalary(100, position, salary, 60000);
    		assertNotSame("", position[0]);*/
    	}
    	
    	/**
    	 * 测试服务加载者用于加载位于meta-inf/services/下服务提供者
    	 */
    	public void testServiceLoader(){
    		
    		ServiceLoader<IMessage> messageLoader=ServiceLoader.load(IMessage.class);
    		for (IMessage iMessage : messageLoader) {
    			System.out.println(iMessage.getBuffer().toString());
    		}
    	}
    
    }
    

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    	<modelVersion>4.0.0</modelVersion>
    
    	<groupId>com.undergrowth</groupId>
    	<artifactId>jdbc</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    	<packaging>jar</packaging>
    
    	<name>jdbc</name>
    	<url>http://maven.apache.org</url>
    
    	<properties>
    		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    	</properties>
    
    	<dependencies>
    		<dependency>
    			<groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>3.8.1</version>
    			<scope>test</scope>
    		</dependency>
    		<!-- 添加oracle jdbc的依赖 -->
    		<dependency>
    			<groupId>com.oracle</groupId>
    			<artifactId>ojdbc6</artifactId>
    			<version>11.2.0</version>
    		</dependency>
    		
    		<dependency>  
                <groupId>org.slf4j</groupId>  
                <artifactId>slf4j-log4j12</artifactId>  
                <version>1.7.7</version>  
            </dependency>  
    		
    		
    	</dependencies>
    </project>
    


    哦 对了 对于oracle的maven依赖 我们需要自己安装到版本仓库中  

    参考如下

    mvn install:install-file -Dfile={Path/to/your/ojdbc.jar} -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0 -Dpackaging=jar
    详细参考 http://www.cnblogs.com/leiOOlei/archive/2013/10/21/3380568.html


    5、最后来看看 注册驱动类DriverManager 是如何与oracle的OriaclDriver挂上关系的

    恩 这里为了不是事情更复杂化 选择常用方法  DriverManager.registerDriver方法入手

     DriverManager.registerDriver(new OracleDriver());

    看看registerDriver方法

     /**
         * Registers the given driver with the <code>DriverManager</code>.
         * A newly-loaded driver class should call
         * the method <code>registerDriver</code> to make itself
         * known to the <code>DriverManager</code>.
         *
         * @param driver the new JDBC Driver that is to be registered with the
         *               <code>DriverManager</code>
         * @exception SQLException if a database access error occurs
         */
        public static synchronized void registerDriver(java.sql.Driver driver)
            throws SQLException {
    
            /* Register the driver if it has not already been added to our list */
            if(driver != null) {
                registeredDrivers.addIfAbsent(new DriverInfo(driver));
            } else {
                // This is for compatibility with the original DriverManager
                throw new NullPointerException();
            }
    
            println("registerDriver: " + driver);
    
        }


    synchronized字节码进行同步锁  查看addIfAbsent
    添加一个不存在的元素到列表中
     /**
         * Append the element if not present.
         *
         * @param e element to be added to this list, if absent
         * @return <tt>true</tt> if the element was added
         */
        public boolean addIfAbsent(E e) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                // Copy while checking if already present.
                // This wins in the most common case where it is not present
                Object[] elements = getArray();
                int len = elements.length;
                Object[] newElements = new Object[len + 1];
                for (int i = 0; i < len; ++i) {
                    if (eq(e, elements[i]))
                        return false; // exit, throwing away copy
                    else
                        newElements[i] = elements[i];
                }
                newElements[len] = e;
                setArray(newElements);
                return true;
            } finally {
                lock.unlock();
            }
        }
    使用 ReentrantLock保证了同步  

    重点是元素是否相等    if (eq(e, elements[i]))

      /**
         * Test for equality, coping with nulls.
         */
        private static boolean eq(Object o1, Object o2) {
            return (o1 == null ? o2 == null : o1.equals(o2));
        }

    当注册驱动时 o1==null 为false  执行  o1.equals(o2)

    /**
         * Compares the specified object with this list for equality.
         * Returns {@code true} if the specified object is the same object
         * as this object, or if it is also a {@link List} and the sequence
         * of elements returned by an {@linkplain List#iterator() iterator}
         * over the specified list is the same as the sequence returned by
         * an iterator over this list.  The two sequences are considered to
         * be the same if they have the same length and corresponding
         * elements at the same position in the sequence are <em>equal</em>.
         * Two elements {@code e1} and {@code e2} are considered
         * <em>equal</em> if {@code (e1==null ? e2==null : e1.equals(e2))}.
         *
         * @param o the object to be compared for equality with this list
         * @return {@code true} if the specified object is equal to this list
         */
        public boolean equals(Object o) {
            if (o == this)
                return true;
            if (!(o instanceof List))
                return false;
    
            List<?> list = (List<?>)(o);
            Iterator<?> it = list.iterator();
            Object[] elements = getArray();
            int len = elements.length;
            for (int i = 0; i < len; ++i)
                if (!it.hasNext() || !eq(elements[i], it.next()))
                    return false;
            if (it.hasNext())
                return false;
            return true;
        }


    当向

     // List of registered JDBC drivers
        private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<DriverInfo>();

    添加了驱动后  即 DriverManager.registerDriver(new OracleDriver());  执行完了  

    接着第二步是 

    conn=DriverManager.getConnection(connect_string);

      /**
         * Attempts to establish a connection to the given database URL.
         * The <code>DriverManager</code> attempts to select an appropriate driver from
         * the set of registered JDBC drivers.
         *
         * @param url a database url of the form
         *  <code> jdbc:<em>subprotocol</em>:<em>subname</em></code>
         * @return a connection to the URL
         * @exception SQLException if a database access error occurs
         */
        public static Connection getConnection(String url)
            throws SQLException {
    
            java.util.Properties info = new java.util.Properties();
    
            // Gets the classloader of the code that called this method, may
            // be null.
            ClassLoader callerCL = DriverManager.getCallerClassLoader();
    
            return (getConnection(url, info, callerCL));
        }



    接着看 getConnection方法

    //  Worker method called by the public getConnection() methods.
        private static Connection getConnection(
            String url, java.util.Properties info, ClassLoader callerCL) 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.
             */
            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.
                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");
        }
    



    重点来了

    Connection con = aDriver.driver.connect(url, info);

    这里的  aDriver.driver  就是我们上面注册的 OracleDriver了  那看看OracleDriver的connect是什么吧

     public Connection connect(String s, Properties properties)
            throws SQLException
        {
            if(s.regionMatches(0, "jdbc:default:connection", 0, 23))
            {
                String s1 = "jdbc:oracle:kprb";
                int j = s.length();
                if(j > 23)
                    s = s1.concat(s.substring(23, s.length()));
                else
                    s = s1.concat(":");
                s1 = null;
            }
            int i = oracleAcceptsURL(s);
            if(i == 1)
                return null;
            if(i == 2)
            {
                DBError.throwSqlException(67);
                return null;
            }
            Hashtable hashtable = parseUrl(s);
            if(hashtable == null)
                return null;
            String s2 = properties.getProperty("user");
            String s3 = properties.getProperty("password");
            String s4 = properties.getProperty("database");
            if(s4 == null)
                s4 = properties.getProperty("server");
            if(s2 == null)
                s2 = (String)hashtable.get("user");
            s2 = parseLoginOption(s2, properties);
            if(s3 == null)
                s3 = (String)hashtable.get("password");
            if(s4 == null)
                s4 = (String)hashtable.get("database");
            String s5 = (String)hashtable.get("protocol");
            properties.put("protocol", s5);
            if(s5 == null)
            {
                DBError.throwSqlException(40, "Protocol is not specified in URL");
                return null;
            }
            String s6 = properties.getProperty("dll");
            if(s6 == null)
                properties.put("dll", "ocijdbc9");
            String s7 = properties.getProperty("prefetch");
            if(s7 == null)
                s7 = properties.getProperty("rowPrefetch");
            if(s7 == null)
                s7 = properties.getProperty("defaultRowPrefetch");
            if(s7 != null && Integer.parseInt(s7) <= 0)
                s7 = null;
            String s8 = properties.getProperty("batch");
            if(s8 == null)
                s8 = properties.getProperty("executeBatch");
            if(s8 == null)
                s8 = properties.getProperty("defaultExecuteBatch");
            if(s8 != null && Integer.parseInt(s8) <= 0)
                s8 = null;
            String s9 = properties.getProperty("remarks");
            if(s9 == null)
                s9 = properties.getProperty("remarksReporting");
            String s10 = properties.getProperty("synonyms");
            if(s10 == null)
                s10 = properties.getProperty("includeSynonyms");
            String s11 = properties.getProperty("restrictGetTables");
            String s12 = properties.getProperty("fixedString");
            String s13 = properties.getProperty("dataSizeUnits");
            String s14 = properties.getProperty("AccumulateBatchResult");
            if(s14 == null)
                s14 = "true";
            Enumeration enumeration;
            for(enumeration = DriverManager.getDrivers(); enumeration.hasMoreElements();)
            {
                Driver driver = (Driver)enumeration.nextElement();
                if(driver instanceof OracleDriver)
                    break;
            }
    
            while(enumeration.hasMoreElements()) 
            {
                Driver driver1 = (Driver)enumeration.nextElement();
                if(driver1 instanceof OracleDriver)
                    DriverManager.deregisterDriver(driver1);
            }
            Connection connection = getConnectionInstance(s5, s, s2, s3, s4, properties);
            if(s7 != null)
                ((oracle.jdbc.driver.OracleConnection)connection).setDefaultRowPrefetch(Integer.parseInt(s7));
            if(s8 != null)
                ((oracle.jdbc.driver.OracleConnection)connection).setDefaultExecuteBatch(Integer.parseInt(s8));
            if(s9 != null)
                ((oracle.jdbc.driver.OracleConnection)connection).setRemarksReporting(s9.equalsIgnoreCase("true"));
            if(s10 != null)
                ((oracle.jdbc.driver.OracleConnection)connection).setIncludeSynonyms(s10.equalsIgnoreCase("true"));
            if(s11 != null)
                ((oracle.jdbc.driver.OracleConnection)connection).setRestrictGetTables(s11.equalsIgnoreCase("true"));
            if(s12 != null)
                ((oracle.jdbc.driver.OracleConnection)connection).setDefaultFixedString(s12.equalsIgnoreCase("true"));
            if(s13 != null)
                ((oracle.jdbc.driver.OracleConnection)connection).setDataSizeUnits(s13);
            ((oracle.jdbc.driver.OracleConnection)connection).setAccumulateBatchResult(s14.equalsIgnoreCase("true"));
            hashtable = null;
            return connection;
        }



    看到 好多 啊  其实 显示解析URL和解析默认属性  中间才是连接 后面又是解析URL和设置默认属性

    主要的是 这个方法

    注意哦 这个地方s5  如果我们用的是thin的协议的话 s5=thin 了  这个很有用啊  直接关系到下面找不找的具体的socket代码

    Connection connection = getConnectionInstance(s5, s, s2, s3, s4, properties);


    看到下面的连接方法

     private Connection getConnectionInstance(String s, String s1, String s2, String s3, String s4, Properties properties)
            throws SQLException
        {
            Object obj = null;
            if(s.compareTo("ultra") == 0)
            {
                try
                {
                    Class aclass[] = null;
                    Object aobj[] = new Object[6];
                    aobj[0] = s;
                    aobj[1] = s1;
                    aobj[2] = s2;
                    aobj[3] = s3;
                    aobj[4] = s4;
                    aobj[5] = properties;
                    Class class1 = Class.forName("oracle.jdbc.ultra.client.Driver");
                    Method amethod[] = class1.getMethods();
                    for(int i = 0; i < amethod.length; i++)
                    {
                        if(!amethod[i].getName().equals("getConnection"))
                            continue;
                        aclass = amethod[i].getParameterTypes();
                        break;
                    }
    
                    Method method = class1.getMethod("getConnection", aclass);
                    obj = (Connection)method.invoke(class1.newInstance(), aobj);
                }
                catch(Exception exception)
                {
                    exception.printStackTrace();
                    DBError.throwSqlException(1);
                }
            } else
            {
                String s5 = null;
                if(s.equals("thin") && System.getProperty("oracle.jserver.version") != null)
                    s5 = "thin-server";
                else
                if((s.equals("oci8") || s.equals("oci")) && System.getProperty("oracle.jserver.version") != null)
                    s5 = "oci-server";
                else
                    s5 = s;
                String s6 = (String)m_driverAccess.get(s5);
                if(s6 == null)
                    DBError.throwSqlException(67, "Invalid protocol " + s);
                DBAccess dbaccess = null;
                try
                {
                    dbaccess = (DBAccess)Class.forName(s6).newInstance();
                }
                catch(Exception _ex)
                {
                    return null;
                }
                if(properties.getProperty("is_connection_pooling") == "true")
                {
                    properties.put("database", s4 != null ? ((Object) (s4)) : "");
                    obj = new OracleOCIConnection(dbaccess, s1, s2, s3, s4, properties);
                } else
                {
                    obj = new oracle.jdbc.driver.OracleConnection(dbaccess, s1, s2, s3, s4, properties);
                }
            }
            return ((Connection) (obj));
        }

    有两句话比较关键

    String s5 = null;
                if(s.equals("thin") && System.getProperty("oracle.jserver.version") != null)
                    s5 = "thin-server";
                else
                if((s.equals("oci8") || s.equals("oci")) && System.getProperty("oracle.jserver.version") != null)
                    s5 = "oci-server";
                else
                    s5 = s;
                String s6 = (String)m_driverAccess.get(s5);
    哈哈  看到上面说了  如果使用的是 client-thin的话  那么s5=s=thin

    那么s6的值是什么呢

     m_driverAccess = new Properties();
            m_driverAccess.put("thin-server", "oracle.jdbc.thinserver.ServerTTC7Protocol");
            m_driverAccess.put("oci-server", "oracle.jdbc.ociserver.ServerOCIDBAccess");
            m_driverAccess.put("thin", "oracle.jdbc.ttc7.TTC7Protocol");
            m_driverAccess.put("oci8", "oracle.jdbc.oci8.OCIDBAccess");
            m_driverAccess.put("oci", "oracle.jdbc.oci8.OCIDBAccess");
            m_driverAccess.put("kprb", "oracle.jdbc.kprb.KprbDBAccess");
            m_defaultDriver = null;
    这个实在OracleDriver的静态代码块中的  

    所以s6=  oracle.jdbc.ttc7.TTC7Protocol    就是你了 

    我看了看  当使用的是thin写的时候  

    执行 最后一步  

    obj = new oracle.jdbc.driver.OracleConnection(dbaccess, s1, s2, s3, s4, properties);

    所以此时 传递的dbaccess及为 TTC7Protocal的实例了   

    dbaccess = (DBAccess)Class.forName(s6).newInstance();

    好的 知道了 这里 DBAccess实际上是指向TTC7Protocal的实例  就可以了 

    接着走

    oracle.jdbc.driver.OracleDriver的构造函数

     public OracleConnection(DBAccess dbaccess, String s, String s1, String s2, String s3, Properties properties)
            throws SQLException
        {
            m_txn_mode = 0;
            m_clientIdSet = false;
            m_clientId = null;
            include_synonyms = false;
            restrict_getTables = false;
            m_accumulateBatchResult = true;
            dataSizeScale = 1;
            m_dbMetaData = null;
            m_opc = null;
            m_opc_oc = null;
            m_osql = null;
            m_warning = null;
            m_readOnly = false;
            m_startTime = 0L;
            statementCache = null;
            m_stmtClearMetaData = false;
            m_process_escapes = true;
            m_defaultAutoRefetch = true;
            m_occ = null;
            m_privData = null;
            defaultFixedString = false;
            m_svptStmt = null;
            wrapper = null;
            connectionProperties = null;
            m_sessionTimeZone = null;
            m_dbTzCalendar = null;
            String s4 = null;
            Object obj = null;
            boolean flag = true;
            if(properties != null)
            {
                s4 = (String)properties.get("protocol");
                String s6 = properties.getProperty("processEscapes");
                if(s6 != null && s6.equalsIgnoreCase("false"))
                    m_process_escapes = false;
                connectionProperties = (Properties)properties.clone();
                connectionProperties.remove("password");
            }
            initialize(s, s1, s4, dbaccess, null, null, null, s3);
            logicalHandle = false;
            try
            {
                needLine();
                conversion = db_access.logon(s1, s2, s3, properties);
                m_warning = DBError.addSqlWarning(m_warning, db_access.getWarnings());
                if(properties == null || properties.getProperty("connection_pool") != "connection_pool")
                {
                    default_row_prefetch = db_access.getDefaultPrefetch();
                    if(properties != null)
                    {
                        String s5 = properties.getProperty("autoCommit");
                        if(s5 != null && s5.equalsIgnoreCase("false"))
                            flag = false;
                    }
                    setAutoCommit(flag);
                    db_access.initNls(this);
                }
            }
            catch(IOException ioexception)
            {
                DBError.throwSqlException(ioexception);
            }
            catch(SQLException sqlexception)
            {
                try
                {
                    db_access.logoff();
                }
                catch(IOException _ex) { }
                catch(SQLException _ex) { }
                throw sqlexception;
            }
            m_txn_mode = 0;
        }

    其实只有一句最关键

    conversion = db_access.logon(s1, s2, s3, properties);

    这里就是用的TTC7Protocal的实例啊    的logon方法

    接着

     public synchronized DBConversion logon(String s, String s1, String s2, Properties properties)
            throws SQLException, IOException
        {
            try
            {
                if(state > 0)
                    DBError.check_error(428);
                if(s == null || s1 == null)
                    DBError.check_error(433);
                if(s.length() == 0 || s1.length() == 0)
                    DBError.check_error(443);
                if(s2 == null)
                    s2 = "localhost:1521:orcl";
                connect(s2, properties);
                all7 = new Oall7(MEngine);
                commoncall = new Ocommoncall(MEngine);
                opencall = new Oopen(MEngine);
                close = new Oclose(MEngine);
                TTCTypeRep _tmp = MEngine.types;
                describe = (Odscrarr)MEngine.types.newTTIFunObject((byte)1, MEngine);
                bfileMsg = new v8TTIBfile(MEngine);
                blobMsg = new v8TTIBlob(MEngine);
                clobMsg = new v8TTIClob(MEngine);
                TTCTypeRep _tmp1 = MEngine.types;
                dty = (TTIdty)MEngine.types.newTTCMsgObject((byte)2, MEngine);
                dty.marshal();
                dty.receive();
                String s3 = (String)properties.get("internal_logon");
                if(s3 != null)
                    if(s3.equalsIgnoreCase("sysoper"))
                        LOGON_MODE = 16L;
                    else
                    if(s3.equalsIgnoreCase("sysdba"))
                        LOGON_MODE = 8L;
                log1 = new O3log(MEngine, s, properties, LOGON_MODE);
                log1.marshal();
                log1.receive1st();
                log2 = new O3log(MEngine, s, s1, log1.encryptedSK, properties, LOGON_MODE);
                log2.marshal();
                do
                    try
                    {
                        log2.receive2nd();
                        break;
                    }
                    catch(SQLWarning sqlwarning)
                    {
                        setWarnings(DBError.addSqlWarning(getWarnings(), sqlwarning));
                    }
                while(true);
                net.setO3logSessionKey(log2.getSessionKey());
                ver = new Oversion(MEngine);
                ver.marshal();
                ver.receive();
                short word0 = ver.getVersionNumber();
                if(word0 < 7230)
                    DBError.check_error(441);
                MEngine.types.setVersion(word0);
                state = 1;
                return MEngine.conv;
            }
            catch(SQLException sqlexception)
            {
                try
                {
                    net.disconnect();
                }
                catch(Exception exception) { }
                state = 0;
                throw sqlexception;
            }
        }

    看到有一句

     connect(s2, properties);

    private void connect(String s, Properties properties)
            throws IOException, SQLException
        {
            if(s == null || properties == null)
                DBError.check_error(433);
            net = new NSProtocol();
            try
            {
                net.connect(s, properties);
            }
            catch(NetException netexception)
            {
                throw new IOException(netexception.getMessage());
            }
            MEngine = new MAREngine(net);
            pro = new v8TTIpro(MEngine);
            pro.marshal();
            pro.receive();
            short word0 = pro.getOracleVersion();
            short word1 = pro.getCharacterSet();
            short word2 = TTCConversion.findAccessCharSet(word1, word0);
            TTCConversion ttcconversion = new TTCConversion(word1, word2, word0, pro.getncharCHARSET());
            MEngine.types.setServerConversion(word2 != word1);
            MEngine.types.setVersion(word0);
            if(DBConversion.isCharSetMultibyte(word2))
            {
                if(DBConversion.isCharSetMultibyte(pro.getCharacterSet()))
                    MEngine.types.setFlags((byte)1);
                else
                    MEngine.types.setFlags((byte)2);
            } else
            {
                MEngine.types.setFlags(pro.getFlags());
            }
            MEngine.conv = ttcconversion;
        }

    进行连接的部分

     net = new NSProtocol();
            try
            {
                net.connect(s, properties);
            }

    嘎嘎 接着找

    NSProtocal的connect

     public void connect(String s, Properties properties)
            throws IOException, NetException
        {
            if(sAtts.connected)
                throw new NetException(201);
            if(s == null)
                throw new NetException(208);
            addrRes = new AddrResolution(s, properties);
            if(addrRes.connection_revised)
            {
                s = addrRes.getTNSAddress();
                properties = addrRes.getUp();
            }
            if(addrRes.jndi)
                sAtts.profile = new ClientProfile(properties, addrRes.getJndi());
            else
                sAtts.profile = new ClientProfile(properties);
            establishConnection(s);
            Object obj4 = null;
            try
            {
                obj4 = Class.forName("oracle.net.ano.Ano").newInstance();
                sAtts.anoEnabled = true;
            }
            catch(Exception _ex)
            {
                sAtts.anoEnabled = false;
            }
            if(obj4 != null)
            {
                ((Ano)obj4).init(sAtts);
                sAtts.ano = (Ano)obj4;
                sAtts.anoEnabled = true;
            }
    label0:
            do
            {
                ConnectPacket connectpacket = new ConnectPacket(sAtts);
                connectpacket.send();
                packet = new Packet(sAtts);
                packet.receive();
                switch(packet.type)
                {
                case 2: // '02'
                    AcceptPacket acceptpacket = new AcceptPacket(packet);
                    break label0;
    
                case 11: // '13'
                    break;
    
                case 5: // '05'
                    RedirectPacket redirectpacket = new RedirectPacket(packet);
                    sAtts.cOption.nt.disconnect();
                    sAtts = establishConnection(redirectpacket.getData());
                    break;
    
                case 4: // '04'
                    RefusePacket refusepacket = new RefusePacket(packet);
                    throw new NetException(206, refusepacket.getData());
    
                case 3: // '03'
                case 6: // '06'
                case 7: // '07'
                case 8: // ''
                case 9: // '	'
                case 10: // '
    '
                default:
                    sAtts.cOption.nt.disconnect();
                    throw new NetException(205);
                }
            } while(true);
            setNetStreams();
            sAtts.connected = true;
            if(sAtts.ano != null)
                sAtts.ano.negotiation();
            packet = null;
            Object obj = null;
            Object obj1 = null;
            Object obj3 = null;
            Object obj2 = null;
        }
    


    关键的语句

    establishConnection(s);

     private SessionAtts establishConnection(String s)
            throws NetException, IOException
        {
            sAtts.cOption = addrRes.resolveAndExecute(s);
            sAtts.ntInputStream = sAtts.cOption.nt.getInputStream();
            sAtts.ntOutputStream = sAtts.cOption.nt.getOutputStream();
            sAtts.setTDU(sAtts.cOption.tdu);
            sAtts.setSDU(sAtts.cOption.sdu);
            sAtts.nsOutputStream = new NetOutputStream(sAtts, 255);
            sAtts.nsInputStream = new NetInputStream(sAtts);
            return sAtts;
        }
    哈哈  看到这 可能就迷糊了 啊   接下去怎么看呢  嘎嘎  关键在第一句  
    sAtts.cOption = addrRes.resolveAndExecute(s);
     public ConnOption resolveAndExecute(String s)
            throws NetException, IOException
        {
            cs = new ConnStrategy();
            if(s.indexOf("//") != -1)
                resolveUrl(s);
            else
            if(s.indexOf(':') != -1 && s.indexOf(')') == -1)
                resolveSimple(s);
            else
            if(newSyntax)
                resolveAddrTree(s);
            else
                resolveAddr(s);
            if(!cs.optAvailable())
                return cs.execute();
            else
                return cs.getOption();
        }

    返回一个ConnOptions  是干什么的呢  看看就知道了

    // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://www.kpdus.com/jad.html
    // Decompiler options: packimports(3) 
    
    package oracle.net.nt;
    
    import java.io.IOException;
    import oracle.net.nl.NLException;
    import oracle.net.ns.NetException;
    
    // Referenced classes of package oracle.net.nt:
    //            NTAdapter, TcpNTAdapter
    
    public class ConnOption
    {
    
        public ConnOption()
        {
            conn_data = new StringBuffer();
        }
    
        public void connect()
            throws IOException
        {
            nt = getNT();
            nt.connect();
        }
    
        private NTAdapter getNT()
            throws NetException
        {
            try
            {
                nt = new TcpNTAdapter(addr);
            }
            catch(NLException _ex)
            {
                throw new NetException(501);
            }
            return nt;
        }
    
        public NTAdapter nt;
        public int port;
        public int tdu;
        public int sdu;
        public String protocol;
        public String host;
        public String sid;
        public String addr;
        public String service_name;
        public String instance_name;
        public StringBuffer conn_data;
        public boolean done;
    }
    


    看到了吧 ConnOptions封装了一个TcpNTAdapter 嘎嘎  看看是干什么的

    // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
    // Jad home page: http://www.kpdus.com/jad.html
    // Decompiler options: packimports(3) 
    
    package oracle.net.nt;
    
    import java.io.*;
    import java.net.Socket;
    import oracle.net.nl.*;
    
    // Referenced classes of package oracle.net.nt:
    //            NTAdapter
    
    public class TcpNTAdapter
        implements NTAdapter
    {
    
        public TcpNTAdapter(String s)
            throws NLException
        {
            NVNavigator nvnavigator = new NVNavigator();
            NVPair nvpair = (new NVFactory()).createNVPair(s);
            if(nvpair == null)
                throw new NLException((short)100);
            NVPair nvpair1 = nvnavigator.findNVPair(nvpair, "PROTOCOL");
            NVPair nvpair2 = nvnavigator.findNVPair(nvpair, "HOST");
            NVPair nvpair3 = nvnavigator.findNVPair(nvpair, "PORT");
            if(nvpair1 == null || nvpair2 == null || nvpair3 == null)
                throw new NLException((short)100);
            prot = nvpair1.getAtom();
            host = nvpair2.getAtom();
            port = Integer.parseInt(nvpair3.getAtom());
            if(!prot.equals("TCP") && !prot.equals("tcp"))
                throw new NLException((short)100);
            else
                return;
        }
    
        public void connect()
            throws IOException
        {
            socket = new Socket(host, port);
        }
    
        public void disconnect()
            throws IOException
        {
            socket.close();
            socket = null;
        }
    
        public InputStream getInputStream()
            throws IOException
        {
            return socket.getInputStream();
        }
    
        public OutputStream getOutputStream()
            throws IOException
        {
            return socket.getOutputStream();
        }
    
        static final boolean DEBUG = false;
        int port;
        String host;
        String prot;
        private Socket socket;
    }
    


    嘎嘎  看到了吧 TcpNTAdapter有一个connect 方法 

     public void connect()
            throws IOException
        {
            socket = new Socket(host, port);
        }
    就建立了一个socket进行连接啊

    以上即是 oracle的jdbc的连接过程 没多讲  这个领会多少 就看个人悟性了 噶  



    oracle的jdbc源码 http://download.csdn.net/detail/hao_lee1014/4221569   其实自己下个jad 就可以得到ojdbc6的源码了 


    以上即是oracle的 jdbc的几种方式 记录学习的脚步


  • 相关阅读:
    Windows FFMPEG开发环境配置
    双网卡单IP实现网卡冗余与负载均衡
    Thinking in Java 4th(Java编程思想第四版)文档、源码、习题答案(偶尔回顾)
    IDEA编译时出现 Information:java: javacTask: 源发行版 1.8 需要目标发行版 1.8
    运行java飞行记录器JFR(java flight recorder)
    Java黑科技之源:JVMTI完全解读
    jvisualvm安装visualgc插件
    系统运行缓慢,CPU 100%,以及Full GC次数过多问题的排查思路
    Jenkins 改成中文语言显示
    windows上Jenkins安装及其配置
  • 原文地址:https://www.cnblogs.com/liangxinzhi/p/4275558.html
Copyright © 2020-2023  润新知