??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品99导航,欧美日韩中文字幕,亚洲精品99久久久久http://www.aygfsteel.com/xixidabao/category/15376.htmlGROW WITH JAVAzh-cnFri, 24 Aug 2007 09:13:35 GMTFri, 24 Aug 2007 09:13:35 GMT60如何在oracle使用blob,clobhttp://www.aygfsteel.com/xixidabao/archive/2007/08/22/138584.htmlJAVA之\JAVA之\Wed, 22 Aug 2007 05:05:00 GMThttp://www.aygfsteel.com/xixidabao/archive/2007/08/22/138584.html?http://blog.tostudy.com.cn/blog/show_930.html 


一.写入BLOB

1.先在blob中插入empty_blob()
2.获得对刚刚插入记录的引用
BLOB blob = (BLOB) rs.getBlob("你的blob字段名称");
3.写入
OutputStream out = blob.getBinaryOutputStream();
out.write(ENCYPWD);//注意q里
?dBLOB

1.blob  = rs.getBlob("你的blob字段名称");
2.
InputStream is = blob.getBinaryStream();
int length = (int) blob.length();
byte[] buffer = new byte[length];
is.read(buffer);
is.close();
3.你有?jin)is随便处理了(jin)
比如说输出到一个文?br>FileOutputStream fo = new FileOutputStream(filename);//数据到的文g?br>fo.write(buffer);
fo.close();

环境Q?br>Database: Oracle 9i
App Server: BEA Weblogic 8.14
表结构:(x)
CREATE TABLE TESTBLOB (ID Int, NAME Varchar2(20), BLOBATTR Blob)
CREATE TABLE TESTBLOB (ID Int, NAME Varchar2(20), CLOBATTR Clob)   JAVA可以通过JDBCQ也可以通过JNDI讉Kq操作数据库Q这两种方式的具体操作存在着一些差异,׃通过App Server的数据库q接池JNDI获得的数据库q接提供的java.sql.Blob和java.sql.Clob实现cMJDBC方式提供的不同,因此在入库操作的时候需要分别对待;出库操作没有q种差异Q因此不用单独对待?
一、BLOB操作
1、入?br>Q?QJDBC方式
    //通过JDBC获得数据库连?br>    Class.forName("oracle.jdbc.driver.OracleDriver");
    Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:testdb", "test", "test");
    con.setAutoCommit(false);
    Statement st = con.createStatement();
    //插入一个空对象empty_blob()
    st.executeUpdate("insert into TESTBLOB (ID, NAME, BLOBATTR) values (1, "thename", empty_blob())");
    //锁定数据行进行更斎ͼ注意“for update”语句
    ResultSet rs = st.executeQuery("select BLOBATTR from TESTBLOB where ID=1 for update");
    if (rs.next())
    {
        //得到java.sql.Blob对象后强制{换ؓ(f)oracle.sql.BLOB
        oracle.sql.BLOB blob = (oracle.sql.BLOB) rs.getBlob("BLOBATTR");
        OutputStream outStream = blob.getBinaryOutputStream();
        //data是传入的byte数组Q定义:(x)byte[] data
        outStream.write(data, 0, data.length);
    }
    outStream.flush();
    outStream.close();
    con.commit();
    con.close(); Q?QJNDI方式
    //通过JNDI获得数据库连?br>    Context context = new InitialContext();
    ds = (DataSource) context.lookup("ORA_JNDI");
    Connection con = ds.getConnection();
    con.setAutoCommit(false);
    Statement st = con.createStatement();
    //插入一个空对象empty_blob()
    st.executeUpdate("insert into TESTBLOB (ID, NAME, BLOBATTR) values (1, "thename", empty_blob())");
    //锁定数据行进行更斎ͼ注意“for update”语句
    ResultSet rs = st.executeQuery("select BLOBATTR from TESTBLOB where ID=1 for update");
    if (rs.next())
    {
        //得到java.sql.Blob对象后强制{换ؓ(f)weblogic.jdbc.vendor.oracle.OracleThinBlobQ不同的App Server对应的可能会(x)不同Q?br>        weblogic.jdbc.vendor.oracle.OracleThinBlob blob = (weblogic.jdbc.vendor.oracle.OracleThinBlob) rs.getBlob("BLOBATTR");
        OutputStream outStream = blob.getBinaryOutputStream();
        //data是传入的byte数组Q定义:(x)byte[] data
        outStream.write(data, 0, data.length);
    }
    outStream.flush();
    outStream.close();
    con.commit();
    con.close(); 2、出?br>    //获得数据库连?br>    Connection con = ConnectionFactory.getConnection();
    con.setAutoCommit(false);
    Statement st = con.createStatement();
    //不需?#8220;for update”
    ResultSet rs = st.executeQuery("select BLOBATTR from TESTBLOB where ID=1");
    if (rs.next())
    {
        java.sql.Blob blob = rs.getBlob("BLOBATTR");
        InputStream inStream = blob.getBinaryStream();
        //data是读出ƈ需要返回的数据Q类型是byte[]
        data = new byte[input.available()];
        inStream.read(data);
        inStream.close();
    }
    inStream.close();
    con.commit();
    con.close();   二、CLOB操作
