View Javadoc

1   package com.atlassian.sal.api.rdbms;
2   
3   import com.atlassian.annotations.PublicApi;
4   
5   import javax.annotation.Nonnull;
6   
7   /**
8    * Interface allowing the user to execute a callback with a {@link java.sql.Connection}, in the context of a transaction.
9    * <p/>
10   * Note that participation in an existing transaction i.e. <code>requiresNew</code> not set is merely a hint to the
11   * host application and not binding. Best effort will be attempted.
12   * <p/>
13   * The following example will query an application's table using JDBC:
14   * <pre>
15   * {@code
16   * final TransactionalExecutor transactionalExecutor = transactionalExecutorFactory
17   *         .createExecutor()
18   *         .readOnly()
19   *         .newTransaction();
20   *
21   * final String summary = transactionalExecutor.execute(new ConnectionCallback<String>()
22   * {
23   *     public String execute(final Connection connection)
24   *     {
25   *         try
26   *         {
27   *             final PreparedStatement preparedStatement = connection.prepareStatement(""
28   *                     + "select summary\n"
29   *                     + "from jiraissue\n"
30   *                     + "order by id desc");
31   *
32   *             final ResultSet resultSet = preparedStatement.executeQuery();
33   *
34   *             return resultSet.next() ? resultSet.getString("summary") : "no issues";
35   *         }
36   *         catch (SQLException e)
37   *         {
38   *             throw new RuntimeException("oh noes!", e);
39   *         }
40   *     }
41   * });
42   * }
43   * </pre>
44   *
45   * @see com.atlassian.sal.api.rdbms.TransactionalExecutorFactory
46   * @since 3.0
47   */
48  @PublicApi
49  public interface TransactionalExecutor {
50      /**
51       * Execute a callback which is supplied a {@link java.sql.Connection}, within a transaction.
52       * <p/>
53       * After successful execution, the transaction will be committed. If the transaction is within the scope of a larger
54       * transaction i.e. <code>requiresNew</code> has been set, it will be scheduled for commit, pending successful
55       * completion of the target transaction.
56       * <p/>
57       * If any exception is thrown by <code>callback</code>, the transaction will be immediately rolled back.
58       * <p/>
59       * Do not attempt to retain or reuse the Connection outside of the scope of <code>callback</code> or within a
60       * different thread. Connection is usually not considered thread safe.
61       * <p/>
62       * Exceptions thrown from the callback are passed through without wrapping.
63       * {@link java.sql.SQLException} occuring in the Executor will be wrapped in {@link com.atlassian.sal.api.rdbms.RdbmsException}.
64       * <p/>
65       * A {@link java.lang.UnsupportedOperationException} will be thrown on invoking any of the following:
66       * <ul>
67       * <li>{@link java.sql.Connection#setAutoCommit(boolean)}</li>
68       * <li>{@link java.sql.Connection#commit()}</li>
69       * <li>{@link java.sql.Connection#close()}</li>
70       * <li>{@link java.sql.Connection#rollback()}</li>
71       * <li>{@link java.sql.Connection#setReadOnly(boolean)}</li>
72       * <li>{@link java.sql.Connection#setReadOnly(boolean)}</li>
73       * <li>{@link java.sql.Connection#abort(java.util.concurrent.Executor)}</li>
74       * <li>{@link java.sql.Connection#setCatalog(String)}</li>
75       * <li>{@link java.sql.Connection#setSchema(String)}</li>
76       * <li>{@link java.sql.Connection#setTransactionIsolation(int)}</li>
77       * <li>{@link java.sql.Connection#setNetworkTimeout(java.util.concurrent.Executor, int)}</li>
78       * </ul>
79       *
80       * @param callback mandatory, may return {@link java.lang.Void}
81       * @return return value of <code>callback</code>
82       */
83      <A> A execute(@Nonnull ConnectionCallback<A> callback);
84  
85      /**
86       * Alter this executor so that the connection is read-only
87       *
88       * @return this executor
89       */
90      @Nonnull
91      TransactionalExecutor readOnly();
92  
93      /**
94       * Alter this executor so that the connection is read-write
95       *
96       * @return this executor
97       */
98      @Nonnull
99      TransactionalExecutor readWrite();
100 
101     /**
102      * Alter this executor so that it executes in a new transaction, regardless of any existing
103      *
104      * @return this executor
105      */
106     @Nonnull
107     TransactionalExecutor newTransaction();
108 
109     /**
110      * Alter this executor so that the connection executes within an existing transaction or creates a new one if one is
111      * not present
112      *
113      * @return this executor
114      */
115     @Nonnull
116     TransactionalExecutor existingTransaction();
117 }