Hi. I am using a standalone Derby server that comes with my JDK (the following is invoked in $JDK_HOME/db/bin):
$ ./sysinfo ------------------ Java Information ------------------ Java Version: 1.7.0_07 Java Vendor: Oracle Corporation Java home: /usr/lib/jvm/jdk1.7.0_07/jre Java classpath: /usr/lib/jvm/java/db/lib/derby.jar:/usr/lib/jvm/java/db/lib/derbynet.jar:/usr/lib/jvm/java/db/lib/derbytools.jar:/usr/lib/jvm/java/db/lib/derbyclient.jar OS name: Linux OS architecture: amd64 OS version: 3.0.0-31-generic Java user name: wujek Java user home: /home/wujek Java user dir: /usr/lib/jvm/jdk1.7.0_07/db/bin java.specification.name: Java Platform API Specification java.specification.version: 1.7 java.runtime.version: 1.7.0_07-b10 --------- Derby Information -------- JRE - JDBC: Java SE 7 - JDBC 4.0 [/usr/lib/jvm/jdk1.7.0_07/db/lib/derby.jar] 10.8.2.2 - (1181258) [/usr/lib/jvm/jdk1.7.0_07/db/lib/derbytools.jar] 10.8.2.2 - (1181258) [/usr/lib/jvm/jdk1.7.0_07/db/lib/derbynet.jar] 10.8.2.2 - (1181258) [/usr/lib/jvm/jdk1.7.0_07/db/lib/derbyclient.jar] 10.8.2.2 - (1181258) The data source configuration is in the attached domain.xml file, but just for reference: <jdbc-connection-pool is-isolation-level-guaranteed="false" datasource-classname="org.apache.derby.jdbc.ClientXADataSource40" res-type="javax.sql.XADataSource" name="DerbyTestXAPool"> <property name="databaseName" value="hibertest" /> <property name="password" value="hibertest" /> <property name="user" value="hibertest" /> <property name="serverName" value="localhost" /> </jdbc-connection-pool> <jdbc-resource pool-name="DerbyTestXAPool" description="" jndi-name="jdbc/DerbyTestXAPool" /> (So, I am using an XA data source. The DDL script for this database will be attached.) The whole project consists of a single 3.0 servlet, whose code is below (sans package and imports): @WebServlet(name = "JdbcServlet", value = "/jdbc") public class JdbcServlet extends HttpServlet { @Resource(name = "jdbc/DerbyTestXAPool") private DataSource dataSource; @Resource private UserTransaction utx; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); response.setCharacterEncoding(StandardCharsets.UTF_8.name()); Writer out = response.getWriter(); Connection conn = null; try { // utx.begin(); out.write(utx.getStatus() + "\n"); conn = dataSource.getConnection(); out.write(conn.getAutoCommit() + "\n"); conn.setAutoCommit(false); out.write(conn.getAutoCommit() + "\n"); ResultSet rs = conn.createStatement().executeQuery("select max(id) from person"); rs.next(); long nextid = rs.getLong(1) + 1; out.write(conn.getAutoCommit() + "\n"); PreparedStatement pst = conn.prepareStatement("insert into person(id, first_name, last_name) values(?, ?, ?)"); out.write(conn.getAutoCommit() + "\n"); pst.setLong(1, nextid); pst.setString(2, "fn" + nextid); pst.setString(3, "ln" + nextid); pst.execute(); out.write(conn.getAutoCommit() + "\n"); rs = conn.createStatement().executeQuery("select id, first_name, last_name from person"); while (rs.next()) { long id = rs.getLong("id"); String firstName = rs.getString("first_name"); String lastName = rs.getString("last_name"); out.write(String.format("[%d] %s %s\n", id, firstName, lastName)); } // utx.commit(); out.write(utx.getStatus() + "\n"); } catch (Exception e) { // try { // utx.rollback(); // } catch (SystemException e2) { // ignore // } throw new ServletException(e); } finally { if (conn != null) { try { conn.close(); } catch (SQLException e) { // ignore } } } } } It does this: 1. takes a connection from the data source (which should be an XA connection per configuration) 2. _does not_ start any transaction, prints the status twice (and I get 6, which is Status.STATUS_NO_TRANSACTION) 3. sets autoCommit to false and prints it a few times 4. gets the biggest id in the table (0 when table is empty) 5. creates a new row with a prepared statement 6. prints out all rows 7. _does not_ commit the transaction in any way The output I see is: 6 true false false false false [1] fn1 ln1 6 (the 6 is the mentioned utx status, true is the initial value of autoCommit, and false are the values after setting it to false) What I don't understand: 1. how is it possible that the insertion is visible in the next select? there is no transaction, autoCommit is explicitly set to false, there is no caching like EntityManager cache - or is there? 2. how is it possible that the insertion is made persistent after the code executes, without the transaction ever being committed (either local or global) - I can see in a db viewer that the row has been added? the close() in finally seems to be doing magic things The transaction isolation is READ_COMITTED by default, at least that's what I found, so reading the just-inserted row should not happen. I think the RA for Derby is allowed to start a local transaction when there is no global one (the specs allows this as optional), but there is not a single commit in this code. How come the row gets saved? I am obviously doing things wrong here, making invalid assumptions or just plain don't know how jdbc / jta works. Could someone help me understand what is going on here? wujek
test.tar.gz
Description: GNU Zip compressed data