1、入?br>Q?QJDBC方式
    //通过JDBC获得数据库连?br>    Class.forName("oracle.jdbc.driver.OracleDriver");
    Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:testdb", "test", "test");
    con.setAutoCommit(false);
    Statement st = con.createStatement();
    //插入一个空对象empty_clob()
    st.executeUpdate("insert into TESTCLOB (ID, NAME, CLOBATTR) values (1, "thename", empty_clob())");
    //锁定数据行进行更斎ͼ注意“for update”语句
    ResultSet rs = st.executeQuery("select CLOBATTR from TESTCLOB where ID=1 for update");
    if (rs.next())
    {
        //得到java.sql.Clob对象后强制{换ؓ(f)oracle.sql.CLOB
        oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob("CLOBATTR");
        Writer outStream = clob.getCharacterOutputStream();
        //data是传入的字符Ԍ定义QString data
        char[] c = data.toCharArray();
        outStream.write(c, 0, c.length);
    }
    outStream.flush();
    outStream.close();
    con.commit();
    con.close();
Q?QJNDI方式
    //通过JNDI获得数据库连?br>    Context context = new InitialContext();
    ds = (DataSource) context.lookup("ORA_JNDI");
    Connection con = ds.getConnection();
    con.setAutoCommit(false);
    Statement st = con.createStatement();
    //插入一个空对象empty_clob()
    st.executeUpdate("insert into TESTCLOB (ID, NAME, CLOBATTR) values (1, "thename", empty_clob())");
    //锁定数据行进行更斎ͼ注意“for update”语句
    ResultSet rs = st.executeQuery("select CLOBATTR from TESTCLOB where ID=1 for update");
    if (rs.next())
    {
        //得到java.sql.Clob对象后强制{换ؓ(f)weblogic.jdbc.vendor.oracle.OracleThinClobQ不同的App Server对应的可能会(x)不同Q?br>        weblogic.jdbc.vendor.oracle.OracleThinClob clob = (weblogic.jdbc.vendor.oracle.OracleThinClob) rs.getClob("CLOBATTR");
        Writer outStream = clob.getCharacterOutputStream();
        //data是传入的字符Ԍ定义QString data
        char[] c = data.toCharArray();
        outStream.write(c, 0, c.length);
    }
    outStream.flush();
    outStream.close();
    con.commit();
    con.close(); 2、出?br>    //获得数据库连?br>    Connection con = ConnectionFactory.getConnection();
    con.setAutoCommit(false);
    Statement st = con.createStatement();
    //不需?#8220;for update”
    ResultSet rs = st.executeQuery("select CLOBATTR from TESTCLOB where ID=1");
    if (rs.next())
    {
        java.sql.Clob clob = rs.getClob("CLOBATTR");
        Reader inStream = clob.getCharacterStream();
        char[] c = new char[(int) clob.length()];
        inStream.read(c);
        //data是读出ƈ需要返回的数据Q类型是String
        data = new String(c);
        inStream.close();
    }
    inStream.close();
    con.commit();
    con.close();   需要注意的地方Q?br>1、java.sql.Blob、oracle.sql.BLOB、weblogic.jdbc.vendor.oracle.OracleThinBlob几种cd的区?br>2、java.sql.Clob、oracle.sql.CLOB、weblogic.jdbc.vendor.oracle.OracleThinClob几种cd的区?/strong>

