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 }