1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.skife.jdbi.v2.tweak.transactions;
18
19 import org.skife.jdbi.v2.Handle;
20 import org.skife.jdbi.v2.exceptions.TransactionException;
21 import org.skife.jdbi.v2.tweak.TransactionHandler;
22
23 import java.sql.Connection;
24 import java.sql.SQLException;
25 import java.sql.Savepoint;
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.concurrent.ConcurrentHashMap;
29
30
31
32
33
34
35 public class LocalTransactionHandler implements TransactionHandler
36 {
37 private ConcurrentHashMap<Handle, LocalStuff> localStuff = new ConcurrentHashMap<Handle, LocalStuff>();
38
39
40
41
42 public void begin(Handle handle)
43 {
44 try {
45 boolean initial = handle.getConnection().getAutoCommit();
46 localStuff.put(handle, new LocalStuff(initial));
47 handle.getConnection().setAutoCommit(false);
48 }
49 catch (SQLException e) {
50 throw new TransactionException("Failed to start transaction", e);
51 }
52 }
53
54
55
56
57 public void commit(Handle handle)
58 {
59 try {
60 handle.getConnection().commit();
61 final LocalStuff stuff = localStuff.remove(handle);
62 if (stuff != null) {
63 handle.getConnection().setAutoCommit(stuff.getInitialAutocommit());
64 stuff.getCheckpoints().clear();
65 }
66 }
67 catch (SQLException e) {
68 throw new TransactionException("Failed to commit transaction", e);
69 }
70 finally {
71
72 if (localStuff.containsKey(handle)) {
73 localStuff.remove(handle);
74 }
75 }
76 }
77
78
79
80
81 public void rollback(Handle handle)
82 {
83 try {
84 handle.getConnection().rollback();
85 final LocalStuff stuff = localStuff.remove(handle);
86 if (stuff != null) {
87 handle.getConnection().setAutoCommit(stuff.getInitialAutocommit());
88 stuff.getCheckpoints().clear();
89 }
90 }
91 catch (SQLException e) {
92 throw new TransactionException("Failed to rollback transaction", e);
93 }
94 finally {
95
96 if (localStuff.containsKey(handle)) {
97 localStuff.remove(handle);
98 }
99 }
100 }
101
102
103
104
105
106
107
108 public void checkpoint(Handle handle, String name)
109 {
110 final Connection conn = handle.getConnection();
111 try {
112 final Savepoint savepoint = conn.setSavepoint(name);
113 localStuff.get(handle).getCheckpoints().put(name, savepoint);
114 }
115 catch (SQLException e) {
116 throw new TransactionException(String.format("Unable to create checkpoint %s", name), e);
117 }
118 }
119
120 public void release(Handle handle, String name)
121 {
122 final Connection conn = handle.getConnection();
123 try {
124 final Savepoint savepoint = localStuff.get(handle).getCheckpoints().remove(name);
125 if (savepoint == null) {
126 throw new TransactionException(String.format("Attempt to rollback to non-existant savepoint, '%s'",
127 name));
128 }
129 conn.releaseSavepoint(savepoint);
130 }
131 catch (SQLException e) {
132 throw new TransactionException(String.format("Unable to create checkpoint %s", name), e);
133 }
134 }
135
136
137
138
139
140
141
142 public void rollback(Handle handle, String name)
143 {
144 final Connection conn = handle.getConnection();
145 try {
146 final Savepoint savepoint = localStuff.get(handle).getCheckpoints().remove(name);
147 if (savepoint == null) {
148 throw new TransactionException(String.format("Attempt to rollback to non-existant savepoint, '%s'",
149 name));
150 }
151 conn.rollback(savepoint);
152 }
153 catch (SQLException e) {
154 throw new TransactionException(String.format("Unable to create checkpoint %s", name), e);
155 }
156 }
157
158
159
160
161 public boolean isInTransaction(Handle handle)
162 {
163 try {
164 return !handle.getConnection().getAutoCommit();
165 }
166 catch (SQLException e) {
167 throw new TransactionException("Failed to test for transaction status", e);
168 }
169 }
170
171 private static class LocalStuff
172 {
173 private final Map<String, Savepoint> checkpoints = new HashMap<String, Savepoint>();
174 private final boolean initialAutocommit;
175
176 public LocalStuff(boolean initial)
177 {
178 this.initialAutocommit = initial;
179 }
180
181 public Map<String, Savepoint> getCheckpoints()
182 {
183 return checkpoints;
184 }
185
186 public boolean getInitialAutocommit()
187 {
188 return initialAutocommit;
189 }
190 }
191 }