JAVA之\ 2007-08-22 13:05 发表评论
]]>
Servlet开发中JDBC的高U应?/title><link>http://www.aygfsteel.com/xixidabao/archive/2006/05/21/47390.html</link><dc:creator>JAVA之\</dc:creator><author>JAVA之\</author><pubDate>Sun, 21 May 2006 15:47:00 GMT</pubDate><guid>http://www.aygfsteel.com/xixidabao/archive/2006/05/21/47390.html</guid><description><![CDATA[ <b>q结数据?/b> <br /> <br />  <a class="bluekey" target="_blank">JDBC</a>使用数据?a class="bluekey" target="_blank">URL</a>来说?a class="bluekey" target="_blank">数据库驱动程?/a>。数据库URLcM?a class="bluekey" target="_blank">通用</a>的URLQ但SUN 在定义时作了(jin)一点简化,?a class="bluekey" target="_blank">语法</a>如下Q?<br /><br />  <a class="bluekey" target="_blank">Jdbc:</a>:[node]/[<a class="bluekey" target="_blank">database</a>] <br /><br />  其中子协议(subprotocalQ定?a class="bluekey" target="_blank">驱动</a>E序cdQnode提供|络数据库的位置和端口号Q后面跟可选的参数。例如:(x) <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td><a class="bluekey" target="_blank">String</a> url=”jdbc:inetdae:myser<a class="bluekey" target="_blank">ver:1</a>433<a class="bluekey" target="_blank">?l</a>anguage=us-<a class="bluekey" target="_blank">english</a>&sql7=<a class="bluekey" target="_blank">true</a>?</td></tr></tbody></table><br />  表示采用inetdae驱动E序q接<a class="bluekey" target="_blank">1433</a>端口上的my<a class="bluekey" target="_blank">server数据?/a>服务器,选择<a class="bluekey" target="_blank">语言</a>为美国英语,数据库的版本是ms<a class="bluekey" target="_blank">sql server</a> 7.0?<br /><br />  <a class="bluekey" target="_blank">java</a>应用通过指定DriverManager装入一个驱动程序类。语法如下:(x) <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>Class.forName(“?;</td></tr></tbody></table><br />  ? <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>Class.forName(“?.newInstance(); </td></tr></tbody></table><br />  然后QDriverManager创徏一个特定的q接Q?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td><a class="bluekey" target="_blank">Connection</a> connection=DriverManager.getConnection(url,<a class="bluekey" target="_blank">login</a>,<a class="bluekey" target="_blank">password</a>)Q?</td></tr></tbody></table><br />  Connection<a class="bluekey" target="_blank">接口</a>通过指定数据库位|,d名和密码<a class="bluekey" target="_blank">q接数据?/a>。Connection接口创徏一个Statement实例<a class="bluekey" target="_blank">执行</a>需要的查询Q?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>Statement stmt=connection.createStatement(); </td></tr></tbody></table><br />  Statementh各种Ҏ(gu)Q?a class="bluekey" target="_blank">API</a>Q,如executeQueryQ?a class="bluekey" target="_blank">execute</a>{可以返回查询的l果集。结果集是一?a class="bluekey" target="_blank">ResultSet</a>对象。具体的可以通过jdbc开发文?a class="bluekey" target="_blank">查看</a>。可以sun的站点上下蝲 <br /><br />  下面例子来说明:(x) <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td><a class="bluekey" target="_blank">import</a><a class="bluekey" target="_blank">java</a>.sql.*; // 输入JDBC <a class="bluekey" target="_blank">package</a><br /><br />String url = "jdbc:inetdae:myserver:1433";// <a class="bluekey" target="_blank">L?/a>和端?<br />String login = "<a class="bluekey" target="_blank">user</a>";// d?<br />String password = "";// 密码 <br /><br />try { <br />  DriverManager.setLogStream(System.out); <a class="bluekey" target="_blank">file</a>://为显CZ些的信息打开一个流 <br />  file://<a class="bluekey" target="_blank">调用</a>驱动E序Q其名字?a class="bluekey" target="_blank">com</a>.<a class="bluekey" target="_blank">inet</a>.tds.TdsDriver <br />  file://Class.forName("<a class="bluekey" target="_blank">com</a>.<a class="bluekey" target="_blank">inet</a>.tds.TdsDriver")Q?<br />  file://讄<a class="bluekey" target="_blank">时</a><br />  DriverManager.setLoginTimeout(10); <br />  file://打开一个连?<br />  Connection connection = DriverManager.getConnection(url,login,password); <br />  file://得到数据库驱动程序版?<br /><br />   DatabaseMetaData conMD = connection.getMetaData(); <br />   System.out.println("<a class="bluekey" target="_blank">Driver</a><a class="bluekey" target="_blank">Name</a>:\t" + conMD.getDriverName()); <br />   System.out.println("<a class="bluekey" target="_blank">Driver</a><a class="bluekey" target="_blank">Version</a>:\t" + conMD.getDriverVersion()); <br /><br />  file://选择数据?<br />  connection.setCatalog( "MyDatabase"); <br /><br />  file://创徏Statement <br /><br />  Statement <a class="bluekey" target="_blank">st</a> = connection.createStatement(); <br /><br />  file://执行查询 <br /><br />  ResultSet rs = st.executeQuery("<a class="bluekey" target="_blank">SELECT</a> * FROM mytable"); <br /><br />  file://取得l果Q输出到屏幕 <br /><br />  while (rs.next()){ <br />     <a class="bluekey" target="_blank">for</a>(<a class="bluekey" target="_blank">int</a> j=1; j<=rs.getMetaData().getColumnCount(); j++){ <br />      System.out.<a class="bluekey" target="_blank">print</a>( rs.getObject(j)+"\t"); <br />     } <br />   System.out.println(); <br />  } <br /><br />  file://关闭对象 <br />  st.close(); <br />    connection.close(); <br />  } catch(<a class="bluekey" target="_blank">Exception</a> e) { <br />    e.printStackTrace(); <br />  } </td></tr></tbody></table><br /><br /><br /><b>建立q结?/b><br /><br />  一个动态的|站频繁C数据库中取得数据来构成html面。每一ơ请求一个页面都?x)发生数据库操作。但q接数据库却是一个需要消耗大量时间的工作Q因求连接需要徏立通讯Q分配资源,q行权限认证。这些工作很能在一两秒内完成。所以,建立一个连接,然后再后l的查询中都使用此连接会(x)大大地提高性能。因为servlet可以在不同的h间保持状态,因此采用数据库连接池是一个直接的解决Ҏ(gu)?<br /><br />  Servlet在服务器的进E空间中ȝQ可以方便而持久地l护数据库连接。接下来Q我们介l一个完整的q接池的实现。在实现中,有一个连接池理器管理连接池对象Q其中每一个连接池保持一l数据库q接对象Q这些对象可ZQ何servlet所使用?<br /><br />  一、数据库q接池类 DBConnectionPool,提供如下的方法:(x) <br /><br />  1、从池中取得一个打开的连接; <br /><br />  2、将一个连接返回池中; <br /><br />  3、在关闭旉放所有的资源Qƈ关闭所有的q接?<br /><br />  另外QDBConnectionPoolq处理连接失败,比如时Q通讯p|{错误,q且Ҏ(gu)预定义的参数限制池中的连接数?<br /><br />  二、管理者类QDBConnetionManagerQ是一个容器将q接池封装在内,q管理所有的q接池。它的方法有Q?<br /><br />  1?调用和注册所有的jdbc驱动E序Q?<br /><br />  2?Ҏ(gu)参数表创建DBConnectionPool对象Q?<br /><br />  3?映射q接池的名字和DBConnectionPool实例Q?<br /><br />  4?当所有的q接客户退出后Q关闭全部连接池?<br /><br />  q些cȝ实现Q以?qing)如何在servlet中用连接池的应用在随后的文章中讲解 <br /><br />  DBConnectionPoolcM表一个由url标识的数据库q接池。前面,我们已经提到Qjdbc的url׃个部分组成:(x)协议标识QLjdbcQ?子协议标识(例如Qodbc.oracleQ?和数据库标识Q跟特定的数据库有关Q。连接池也具有一个名字,供客L(fng)序引用。另外,q接池还有一个用户名Q一个密码和一个最大允许连接数。如果web应用允许所有的用户使用某些数据库操作,而另一些操作是有限制的Q则可以创徏两个q接池,h同样的url,不同的user name和passwordQ分别处理两cM同的操作权限。现把DBConnectionPool详细介绍如下Q?<br /><br />  三、DBConnectionPool的构?<br /><br />  构造函数取得上q的所有参敎ͼ(x) <br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>public DBConnectionPool(String name, String URL, String user, <br />String password, int maxConn) { <br /> this.name = name; <br /> this.URL = URL; <br /> this.user = user; <br /> this.password = password; <br /> this.maxConn = maxConn; <br />} </td></tr></tbody></table><br />  所有的参数保存在实例变量中?<br /><br />  四、从池中打开一个连?<br /><br />  DBConnectionPool提供两种Ҏ(gu)来检查连接。两U方法都q回一个可用的q接Q如果没有多余的q接Q则创徏一个新的连接。如果最大连接数已经辑ֈQ第一个方法返回nullQ第二个Ҏ(gu)则等待一个连接被其他q程释放?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>public synchronized Connection getConnection() { <br /> Connection con = null; <br /> if (freeConnections.size() > 0) { <br />  // Pick the first Connection in the Vector <br />  // to get round-robin usage <br />  con = (Connection) freeConnections.firstElement(); <br />  freeConnections.removeElementAt(0); <br />  try { <br />   if (con.isClosed()) { <br />    log("Removed bad connection from " + name); <br />    // Try again recursively <br />    con = getConnection(); <br />   } <br />  } <br />  catch (SQLException e) { <br />   log("Removed bad connection from " + name); <br />   // Try again recursively <br />   con = getConnection(); <br />  } <br /> } <br /> else if (maxConn == 0 || checkedOut < maxConn) { <br />  con = newConnection(); <br /> } <br /> if (con != null) { <br />  checkedOut++; <br /> } <br /> return con; <br />} </td></tr></tbody></table><br />  所有空闲的q接对象保存在一个叫freeConnections 的Vector中。如果存在至一个空闲的q接QgetConnection()q回其中W一个连接。下面,会(x)看到Q进E释攄q接q回到freeConnections的末。这P最大限度地避免?jin)数据库因一个连接不zd而意外将其关闭的风险?<br /><br />  再返回客户之前,isClosed()(g)查连接是否有效。如果连接被关闭?jin),或者一个错误发生,该方法递归调用取得另一个连接?<br /><br />  如果没有可用的连接,该方法检查是否最大连接数被设|ؓ(f)0表示无限q接敎ͼ或者达C(jin)最大连接数。如果可以创建新的连接,则创Z个新的连接。否则,q回null?<br /><br />  Ҏ(gu)newConnection()用来创徏一个新的连接。这是一个私有方法,Z用户名和密码来确定是否可以创建新的连接?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>private Connection newConnection() { <br /> Connection con = null; <br /> try { <br />  if (user == null) { <br />   con = DriverManager.getConnection(URL); <br />  } <br />  else { <br />   con = DriverManager.getConnection(URL, user, password); <br />  } <br />  log("Created a new connection in pool " + name); <br /> } <br /> catch (SQLException e) { <br />  log(e, "Can not create a new connection for " + URL); <br />  return null; <br /> } <br /> return con; <br />}</td></tr></tbody></table><br />  jdbc的DriverManager提供一pd的getConnectionQ)(j)Ҏ(gu)Q可以用url和用户名Q密码等参数创徏一个连接?<br /><br />  W二个getConnection()Ҏ(gu)带有一个超时参?timeout,当该参数指定的毫U数表示客户愿意Z个连接等待的旉。这个方法调用前一个方法?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>public synchronized Connection getConnection(long timeout) { <br /> long startTime = new Date().getTime(); <br /> Connection con; <br /> while ((con = getConnection()) == null) { <br />  try { <br />   wait(timeout); <br />  } <br />  catch (InterruptedException e) {} <br />  if ((new Date().getTime() - startTime) >= timeout) { <br />   // Timeout has expired <br />   return null; <br />  } <br /> } <br /> return con; <br />} </td></tr></tbody></table><br />  局部变量startTime初始化当前的旉。一个while循环首先试获得一个连接,如果p|Qwait()函数被调用来{待需要的旉。后面会(x)看到QW(xu)ait()函数?x)在另一个进E调用notify()或者notifyAll()时返回,或者等到时间流逝完毕。ؓ(f)?jin)确定wait()是因ZU原因返回,我们用开始时间减d前时_(d)(g)查是否大于timeout。如果结果大于timeout,q回null,否则Q在此调用getConnection()函数?<br /><br />  五、将一个连接返回池?<br /><br />  DBConnectionPoolcM有一个freeConnectionҎ(gu)以返回的q接作ؓ(f)参数Q将q接q回q接池?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>public synchronized void freeConnection(Connection con) { <br /> // Put the connection at the end of the Vector <br /> freeConnections.addElement(con); <br /> checkedOut--; <br /> notifyAll(); <br />} </td></tr></tbody></table><br />  q接被加在freeConnections向量的最后,占用的连接数?Q调用notifyAll()函数通知其他{待的客L(fng)在有?jin)一个连接?<br /><br />  六、关?<br /><br />  大多数servlet引擎提供完整的关闭方法。数据库q接池需要得到通知以正地关闭所有的q接。DBConnectionManager负责协调关闭事gQ但q接由各个连接池自己负责关闭。方法r(sh)elase()由DBConnectionManager调用?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>public synchronized void release() { <br /> Enumeration allConnections = freeConnections.elements(); <br /> while (allConnections.hasMoreElements()) { <br />  Connection con = (Connection) allConnections.nextElement(); <br />  try { <br />   con.close(); <br />   log("Closed connection for pool " + name); <br />  } <br />  catch (SQLException e) { <br />   log(e, "Can not close connection for pool " + name); <br />  } <br /> } <br /> freeConnections.removeAllElements(); <br />} </td></tr></tbody></table><br />  本方法遍历freeConnections向量以关闭所有的q接?<br /><br />  DBConnetionManager的构造函数是U有函数Q以避免其他cd建其实例?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>private DBConnectionManager() { <br /><br />init(); <br /><br />} </td></tr></tbody></table><br />  DBConnetionManager的客戯用getInstance()Ҏ(gu)来得到该cȝ单一实例的引用?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>static synchronized public DBConnectionManager getInstance() { <br />if (instance == null) { <br /> instance = new DBConnectionManager(); <br />} <br />clients++; <br />return instance; <br />} </td></tr></tbody></table><br /><br /><br /><b>q结池用实?/b><br /><br />  单一的实例在W一ơ调用时创徏Q以后的调用q回该实例的?rn)态应用。一个计数器U录所有的客户敎ͼ直到客户释放引用。这个计数器在以后用来协调关闭连接池?<br /><br />  一、初始化 <br /><br />  构造函数调用一个私有的init()函数初始化对象?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>private void init() { <br /> InputStream is = getClass().getResourceAsStream("/db.properties"); <br /> Properties dbProps = new Properties(); <br /> try { <br />  dbProps.load(is); <br /> } <br /> catch (Exception e) { <br />  System.err.println("Can not read the properties file. " + "Make sure db.properties is in the CLASSPATH"); <br />  return; <br /> } <br /><br /> String logFile = dbProps.getProperty("logfile", <br />    "DBConnectionManager.log"); <br /> try { <br />  log = new PrintWriter(new FileWriter(logFile, true), true); <br /> } <br /> catch (IOException e) { <br />  System.err.println("Can not open the log file: " + logFile); <br />  log = new PrintWriter(System.err); <br /> } <br /> loadDrivers(dbProps); <br /> createPools(dbProps); <br />} </td></tr></tbody></table><br />  Ҏ(gu)getResourceAsStream()是一个标准方法,用来打开一个外部输入文件。文件的位置取决于类加蝲器,而标准的cd载器从classpath开始搜索。Db.properties文g是一个Porperties格式的文Ӟ保存在连接池中定义的key-value寏V下面一些常用的属性可以定义:(x) <br /><br />   drivers 以空格分开的jdbc驱动E序的列?<br /><br />   logfile 日志文g的绝对\?<br /><br />  每个q接池中q用另一些属性。这些属性以q接池的名字开_(d)(x) <br /><br />   .url数据库的JDBC URL <br /><br />   .maxconn最大连接数?表示无限?<br /><br />   .userq接池的用户?<br /><br />   .password相关的密?<br /><br />  url属性是必须的,其他属性可选。用户名和密码必d所定义的数据库匚w?<br /><br />  下面是windowsq_下的一个db.properties文g的例子。有一个InstantDBq接池和一个通过odbcq接的access数据库的数据源,名字叫demo?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>drivers=sun.jdbc.odbc.JdbcOdbcDriver jdbc.idbDriver <br /><br />logfile=D:\\user\\src\\java\\DBConnectionManager\\log.txt <br /><br />idb.url=jdbc:idb:c:\\local\\javawebserver1.1\\db\\db.prp <br /><br />idb.maxconn=2 <br /><br />access.url=jdbc:odbc:demo <br /><br />access.user=demo <br /><br />access.password=demopw </td></tr></tbody></table><br />  注意Q反斜线在windowsq_下必d写?<br /><br />  初始化方法init()创徏一个Porperties对象q装载db.properties文gQ然后读取日志文件属性。如果日志文件没有命名,则用缺省的名字DBConnectionManager.log在当前目录下创徏。在此情况下Q一个系l错误被U录?<br /><br />  Ҏ(gu)loadDrivers()指定的所有jdbc驱动E序注册Q装载?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>private void loadDrivers(Properties props) { <br /> String driverClasses = props.getProperty("drivers"); <br /> StringTokenizer st = new StringTokenizer(driverClasses); <br /> while (st.hasMoreElements()) { <br />  String driverClassName = st.nextToken().trim(); <br />  try { <br />   Driver driver = (Driver) <br />   Class.forName(driverClassName).newInstance(); <br />   DriverManager.registerDriver(driver); <br />   drivers.addElement(driver); <br />   log("Registered JDBC driver " + driverClassName); <br />  } <br />  catch (Exception e) { <br />   log("Can not register JDBC driver: " + driverClassName + ", Exception: " + e); <br />  } <br /> } <br />} </td></tr></tbody></table><br />  loadDrivers()使用StringTokenizerdirvers属性分成单独的driverԌq将每个驱动E序装入java虚拟机。驱动程序的实例在JDBC 的DriverManager中注册,q加入一个私有的向量drivers中。向量drivers用来关闭和注销所有的驱动E序?<br /><br />  然后QDBConnectionPool对象q有方法createPools()创徏?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>private void createPools(Properties props) { <br /> Enumeration propNames = props.propertyNames(); <br /> while (propNames.hasMoreElements()) { <br />  String name = (String) propNames.nextElement(); <br />  if (name.endsWith(".url")) { <br />   String poolName = name.substring(0, name.lastIndexOf(".")); <br />   String url = props.getProperty(poolName + ".url"); <br />   if (url == null) { <br />    log("No URL specified for " + poolName); <br />    continue; <br />   } <br />   String user = props.getProperty(poolName + ".user"); <br />   String password = props.getProperty(poolName + ".password"); <br />   String maxconn = props.getProperty(poolName + ".maxconn", "0"); <br />   int max; <br />   try { <br />    max = Integer.valueOf(maxconn).intValue(); <br />   } <br />   catch (NumberFormatException e) { <br />    log("Invalid maxconn value " + maxconn + " for " + poolName); <br />    max = 0; <br />   } <br />   DBConnectionPool pool = new DBConnectionPool(poolName, url, user, password, max); <br />   pools.put(poolName, pool); <br />   log("Initialized pool " + poolName); <br />  } <br /> } <br />} </td></tr></tbody></table><br />  一个枚丑֯象保存所有的属性名Q如果属性名带有.urll尾Q则表示是一个连接池对象需要被实例化。创建的q接池对象保存在一个Hashtable实例变量中。连接池名字作ؓ(f)索引Q连接池对象作ؓ(f)倹{?<br /><br />  二、得到和q回q接 <br /><br />  DBConnectionManager提供getConnectionQ)(j)Ҏ(gu)和freeConnectionҎ(gu)Q这些方法有客户E序使用。所有的Ҏ(gu)以连接池名字所参数Qƈ调用特定的连接池对象?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>public Connection getConnection(String name) { <br /> DBConnectionPool pool = (DBConnectionPool) pools.get(name); <br /> if (pool != null) { <br />  return pool.getConnection(); <br /> } <br /> return null; <br />} <br /><br />public Connection getConnection(String name, long time) { <br /> DBConnectionPool pool = (DBConnectionPool) pools.get(name); <br /> if (pool != null) { <br />  return pool.getConnection(time); <br /> } <br /> return null; <br />} <br /><br />public void freeConnection(String name, Connection con) { <br /> DBConnectionPool pool = (DBConnectionPool) pools.get(name); <br /> if (pool != null) { <br />  pool.freeConnection(con); <br /> } <br />} </td></tr></tbody></table><br />  三、关?<br /><br />  最后,׃个releaseQ)(j)Ҏ(gu)Q用来完好地关闭q接池。每个DBConnectionManager客户必须调用getInstance()Ҏ(gu)引用。有一个计数器跟踪客户的数量。方法r(sh)elease()在客户关闭时调用Q技术器?。当最后一个客户释放,DBConnectionManager关闭所有的q接池?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>public synchronized void release() { <br /> // Wait until called by the last client <br /> if (--clients != 0) { <br />  return; <br /> } <br /><br /> Enumeration allPools = pools.elements(); <br /> while (allPools.hasMoreElements()) { <br />  DBConnectionPool pool = (DBConnectionPool) allPools.nextElement(); <br />  pool.release(); <br /> } <br /><br /> Enumeration allDrivers = drivers.elements(); <br /> while (allDrivers.hasMoreElements()) { <br />  Driver driver = (Driver) allDrivers.nextElement(); <br />  try { <br />   DriverManager.deregisterDriver(driver); <br />   log("Deregistered JDBC driver " + driver.getClass().getName()); <br />  } <br />  catch (SQLException e) { <br />   log(e, "Can not deregister JDBC driver: " + driver.getClass().getName()); <br />  } <br /> } <br />} </td></tr></tbody></table><br />  当所有连接池关闭Q所有jdbc驱动E序也被注销?<br /><br /><br /><b>q结池的作用</b><br /><br />  现在我们l合DBConnetionManager和DBConnectionPoolcL讲解servlet中连接池的用:(x) <br /><br />  一、首先简单介l一下Servlet的生命周期:(x) <br /><br />  Servlet API定义的servlet生命周期如下Q?<br /><br />  1?Servlet 被创建然后初始化Qinit()Ҏ(gu)Q?<br /><br />  2??个或多个客户调用提供服务Qservice()Ҏ(gu)Q?<br /><br />  3?Servlet被销毁,内存被回Ӟdestroy()Ҏ(gu)Q?<br /><br />  二、servlet中用连接池的实?<br /><br />  使用q接池的servlet有三个阶D늚典型表现是:(x) <br /><br />  1Q?在init()中,调用DBConnectionManager.getInstance()然后返回的引用保存在实例变量中?<br /><br />  2Q?在sevice()中,调用getConnection()Q执行一pd数据库操作,然后调用freeConnection()归还q接?<br /><br />  3Q?在destroy()中,调用release()来释放所有的资源Qƈ关闭所有的q接?<br /><br />  下面的例子演C如何用连接池?<br /><br /><table bordercolor="#ffcc66" width="90%" align="center" bgcolor="#dadacf" border="1"><tbody><tr><td>import java.io.*; <br />import java.sql.*; <br />import javax.servlet.*; <br />import javax.servlet.http.*; <br /><br />public class TestServlet extends HttpServlet { <br /> private DBConnectionManager connMgr; <br /><br /> public void init(ServletConfig conf) throws ServletException { <br />  super.init(conf); <br />  connMgr = DBConnectionManager.getInstance(); <br /> } <br /><br /> public void service(HttpServletRequest req, HttpServletResponse res) <br /> throws IOException { <br />  res.setContentType("text/html"); <br />  PrintWriter out = res.getWriter(); <br />  Connection con = connMgr.getConnection("idb"); <br />  if (con == null) { <br />   out.println("Cant get connection"); <br />   return; <br />  } <br />  ResultSet rs = null; <br />  ResultSetMetaData md = null; <br />  Statement stmt = null; <br />  try { <br />   stmt = con.createStatement(); <br />   rs = stmt.executeQuery("SELECT * FROM EMPLOYEE"); <br />   md = rs.getMetaData(); <br />   out.println("Employee data "); <br />   while (rs.next()) { <br />    out.println(" "); <br />    for (int i = 1; i < md.getColumnCount(); i++) { <br />     out.print(rs.getString(i) + ", "); <br />    } <br />   } <br />   stmt.close(); <br />   rs.close(); <br />  } <br />  catch (SQLException e) { <br />   e.printStackTrace(out); <br />  } <br />  connMgr.freeConnection("idb", con); <br /> } <br /> public void destroy() { <br />  connMgr.release(); <br />  super.destroy(); <br /> } <br />} </td></tr></tbody></table><br />  <img src ="http://www.aygfsteel.com/xixidabao/aggbug/47390.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/xixidabao/" target="_blank">JAVA之\</a> 2006-05-21 23:47 <a href="http://www.aygfsteel.com/xixidabao/archive/2006/05/21/47390.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JDBC基础(?http://www.aygfsteel.com/xixidabao/archive/2006/05/10/45555.htmlJAVA之\JAVA之\Wed, 10 May 2006 14:46:00 GMThttp://www.aygfsteel.com/xixidabao/archive/2006/05/10/45555.html    前面说过,Statement对象是用来绑定要执行的操作的,在它上面有三U执行方?
即用来执行查询操作的executeQuery(),用来执行更新操作的executeUpdate()和用来执?br />动态的未知的操作的execute().
    JDBC在编译时q不对要执行的SQL语句(g)?只是把它看着一个String,只有在驱?br />E序执行SQL语句时才知道正确与否.
    一个Statement对象同时只能有一个结果集在活?q是宽容性的,是说即使没?br />调用ResultSet的close()Ҏ(gu),只要打开W二个结果集隐含着对上一个结果集的关?所?br />如果你想同时对多个结果集操作,p创徏多个Statement对象,如果不需要同时操?那么?br />以在一个Statement对象上须序操作多个结果集.
    
    q里我不得不特别说明一?很多Z(x)用一个Statementq行嵌套查询,然后来?br />我说Z么不能@?道理上面已经说清楚了(jin).我们来详l分析一下嵌套查?
    Connection conn = null;
    Statement stmt = null;
    conn = .......;
    stmt = conm.createStatement(xxxxxx);
    ResultSet rs = stmt.executeQuery(sql1);
    while(rs.next()){
        str = rs.getString(xxxxx);
        ResultSet rs1 = stmt.executeQuery(\"select * from 表 where 字段=str\");
    }
当stmt.executeQuery(\"select * from 表 where 字段=str\");赋给rs1?q时隐含的操?br />是已l关闭了(jin)rs,你还能@环下d?
所以如果要同时操作多个l果集一定要让它他绑定到不同的Statement对象?好在一个connection
对象可以创徏L多个Statement对象,而不需要你重新获取q结.

    关于获取和设|Statement的选项:只要看看它的getXXXҎ(gu)和setXXXҎ(gu)明白了(jin),q儿
作ؓ(f)基础知识只提一下以下几?
    setQueryTimeout,讄一个SQL执行的超旉?
    setMaxRows,讄l果集能容纳的行?
    setEscapeProcessing,如果参数为true,则驱动程序在把SQL语句发给数据库前q行转义?br />?否则让数据库自己处理,当然q些默认值都可以通过getҎ(gu)查询.

    Statement的两个子c?
    PreparedStatement:对于同一条语句的多次执行,Statement每次都要把SQL语句发送给数据
?q样做效率明显不?而如果数据库支持预编?PreparedStatement可以先把要执行的语句一ơ发
l它,然后每次执行而不必发送相同的语句,效率当然提高,当然如果数据库不支持预编?
PreparedStatement?x)象Statement一样工?只是效率不高而不需要用户工手干?
    另外PreparedStatementq支持接收参?在预~译后只要传输不同的参数可以执?大大
提高?jin)性能.
        
    PreparedStatement ps = conn.prepareStatement(\"select * from 表 where 字段=?\");
    ps.setString(1,参数);
    ResultSet rs = ps.executeQuery();
    
    CallableStatement:是PreparedStatement的子c?它只是用来执行存储过E的.
    CallableStatement sc = conn.prepareCall(\"{call query()}\");
    ResultSet rs = cs.executeQuery();
    
    关于更高U的知识我们在JDBC高应用中介l? 

JAVA之\ 2006-05-10 22:46 发表评论
]]>
վ֩ģ壺 | | | | | | | | | | | Դ| | | | ֯| ²| ԭ| | | ײ| | | ְ| ̩| | ɽ| ƽ| ƽ| | ɽ| | | | | ³ɽ| | û| | | ʩ|