jdbc底层驱动加载数据机制之防止内存溢出(2)--oracle

本文探讨了Oracle JDBC驱动的数据加载机制,防止内存溢出的方法。通过分析关键对象如T4CConnection和OraclePreparedStatementWrapper,揭示了Oracle默认采用游标方式分批次读取结果集,每次读取10条数据。同时,详细解释了结果集的内部结构,包括字段访问器(NumberCommonAccessor、DateTimeCommonAccessor、CharCommonAccessor)以及如何通过设置如defaultRowPrefetch参数控制数据加载行为,以优化内存使用。
摘要由CSDN通过智能技术生成

1.关键对象

connection对象---oracle.jdbc.driver.T4CConnection,里面有关于oracle的所有配置参数,设置方式通过与mysql有所不同,需要通过properties对象传入进去

153931_Hpuz_2345835.png

preparedStatement对象--oracle.jdbc.driver.OraclePreparedStatementWrapper

 

2.数据结果集读取方式

oracle默认的结果集的读取方式就是游标方式,一个结果集分批次读取,一次读取十条。这样保证了,即便数据量很大,也不会出现内存溢出。

3.代码解释

oracle是非开源的,不像mysql可以看到源码,但是可以反编译查看。

每个结果集所包含的关键属性:

103345_pNhK_2345835.png

每个结果集Resultset都有一个statement对象,这个statement对象里包含了结果集数据。

statement关键属性:通过查看源码可以看到

accessors:字段访问器,一个字段对应一个accessor,每个字段访问器都包含一个

currentRow:当前行的游标,每次调用rs.next() 这个值就会加+1

validRows:需要校验的行数,这个值等于每一批次取出来的数据行数。当调用rs.next()时候,通过 currentRow与validRows来判断,这个sql的结果集是不是已经全部读取完了。

关键代码

public boolean next()
    throws SQLException
  {
    synchronized (this.connection)
    {
      boolean bool = true;
      
      //计数器
      this.statement.currentRow += 1;
      this.statement.totalRowsVisited += 1;
      
      if ((this.statement.maxRows != 0) && (this.statement.totalRowsVisited > this.statement.maxRows))
      {
        internal_close(false);
        this.statement.currentRow -= 1;
        this.statement.totalRowsVisited -= 1;
        
        return false;
      }
      //验证到最后一行了,再去服务器端获取下一批数据,默认10条
      if (this.statement.currentRow >= this.statement.validRows) {
        bool = close_or_fetch_from_next(false);
      }
      if ((bool) && (localPhysicalConnection.useFetchSizeWithLongColumn)) {
        this.statement.reopenStreams();
      }
      if (!bool)
      {
        this.statement.currentRow -= 1;
        this.statement.totalRowsVisited -= 1;
      }
      
      return bool;
    }
  }

 

关于accessors。一张表有几个字段就会有几个accessor对象。

在accessor对象中 关键属性:

columnName :字段的名称

rowSpaceByte:字节数组,用来保存字段类型是数字,日期的值。注意,这里保存的是一批字段的值。比如保存id字段前10行
105358_cmN6_2345835.png

rowSpaceChar :字符数组保存的是char类型的字段,也是保存一批字段的值,比如
105516_Q0KQ_2345835.png

 

关于rs.getObject()获取字段值的流程。这里以char类型为例,翻编译jdbc驱动

 CharCommonAccessor
 
String getString(int paramInt)
    throws SQLException
  {
    String str = null;
    
    if (this.rowSpaceIndicator == null)
    {
      SQLException localSQLException = DatabaseError.createSqlException(getConnectionDuringExceptionHandling(), 21);
      localSQLException.fillInStackTrace();
      throw localSQLException;
    }
    
    if (this.rowSpaceIndicator[(this.indicatorIndex + paramInt)] != -1)
    {
      int i = this.columnIndex + this.charLength * paramInt;
      int j = this.rowSpaceChar[i] >> '\001';
      
      if (j > this.internalTypeMaxLength) {
        j = this.internalTypeMaxLength;
      }
      str = new String(this.rowSpaceChar, i + 1, j);//读取当前行该字段的值
    }
    
    return str;
  }

