tag:blogger.com,1999:blog-52773822854387379602007-07-11T16:38:35.024+01:00OrindaBlogDavid RolfeBlogger4125tag:blogger.com,1999:blog-5277382285438737960.post-55449828574128132302007-07-07T20:03:00.000+01:002007-07-07T20:12:17.334+01:00Why '43113f32554e54494d45110e4350500308' is bad news for Java users...<p>While going through our web server logs recently we found out that we had our first single word google hit. Unfortunately the word in question is <a href="http://www.google.com/search?hl=en&q=43113f32554e54494d45110e4350500308&btnG=Google+Search">43113f32554e54494d45110e4350500308</a>,<br />which we suspect isn't terribly memorable. It's thrown as an error id when the JVM crashes and is referred to in the <a href="http://www.orindasoft.com/public/Supporttwo.php4#Java_VM_Crashes_when_asked_to_generate_a_large_number%28hundreds%29_of_java_files">support</a> section of our web site.</p><p>We've now had hundreds of people show up at our web site trying to find out about this. We suspect we may see many more, as the underlying problem appears to affect all applications that use the Java 1.3 or 1.4 JVMs.</p><p>If you encounter this you will find the following information useful:<br /></p><p></p><ul><ul><li>This is Sun bug <a class="news" href="http://developer.java.sun.com/developer/bugParade/bugs/4820592.html" target="_blank">4820592</a>.</li><li>The bug appears to be limited to x86 based systems.</li><li>The bug will appear as a JVM crash after the application has done a fair amount of work.</li><li>If you try and use the 'debug' mode of an IDE such as Eclipse the JVM crash will take place at odd and changing locations.</li><li>Using interpreted mode ('-Xint') is an effective workaround.</li><li>Changing other JVM parameters may postpone the crash but will not prevent it.</li><li>To prevent it you can:<br /></li><ul><li>Move to Java 1.5</li></ul><ul><li>Rewrite your code.</li></ul></ul></ul>In our case we were able to fix the problem by replacing an ArrayList of String[] with an ArrayList of File, with each File containing 0 or more String. We suspect that the presence of zero length 'String[]'s in the arraylist was the root cause of the problem.<br /><p></p><p><span style="font-size:78%;">[This post originally appeared on JRoller]</span> </p>David Rolfetag:blogger.com,1999:blog-5277382285438737960.post-13553242010885786142007-07-07T07:36:00.000+01:002007-07-07T19:59:07.421+01:00LOBS, BLOBS and BFILES in Oracle<span style="font-size:130%;">Summary</span><br /><br />Oracle users currently have 3 different <b>L</b>arge <b>OB</b>ject data types to choose from - BLOB, CLOB and BFILE. We'll look at the basic mechanics of how they work from a Java developers perspective and then explain why oracle.sql.BFILE poses serious challanges for web service developers.L<br /><br /><span style="font-size:130%;">LOB's 101</span><br /><br />When you retrieve an oracle.sql.BLOB or oracle.sql.CLOB the single most important thing to understand is that you're dealing with a pointer, not a file. Not only that, but that the oracle.sql.CLOB you just retrieved from the database is totally independent of the SQL statement or PL/SQL procedure that was used to return it to you. What you've actually got is a pointer to a large object inside the database that will continue to exist until your commit, rollback or lose your connection. Once you understand this life will become bearable. There are significant API changes for Oracle's JDBC drivers as you move up through the different versions of Oracle. You will need to re-read the JavaDocs and check your LOB code line by line when you upgrade. Of course, if you used <a href="http://www.orindasoft.com/public/features.php4" target="_blank">OrindaBuild</a> you could just re-generate your code...<br /><br /><span style="font-size:130%;">BFILE</span><br /><br />oracle.sql.BFILE is different. A BFILE is a pointer to a file that resides <i>outside</i> the database. In fact a BFILE consists of two things:<br /><ol><li>The name of an Oracle DIRECTORY (as found in the ALL_DIRECTORIES view)</li><li>The name of the file within that directory </li></ol>oracle.sql.BFILE objects are small - often under 100 bytes. Oracle makes no attempt to verify that the file referred to by the oracle.sql.BFILE exists and is usable until you attempt to read from it. The only way to create an oracle.sql.BFILE is to call use the SQL function BFILENAME, which implies a database call. You can quite happily create BFILE objects for files which don't exist. This makes sense when you consider how much work checking every BFILE every time it was referred to would impose on the server, but obviously needs to be understood by the developer.<br /><span style="font-size:130%;"><br />LOBs and Web Services </span><br /><br />If you're going to write a Web Service app and are one of the surprising number of people who are still on 8i you should upgrade to at least 9i. Creating CLOBS and BLOBS is a lot easier because of the <a href="http://www.orindasoft.com/public/Web%20Servicestwo.php4#lobs">createTemporary()</a> method that appears in 9.0.1.Using LOBS in a Web Service environment is not a problem, provided you think carefully about how big the LOBs will actually be and how much memory you'll need - Oracle can support huge CLOBS and BLOBS that simply wouldn't be practical in a Web Service scenario.Creating BFILES and Web Services. If you are writing a web service application that stores LOBs in Oracle you should avoid the use of the BFILE data type. It may well seem very tempting but the JVM which is running the service will need to be on the same filesystem as the Oracle database server, which will severly limit scalability. If, as is normal, your JVM is on a different machine you could in theory get round this by creating a BFILE that points to a non-existent directory/file on the database server and then trying to asynchronously move the file to where the BFILE pointer claims it is before anyone actually tries to read the BFILE. For obvious reasons we don't recommend this.<br /><p><span style="font-size:78%;">[This post originally appeared on JRoller] <br /></span></p>David Rolfetag:blogger.com,1999:blog-5277382285438737960.post-45913806231793063162007-07-01T17:51:00.000+01:002007-07-10T18:52:13.030+01:00Not All Jdbc Advice Is Good JDBC Advice...While wandering around the web I stumbled across a link to a <a href="http://www.onjava.com/pub/a/onjava/excerpt/oraclejdbc_19/index.html?page=1"> sample chapter</a> for 'Java Programming with Oracle JDBC', published in December 2001 by O'Reilly. Now 2001 is a bit dated but one would assume that if they are plugging it on their web site it must still be relevent. And that any <i>glaring errors</i> would have been corrected, right? Think again...<p></p><p>The author spends the chapter conducting elaborate benchmarks which in his view demonstrate that there's nothing special about <b>PreparedStatement</b> and that you should really be using <b>Statement</b> most of the time. His reasoning is based on the premise that the additional set up costs of <i>Prepare</i>ing a statement and sending all the bind variables etc cause applications to run more slowly than if you had simply said something like:<br /></p><br /><br />Statement stmt = conn.createStatement();<br /><br />stmt.executeUpdate(<br />"values ( " + Integer.toString( i ) + ", '125678901234567890', " +<br /><br />"'1234567890', " +<br /><br />"USER, to_date('" + sdf.format(new java.util.Date(System.currentTimeMillis()))<br /><br />+ "', 'YYYYMMDDHH24MISS'))");<br /><br />instead of:<br /><br /><br />PreparedStatement stmt = conn.prepareStatement(<p></p><p>"insert into oehr.testxxxperf ( id, code, descr, "</p><p>+ "insert_user, insert_date ) " +</p><p>"values ( ?, ?, ?, ?, ? )");</p><p>startTime = System.currentTimeMillis();</p><p>int i=1;</p><p>stmt.setInt(1,i);</p><p>stmt.setString(2,"123456789012345678901234567890");</p><p> <br />stmt.setString(3,"123456789019012345678901234567890");</p><p>stmt.setString(4,"ZXVI01");</p><p>stmt.setDate(5,new java.sql.Date(System.currentTimeMillis()));</p><p>stmt.executeUpdate();</p><p><br />The point made is that unless you plan on issuing <i>hundreds</i> of statements the first method is faster because it has fewer network round trips and therefore less elapsed time. All of which is true - provided there is only 1 copy of the client software being used. In practice what will happen is that using <b>Statement</b> in preference to <b>PreparedStatement</b> will cause the database server to devote significant resources to compiling execution plans for <i>each and every</i> version of the insert statement being called. Indeed, not using <b>PreparedStatement</b> and bind variables is listed as the second most common mistake in Oracle's '<br /><a href="http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96532/ch2.htm#13670">Top Ten Mistakes Found in Oracle Systems</a>'.There's also a less obvious but equally serious problem with cobbling together your SQL statements instead of using bind variables and <b>PreparedStatement</b> - sooner or later someone with an apostrophe in their name will show up and cause a syntax error:<br /><code><br />Int empno = 42;<br />String empname = "O'Reilly";<br />String myStatement = "INSERT INTO EMP (empno, ename) VALUES ("<br /> + empno + ",'" + empname + "');";<br /></code><br />But wait... it gets worse! If you're working on a public facing web system and some bright spark realizes you are hacking together SQL statements you could have something like this happen:<br /><br /><code><br />Int empno = 42;<br />String ename = "'Smith', sal = 99999";<br />String myStatement = "UPDATE EMP set ename = "<br /> + ename+ " WHERE empno = " + empno');";<br /></code><br /><br /><p>which means that your Statement would be:</p><br /><br /><code><br />UPDATE EMP set ename = 'Smith', sal = 99999 WHERE empno = 42;<br /></code><br /><br /></p><p><span style="font-size:78%;">[This post originally appeared on JRoller]</span></p>David Rolfetag:blogger.com,1999:blog-5277382285438737960.post-83265680627050364592007-07-01T17:27:00.000+01:002007-07-07T19:57:53.796+01:00Rowid Madness<p>For years the first of my interview questions for Oracle developers has been one in which I ask them to explain why it's a bad idea to use the ROWID of table 'A' as a foreign key to table 'B'. This is not hard for a competant person to answer, as ROWID changes when you import the data into another database which will happen sooner or later. It never occured to me that someone could be crazy enough to actually do this, but someone <a href="http://groups-beta.google.com/group/comp.databases.oracle.server/browse_frm/thread/5a70bbe4a79cd596/e981567d07fee3fe?q=ROWID+group:comp.databases.oracle.*&rnum=1&hl=en#e981567d07fee3fe"> has</a>.</p><br /><p><span style="font-size:78%;">[This post originally appeared on JRoller]</span><br /></p>David Rolfe