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
