`
wanglei6744
  • 浏览: 25598 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Oracle BLOB 存储 两三事

阅读更多

最近遇到好多需要存储Oracle BLOB 需求。 众所周知,BLOB 是用来存储图片、PDF、等大数据对象的。由于公司的需要我们所有的数据库操作都要使用存储过程来操作。所以首先先贴上一个BLOB存储的存储过程供大家参考:

create or replace
procedure NDSSP_backup_fund (fund_id_in in varchar2 ,selector_in in varchar2,
time_in in timestamp,blob_in in BLOB) 
  is
    key number;
    blob_tmp blob;
  begin
    delete from fund_backup bf where bf.selector = selector_in and bf.fund_id = fund_id_in;
    select fund_backup_seq.nextval into key from dual;
    insert into fund_backup values(key,selector_in,fund_id_in,empty_blob(),time_in);
    select content into  blob_tmp from fund_backup where id = key for update;
    dbms_lob.copy(blob_tmp, blob_in, dbms_lob.getLength(blob_in));
  end NDSSP_backup_fund;

  大家只要关注BLOB存储的部分就好了,其他的部分都可以忽略。正如大家所看到的,我们想要调用这个存储过程,必须要传递一个BLOB 对象。BLOB对象比较特殊,我们不能直接去new它。我们必须要调用Oracle 驱动提供的 createTemporary方法,具体代码如下:

    private BLOB transformObj2Blob(Object obj, Connection conn)
    {
	OutputStream os = null;
	ObjectOutputStream oos = null;
	BLOB blob = null;
	try
	{
	    blob = BLOB.createTemporary(conn, true, BLOB.DURATION_SESSION);
	    os = blob.setBinaryStream(0l);
	    oos = new ObjectOutputStream(os);
	    oos.writeObject(obj);
	    oos.flush();
	    os.flush();
	}
	catch (SQLException e)
	{
	    e.printStackTrace();
	}
	catch (IOException e)
	{
	    e.printStackTrace();
	}
	finally
	{

	    try
	    {
		if (oos != null)
		    oos.close();
	    }
	    catch (IOException e)
	    {
		LogUtil.debug(e);
	    }
	}

	return blob;
    }

 这里又引入了一个新的问题: connection , 大家可能觉得 connection 能有什么问题 就是数据库连接嘛,没错它就是数据库连接,但是在这个方法中conn 会被强制转化成 oracle.jdbc.driver.OracleDriver 这就意味着我们传进去的Connection 必须原始的没有经过任何包装的connection。但是在这个连接池充斥的年代,我们很难拿到原始的Connection了我们拿到的都是经过包装的Connection了。所以一般第一次用这个方法的人都很有可能遇到CastException 。如何拿到原始的Connection不同的连接池有不同的方法:

1、Tomcat 连接池(dbcp 如此类似):

if(connecion instanceof org.apache.tomcat.dbcp.dbcp.DelegatingConnection)
		{
			realConn =  ((org.apache.tomcat.dbcp.dbcp.DelegatingConnection) connecion)
				.getInnermostDelegate();
			return realConn;
		}

 2、Webphere 连接池:

if(connecion instanceof com.ibm.ws.rsadapter.jdbc.WSJdbcConnection)
		{
			realConn = (Connection) com.ibm.ws.rsadapter.jdbc.WSJdbcUtil.
			getNativeConnection(
				(com.ibm.ws.rsadapter.jdbc.WSJdbcConnection)connecion);
			return realConn;
		}
 

 3、MyBaits 连接池(Pooled 方式):

realConn = PooledDataSource.unwrapConnection(connecion);

 

其他的连接池需要自己去探索了。如果你认为到此这篇文章已经结束了那你就错了。对于我这种用Mybatis的悲催男来说这远远没有结束。大家请看这段代码:

 try {
      final Environment environment = configuration.getEnvironment();
      final DataSource dataSource = getDataSourceFromEnvironment(environment);
      TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      Connection connection = dataSource.getConnection();
      if (level != null) {
        connection.setTransactionIsolation(level.getLevel());
      }
      connection = wrapConnection(connection);
      Transaction tx = transactionFactory.newTransaction(connection, autoCommit);
      Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (SQLException e) {
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }


 private Connection wrapConnection(Connection connection) {
    if (log.isDebugEnabled()) {
      return ConnectionLogger.newInstance(connection);
    } else {
      return connection;
    }
  }

让我们再来看看ConnectionLogger.newInstance(connection) 方法:

public static Connection newInstance(Connection conn) {
    InvocationHandler handler = new ConnectionLogger(conn);
    ClassLoader cl = Connection.class.getClassLoader();
    return (Connection) Proxy.newProxyInstance(cl, new Class[]{Connection.class}, handler);
  }

  看到原因了吧,只要你开启了Log 到debug 级别(isDebugEnabled 还没研究 不同环境表现不同 大家见谅),MyBatis tm的把所有 connection 动态代理了一遍。只要你通过session.getConnection 方法拿connection,不管你有没有用连接池用的是啥连接池,你拿到的都不一定是原始的connection。纠结的Mybatis啊。看到这里我很有改源代码的冲动啊。所以我们不能通过session直接拿connection了,我们必须先拿到数据源然后直接从数据源拿connection然后调用上边说的转化方式拿原始的connection:

connecion=session.getConfiguration().getEnvironment().getDataSource().getConnection();

 

到此这篇文章结束了 希望能够给同学们一点帮助……

我的微薄:http://weibo.com/lei6744

 

分享到:
评论
2 楼 grayliu 2011-07-19  
good,加关注。。。。
1 楼 yixiugg 2011-07-19  
很有帮助,顶,re,赞

相关推荐

Global site tag (gtag.js) - Google Analytics