常用的字段访问器有三种:

数字类型访问器使用的是:NumberCommonAccessor--获取数字类型的字段,保存的是数字的二进制

日期类型访问器使用的是:DateTimeCommonAccessor--获取日期类型的字段,保存的是日期的二进制数据

字符串类型访问器使用的是:CharCommonAccessor--保存的是字符串的字符

4.oracle参数的设置

所有的属性通过properties设置--比如修改默认的一次加载的行数defaultRowPrefetch。当然也可以通过statement.setFetchSize(xx)设置,效果一样。只是一个是全局的,一个是局部的

Properties props = new Properties();
		props.setProperty("user", username);
		props.setProperty("password", password);
		props.setProperty("defaultRowPrefetch", "11");//修改一次加载的数据条数,默认是10
		//获取连接
		Connection conn= DriverManager.getConnection(url, props);

 

属性大全源码:源码中的解析过程

private void readConnectionProperties(String paramString, Properties paramProperties)
    throws SQLException
  {
    initializeUserDefaults(paramProperties);

    String str1 = null;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("oracle.jdbc.RetainV9LongBindBehavior");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.RetainV9LongBindBehavior", null);
    if (str1 == null) {
      str1 = "false";
    }

    this.retainV9BindBehavior = ((str1 != null) && (str1.equalsIgnoreCase("true")));

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("user");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.user");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.user", null);
    if (str1 == null) {
      str1 = null;
    }

    this.userName = str1;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("database");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.database");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.database", null);
    if (str1 == null) {
      str1 = null;
    }

    this.database = str1;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("autoCommit");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.autoCommit");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.autoCommit", null);
    if (str1 == null) {
      str1 = "true";
    }

    this.autocommit = ((str1 != null) && (str1.equalsIgnoreCase("true")));

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("protocol");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.protocol");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.protocol", null);
    if (str1 == null) {
      str1 = null;
    }

    this.protocol = str1;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("oracle.jdbc.StreamChunkSize");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.StreamChunkSize", null);
    if (str1 == null)
      str1 = "16384";
    try
    {
      this.streamChunkSize = Integer.parseInt(str1);
    }
    catch (NumberFormatException localNumberFormatException1)
    {
      SQLException sqlexception = DatabaseError.createSqlException(getConnectionDuringExceptionHandling(), 190, "Property is 'streamChunkSize'");
      sqlexception.fillInStackTrace();
      throw sqlexception;
    }

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("SetFloatAndDoubleUseBinary");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.SetFloatAndDoubleUseBinary");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.SetFloatAndDoubleUseBinary", null);
    if (str1 == null) {
      str1 = "false";
    }

    this.setFloatAndDoubleUseBinary = ((str1 != null) && (str1.equalsIgnoreCase("true")));

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("oracle.jdbc.ocinativelibrary");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.ocinativelibrary", null);
    if (str1 == null) {
      str1 = null;
    }

    this.ocidll = str1;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("v$session.terminal");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.v$session.terminal");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.v$session.terminal", null);
    if (str1 == null) {
      str1 = "unknown";
    }

    this.thinVsessionTerminal = str1;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("v$session.machine");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.v$session.machine");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.v$session.machine", null);
    if (str1 == null) {
      str1 = null;
    }

    this.thinVsessionMachine = str1;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("v$session.osuser");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.v$session.osuser");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.v$session.osuser", null);
    if (str1 == null) {
      str1 = null;
    }

    this.thinVsessionOsuser = str1;

    str1 = null;
    if (paramProperties != null)
    {
      str1 = paramProperties.getProperty("v$session.program");
      if (str1 == null)
        str1 = paramProperties.getProperty("oracle.jdbc.v$session.program");
    }
    if (str1 == null)
      str1 = getSystemProperty("oracle.jdbc.v$session.program", null);
    if (str1 == null) {
      st
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值