Ok, so I was wrong all along. There seems not to be any explicit method to start a local transaction in jdbc, it is implicit when a previous transaction is committed (in JTA, though, I need to start it myself if I manage the tx boundaries myself, and that perplexed me ;d). When I change the autoCommit setting, the current transaction is committed, and a new is started. Also, in my code, I ignored the SQLException when connection.close() was called (it's not production code, just some testing, but still a bad thing to do), and derby does throw a meaningful exception there (saying that the transaction is still active), which is very nice.
One more question, though: the uncommitted insert comes up in the subsequent select - is this data coming from the server, from the active tx, or does the jdbc driver cache the data somehow?