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 * A {@link java.lang.UnsupportedOperationException} will be thrown on invoking any of the following:
63 * <ul>
64 * <li>{@link java.sql.Connection#setAutoCommit(boolean)}</li>
65 * <li>{@link java.sql.Connection#commit()}</li>
66 * <li>{@link java.sql.Connection#close()}</li>
67 * <li>{@link java.sql.Connection#rollback()}</li>
68 * <li>{@link java.sql.Connection#setReadOnly(boolean)}</li>
69 * <li>{@link java.sql.Connection#setReadOnly(boolean)}</li>
70 * <li>{@link java.sql.Connection#abort(java.util.concurrent.Executor)}</li>
71 * <li>{@link java.sql.Connection#setCatalog(String)}</li>
72 * <li>{@link java.sql.Connection#setSchema(String)}</li>
73 * <li>{@link java.sql.Connection#setTransactionIsolation(int)}</li>
74 * <li>{@link java.sql.Connection#setNetworkTimeout(java.util.concurrent.Executor, int)}</li>
75 * </ul>
76 *
77 * @param callback mandatory, may return {@link java.lang.Void}
78 * @return return value of <code>callback</code>
79 */
80 <A> A execute(@Nonnull ConnectionCallback<A> callback);
81
82 /**
83 * Alter this executor so that the connection is read-only
84 *
85 * @return this executor
86 */
87 @Nonnull
88 TransactionalExecutor readOnly();
89
90 /**
91 * Alter this executor so that the connection is read-write
92 *
93 * @return this executor
94 */
95 @Nonnull
96 TransactionalExecutor readWrite();
97
98 /**
99 * Alter this executor so that it executes in a new transaction, regardless of any existing
100 *
101 * @return this executor
102 */
103 @Nonnull
104 TransactionalExecutor newTransaction();
105
106 /**
107 * Alter this executor so that the connection executes within an existing transaction or creates a new one if one is
108 * not present
109 *
110 * @return this executor
111 */
112 @Nonnull
113 TransactionalExecutor existingTransaction();
114 }