users@glassfish.java.net

XADataSource, no JTA transaction started, but data gets committed - is this

From: <forums_at_java.net>
Date: Tue, 19 Feb 2013 03:26:12 -0600 (CST)

Hi. I configured a (standalone) Derby XADataSource for use in my application.
The application consists of the following servlet code: @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) { // throw new
ServletException(e2); // } throw new ServletException(e); } finally { if
(conn != null) { try { conn.close(); } catch (SQLException e) { throw new
ServletException(e); } } } } } This code is buggy. The UserTransaction is
never actually used, so Derby uses a local transaction (as allowed by the JTA
specification), and should fail during close() because there is an active
transaction running - that's how it behaves when used standalone. Here, the
close() method belongs to com.sun.gjc.spi.jdbc40.ConnectionWrapper40, and
during releasing the pooled connection, deep in the code, it does this (in
com.sun.gjc.spi.ManagedConnection.java): private void resetAutoCommit()
throws ResourceException { if (defaultAutoCommitValue !=
getLastAutoCommitValue() && !(isTransactionInProgress())) { try {
actualConnection.setAutoCommit(defaultAutoCommitValue); } catch (SQLException
sqle) { String i18nMsg = localStrings.getString(
"jdbc.error_during_setAutoCommit"); throw new ResourceException(i18nMsg +
sqle.getMessage(), sqle); } setLastAutoCommitValue(defaultAutoCommitValue); }
} For some reason, isTransactionInProgress() returns false (I guess this
relates to the global transaction status) and the autoCommit status is set,
which causes the transaction to commit implicitly, as per the jdbc
specification. I think this is weird and confusing - I spend quite some time
debugging what is going wrong here, why are things committed when I expect
things to fail. Is this the expected behavior? I would expect an exception of
some kind. Could anybody of the GlassFish team maybe shed some light? Maybe
this is correct the way it is?

--
[Message sent by forum member 'wujek.srujek']
View Post: http://forums.java.net/node/894818