View Javadoc
1   /*
2    *    Copyright 2009-2023 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.session;
17  
18  import java.io.InputStream;
19  import java.io.Reader;
20  import java.lang.reflect.InvocationHandler;
21  import java.lang.reflect.Method;
22  import java.lang.reflect.Proxy;
23  import java.sql.Connection;
24  import java.util.List;
25  import java.util.Map;
26  import java.util.Properties;
27  
28  import org.apache.ibatis.cursor.Cursor;
29  import org.apache.ibatis.executor.BatchResult;
30  import org.apache.ibatis.reflection.ExceptionUtil;
31  
32  /**
33   * @author Larry Meadors
34   */
35  public class SqlSessionManager implements SqlSessionFactory, SqlSession {
36  
37    private final SqlSessionFactory sqlSessionFactory;
38    private final SqlSession sqlSessionProxy;
39  
40    private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
41  
42    private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
43      this.sqlSessionFactory = sqlSessionFactory;
44      this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(),
45          new Class[] { SqlSession.class }, new SqlSessionInterceptor());
46    }
47  
48    public static SqlSessionManager newInstance(Reader reader) {
49      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
50    }
51  
52    public static SqlSessionManager newInstance(Reader reader, String environment) {
53      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
54    }
55  
56    public static SqlSessionManager newInstance(Reader reader, Properties properties) {
57      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, properties));
58    }
59  
60    public static SqlSessionManager newInstance(InputStream inputStream) {
61      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, null));
62    }
63  
64    public static SqlSessionManager newInstance(InputStream inputStream, String environment) {
65      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, environment, null));
66    }
67  
68    public static SqlSessionManager newInstance(InputStream inputStream, Properties properties) {
69      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, properties));
70    }
71  
72    public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
73      return new SqlSessionManager(sqlSessionFactory);
74    }
75  
76    public void startManagedSession() {
77      this.localSqlSession.set(openSession());
78    }
79  
80    public void startManagedSession(boolean autoCommit) {
81      this.localSqlSession.set(openSession(autoCommit));
82    }
83  
84    public void startManagedSession(Connection connection) {
85      this.localSqlSession.set(openSession(connection));
86    }
87  
88    public void startManagedSession(TransactionIsolationLevel level) {
89      this.localSqlSession.set(openSession(level));
90    }
91  
92    public void startManagedSession(ExecutorType execType) {
93      this.localSqlSession.set(openSession(execType));
94    }
95  
96    public void startManagedSession(ExecutorType execType, boolean autoCommit) {
97      this.localSqlSession.set(openSession(execType, autoCommit));
98    }
99  
100   public void startManagedSession(ExecutorType execType, TransactionIsolationLevel level) {
101     this.localSqlSession.set(openSession(execType, level));
102   }
103 
104   public void startManagedSession(ExecutorType execType, Connection connection) {
105     this.localSqlSession.set(openSession(execType, connection));
106   }
107 
108   public boolean isManagedSessionStarted() {
109     return this.localSqlSession.get() != null;
110   }
111 
112   @Override
113   public SqlSession openSession() {
114     return sqlSessionFactory.openSession();
115   }
116 
117   @Override
118   public SqlSession openSession(boolean autoCommit) {
119     return sqlSessionFactory.openSession(autoCommit);
120   }
121 
122   @Override
123   public SqlSession openSession(Connection connection) {
124     return sqlSessionFactory.openSession(connection);
125   }
126 
127   @Override
128   public SqlSession openSession(TransactionIsolationLevel level) {
129     return sqlSessionFactory.openSession(level);
130   }
131 
132   @Override
133   public SqlSession openSession(ExecutorType execType) {
134     return sqlSessionFactory.openSession(execType);
135   }
136 
137   @Override
138   public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
139     return sqlSessionFactory.openSession(execType, autoCommit);
140   }
141 
142   @Override
143   public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
144     return sqlSessionFactory.openSession(execType, level);
145   }
146 
147   @Override
148   public SqlSession openSession(ExecutorType execType, Connection connection) {
149     return sqlSessionFactory.openSession(execType, connection);
150   }
151 
152   @Override
153   public Configuration getConfiguration() {
154     return sqlSessionFactory.getConfiguration();
155   }
156 
157   @Override
158   public <T> T selectOne(String statement) {
159     return sqlSessionProxy.selectOne(statement);
160   }
161 
162   @Override
163   public <T> T selectOne(String statement, Object parameter) {
164     return sqlSessionProxy.selectOne(statement, parameter);
165   }
166 
167   @Override
168   public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
169     return sqlSessionProxy.selectMap(statement, mapKey);
170   }
171 
172   @Override
173   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
174     return sqlSessionProxy.selectMap(statement, parameter, mapKey);
175   }
176 
177   @Override
178   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
179     return sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
180   }
181 
182   @Override
183   public <T> Cursor<T> selectCursor(String statement) {
184     return sqlSessionProxy.selectCursor(statement);
185   }
186 
187   @Override
188   public <T> Cursor<T> selectCursor(String statement, Object parameter) {
189     return sqlSessionProxy.selectCursor(statement, parameter);
190   }
191 
192   @Override
193   public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
194     return sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
195   }
196 
197   @Override
198   public <E> List<E> selectList(String statement) {
199     return sqlSessionProxy.selectList(statement);
200   }
201 
202   @Override
203   public <E> List<E> selectList(String statement, Object parameter) {
204     return sqlSessionProxy.selectList(statement, parameter);
205   }
206 
207   @Override
208   public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
209     return sqlSessionProxy.selectList(statement, parameter, rowBounds);
210   }
211 
212   @Override
213   public void select(String statement, ResultHandler handler) {
214     sqlSessionProxy.select(statement, handler);
215   }
216 
217   @Override
218   public void select(String statement, Object parameter, ResultHandler handler) {
219     sqlSessionProxy.select(statement, parameter, handler);
220   }
221 
222   @Override
223   public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
224     sqlSessionProxy.select(statement, parameter, rowBounds, handler);
225   }
226 
227   @Override
228   public int insert(String statement) {
229     return sqlSessionProxy.insert(statement);
230   }
231 
232   @Override
233   public int insert(String statement, Object parameter) {
234     return sqlSessionProxy.insert(statement, parameter);
235   }
236 
237   @Override
238   public int update(String statement) {
239     return sqlSessionProxy.update(statement);
240   }
241 
242   @Override
243   public int update(String statement, Object parameter) {
244     return sqlSessionProxy.update(statement, parameter);
245   }
246 
247   @Override
248   public int delete(String statement) {
249     return sqlSessionProxy.delete(statement);
250   }
251 
252   @Override
253   public int delete(String statement, Object parameter) {
254     return sqlSessionProxy.delete(statement, parameter);
255   }
256 
257   @Override
258   public <T> T getMapper(Class<T> type) {
259     return getConfiguration().getMapper(type, this);
260   }
261 
262   @Override
263   public Connection getConnection() {
264     final SqlSession sqlSession = localSqlSession.get();
265     if (sqlSession == null) {
266       throw new SqlSessionException("Error:  Cannot get connection.  No managed session is started.");
267     }
268     return sqlSession.getConnection();
269   }
270 
271   @Override
272   public void clearCache() {
273     final SqlSession sqlSession = localSqlSession.get();
274     if (sqlSession == null) {
275       throw new SqlSessionException("Error:  Cannot clear the cache.  No managed session is started.");
276     }
277     sqlSession.clearCache();
278   }
279 
280   @Override
281   public void commit() {
282     final SqlSession sqlSession = localSqlSession.get();
283     if (sqlSession == null) {
284       throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
285     }
286     sqlSession.commit();
287   }
288 
289   @Override
290   public void commit(boolean force) {
291     final SqlSession sqlSession = localSqlSession.get();
292     if (sqlSession == null) {
293       throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
294     }
295     sqlSession.commit(force);
296   }
297 
298   @Override
299   public void rollback() {
300     final SqlSession sqlSession = localSqlSession.get();
301     if (sqlSession == null) {
302       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
303     }
304     sqlSession.rollback();
305   }
306 
307   @Override
308   public void rollback(boolean force) {
309     final SqlSession sqlSession = localSqlSession.get();
310     if (sqlSession == null) {
311       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
312     }
313     sqlSession.rollback(force);
314   }
315 
316   @Override
317   public List<BatchResult> flushStatements() {
318     final SqlSession sqlSession = localSqlSession.get();
319     if (sqlSession == null) {
320       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
321     }
322     return sqlSession.flushStatements();
323   }
324 
325   @Override
326   public void close() {
327     final SqlSession sqlSession = localSqlSession.get();
328     if (sqlSession == null) {
329       throw new SqlSessionException("Error:  Cannot close.  No managed session is started.");
330     }
331     try {
332       sqlSession.close();
333     } finally {
334       localSqlSession.remove();
335     }
336   }
337 
338   private class SqlSessionInterceptor implements InvocationHandler {
339     public SqlSessionInterceptor() {
340       // Prevent Synthetic Access
341     }
342 
343     @Override
344     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
345       final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
346       if (sqlSession != null) {
347         try {
348           return method.invoke(sqlSession, args);
349         } catch (Throwable t) {
350           throw ExceptionUtil.unwrapThrowable(t);
351         }
352       }
353       try (SqlSession autoSqlSession = openSession()) {
354         try {
355           final Object result = method.invoke(autoSqlSession, args);
356           autoSqlSession.commit();
357           return result;
358         } catch (Throwable t) {
359           autoSqlSession.rollback();
360           throw ExceptionUtil.unwrapThrowable(t);
361         }
362       }
363     }
364   }
365 
366 }