This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.
NetBeans IDE 5.0 [200509051800] on jdk 1.5.0_05 1) start with clean userdir 2) switch to Runtime|Databases and use context menu to add driver 3) add driver file derby.jar (embeded appache derby) and click OK 4) select 'Apache Derby (Embedded)' node and from context menu invoke Connect Using... 5) in the connect dialog write connect string 'jdbc:derby:test;create=true' and click OK 6) select new connected database node and from context menu invoke Disconnect 7) select the node again and from context menu invoke Connect... 8) in the connect dialog click OK => the connection fails with message 'Failed to start database test, see the next exception for details'. Another problem is there is no exception with the details anywhere.
Reproducible only on Win platform. Cannot reproduce on Linux and Mac OS X.
Caused by NetBeans using a new class loader each time a database connection is made (the class loaders are used to load the JDBC drivers, since they aren't on the IDE classpath). The attached Java code reproduces the bug (run *without* derby.jar on the classpath, since this would cause the jar to be loaded using the bootstrap class loader). Not sure if this is a bug in Derby or not. A solution to this issue could be to cache the class loader for each connection. But while evaluating this bug I also found out that NetBeans doesn't properly shut down the Derby instance started when making the connection to an embedded database. If a user developing a JDBC app using embedded Derby would connect from NetBeans to the embedded database used by his app, he won't be able to connect to this database from the application until NetBeans is restarted. So a more correct fix would be to shut down Derby each time a connection to an embedded database is closed. Adding Oyvind to CC in case he has any comments.
Created attachment 24676 [details] Code which reproduces the issue outside NetBeans
It's not a Derby bug, it's a feature. I'll try to explain: When Derby is used in embedded mode, the Derby system is initialized the first time the (embedded) JDBC driver is loaded. In embedded mode, we can view the Derby system as a server which is serving only one application - the application it is embedded in. Loading the driver means starting the server. Now, it is completely possible to load the embedded JDBC driver in multiple class loaders, but that means loading multiple instances of the Derby system. This corresponds to starting multiple instances of traditional (non-embeddable) database servers. Now, that is perfectly legal, but for obvious reasons, they cannot share resources - they are individual server instances running on the same machine (and, in the case of Derby, in the same JVM, but they are still separate systems). The problem arises when two connections - through two distinct server instances - try to access the same database. At any time, no more than one server may be responsible for a particular database. Shutting down the database each time a connection is closed is not a good solution, since that would kill all your other open connections to the same database when one of them closes. Also, it will generate a lot of overhead and be much slower. Shutting down the Derby *system* (not just the database) each time a connection is closed will be even worse. Bottom line: In embedded mode, applications must get all connections to a particular database X through the same Derby system, which means: from the same JDBC driver (loaded with the same classloader). The Derby system should be shut down when NetBeans exits. In client/server mode, Derby behaves similar to other DBMSs: You start the server process separately, connect to it through a network protocol, and it does not matter to the server which classloader loaded the client JDBC driver, how many drivers are loaded etc.
Oyvind, thank you for the explanation. It still seems to the that shutting down the database and maybe even the instance would cause no harm. Currently each time a you invoke the Connect action on a connection a new class loader is created for loading the respective driver. For Derby this causes a new instance to be created. The class loader, and therefore the instance, is not shared among connections. Note that this means that you cannot have more than one database connection with the same Derby database URL (since a new connection would access the same database, but from a new Derby instance, which is disallowed by Derby). So it seems that shutting down the Derby instance upon disconnecting a connection is OK, since there would only be one connection using that instance -- the one you are just disconnecting. BTW I think in the future we should cache and reuse the class loaders instead of creating new ones. That would allow multiple connections to the same Derby database, and we should shut down the database (not the instance) when the last connection is disconnected.
What is the reason for using a separate classloader for each connection? Although it works better for traditional client/server databases than for Embedded Derby, it still consumes a lot more memory than necessary, by loading the JDBC driver multiple times. If reusing the classloader is not an option at this time, I agree that shutting down the instance when closing the connection will be an improvement. However, it is not intuitive to the user why the second connection to the database fails. (Especially since the 'next exception' is not shown.)
Re. the separate class loader: there isn't any good reason I can think of, aside from simplicity. But then again, it has never caused any problems (except from more memory usage and a memory leak caused by each driver loaded by a new class loader registering itself to DriverManager). Anyway, I plan to fix this, but it looks like too big a change for it to be made so late in the 5.0 release schedule. Re. the intuitivity: what's worse is that on Linux a user making the second connection won't be noticed of anything and the db could be corrupted (except if we set the derby.database.forceDatabaseLock property). But then we must make really sure we shutdown the Derby instance, which cannot be guaranteed. For example one could kill the NetBeans process or restart the machine and NetBeans wouldn't get a change to shutdown the Derby instance correctly. We must definitely display the next exception in the "Connection failed" dialog, since Derby displays quite a meaningful message when derby.database.forceDatabaseLock is true and a db.lck file exists.
Shouldn't this issue have 'derby' as its subcomponent value?
I guess it should. Reassigning to db/derby.
Fixed. Now shutting down the Derby engine upon disconnect, setting derby.database.forceDatabaseLock=true and displaying the whole chain of SQL exceptions upon connect. Checking in src/org/netbeans/modules/db/explorer/DatabaseConnection.java; /cvs/db/src/org/netbeans/modules/db/explorer/DatabaseConnection.java,v <-- DatabaseConnection.java new revision: 1.43; previous revision: 1.42 done Checking in src/org/netbeans/modules/db/explorer/DbDriverManager.java; /cvs/db/src/org/netbeans/modules/db/explorer/DbDriverManager.java,v <-- DbDriverManager.java new revision: 1.2; previous revision: 1.1 done RCS file: /cvs/db/src/org/netbeans/modules/db/explorer/DerbyConectionEventListener.java,v done Checking in src/org/netbeans/modules/db/explorer/DerbyConectionEventListener.java; /cvs/db/src/org/netbeans/modules/db/explorer/DerbyConectionEventListener.java,v <-- DerbyConectionEventListener.java initial revision: 1.1 done Checking in src/org/netbeans/modules/db/explorer/actions/ConnectAction.java; /cvs/db/src/org/netbeans/modules/db/explorer/actions/ConnectAction.java,v <-- ConnectAction.java new revision: 1.38; previous revision: 1.37 done Checking in src/org/netbeans/modules/db/explorer/infos/ConnectionNodeInfo.java; /cvs/db/src/org/netbeans/modules/db/explorer/infos/ConnectionNodeInfo.java,v <-- ConnectionNodeInfo.java new revision: 1.41; previous revision: 1.40 done Checking in test/unit/src/org/netbeans/modules/db/explorer/DbDriverManagerTest.java; /cvs/db/test/unit/src/org/netbeans/modules/db/explorer/DbDriverManagerTest.java,v <-- DbDriverManagerTest.java new revision: 1.2; previous revision: 1.1 done
VERIFIED