View Javadoc
1   /*
2    *    Copyright 2009-2022 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    *       http://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(
45          SqlSessionFactory.class.getClassLoader(),
46          new Class[]{SqlSession.class},
47          new SqlSessionInterceptor());
48    }
49  
50    public static SqlSessionManager newInstance(Reader reader) {
51      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
52    }
53  
54    public static SqlSessionManager newInstance(Reader reader, String environment) {
55      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
56    }
57  
58    public static SqlSessionManager newInstance(Reader reader, Properties properties) {
59      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, properties));
60    }
61  
62    public static SqlSessionManager newInstance(InputStream inputStream) {
63      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, null));
64    }
65  
66    public static SqlSessionManager newInstance(InputStream inputStream, String environment) {
67      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, environment, null));
68    }
69  
70    public static SqlSessionManager newInstance(InputStream inputStream, Properties properties) {
71      return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, properties));
72    }
73  
74    public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
75      return new SqlSessionManager(sqlSessionFactory);
76    }
77  
78    public void startManagedSession() {
79      this.localSqlSession.set(openSession());
80    }
81  
82    public void startManagedSession(boolean autoCommit) {
83      this.localSqlSession.set(openSession(autoCommit));
84    }
85  
86    public void startManagedSession(Connection connection) {
87      this.localSqlSession.set(openSession(connection));
88    }
89  
90    public void startManagedSession(TransactionIsolationLevel level) {
91      this.localSqlSession.set(openSession(level));
92    }
93  
94    public void startManagedSession(ExecutorType execType) {
95      this.localSqlSession.set(openSession(execType));
96    }
97  
98    public void startManagedSession(ExecutorType execType, boolean autoCommit) {
99      this.localSqlSession.set(openSession(execType, autoCommit));
100   }
101 
102   public void startManagedSession(ExecutorType execType, TransactionIsolationLevel level) {
103     this.localSqlSession.set(openSession(execType, level));
104   }
105 
106   public void startManagedSession(ExecutorType execType, Connection connection) {
107     this.localSqlSession.set(openSession(execType, connection));
108   }
109 
110   public boolean isManagedSessionStarted() {
111     return this.localSqlSession.get() != null;
112   }
113 
114   @Override
115   public SqlSession openSession() {
116     return sqlSessionFactory.openSession();
117   }
118 
119   @Override
120   public SqlSession openSession(boolean autoCommit) {
121     return sqlSessionFactory.openSession(autoCommit);
122   }
123 
124   @Override
125   public SqlSession openSession(Connection connection) {
126     return sqlSessionFactory.openSession(connection);
127   }
128 
129   @Override
130   public SqlSession openSession(TransactionIsolationLevel level) {
131     return sqlSessionFactory.openSession(level);
132   }
133 
134   @Override
135   public SqlSession openSession(ExecutorType execType) {
136     return sqlSessionFactory.openSession(execType);
137   }
138 
139   @Override
140   public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
141     return sqlSessionFactory.openSession(execType, autoCommit);
142   }
143 
144   @Override
145   public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
146     return sqlSessionFactory.openSession(execType, level);
147   }
148 
149   @Override
150   public SqlSession openSession(ExecutorType execType, Connection connection) {
151     return sqlSessionFactory.openSession(execType, connection);
152   }
153 
154   @Override
155   public Configuration getConfiguration() {
156     return sqlSessionFactory.getConfiguration();
157   }
158 
159   @Override
160   public <T> T selectOne(String statement) {
161     return sqlSessionProxy.selectOne(statement);
162   }
163 
164   @Override
165   public <T> T selectOne(String statement, Object parameter) {
166     return sqlSessionProxy.selectOne(statement, parameter);
167   }
168 
169   @Override
170   public <K, V> Map<K, V> selectMap(String statement, String mapKey) {
171     return sqlSessionProxy.selectMap(statement, mapKey);
172   }
173 
174   @Override
175   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey) {
176     return sqlSessionProxy.selectMap(statement, parameter, mapKey);
177   }
178 
179   @Override
180   public <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds) {
181     return sqlSessionProxy.selectMap(statement, parameter, mapKey, rowBounds);
182   }
183 
184   @Override
185   public <T> Cursor<T> selectCursor(String statement) {
186     return sqlSessionProxy.selectCursor(statement);
187   }
188 
189   @Override
190   public <T> Cursor<T> selectCursor(String statement, Object parameter) {
191     return sqlSessionProxy.selectCursor(statement, parameter);
192   }
193 
194   @Override
195   public <T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds) {
196     return sqlSessionProxy.selectCursor(statement, parameter, rowBounds);
197   }
198 
199   @Override
200   public <E> List<E> selectList(String statement) {
201     return sqlSessionProxy.selectList(statement);
202   }
203 
204   @Override
205   public <E> List<E> selectList(String statement, Object parameter) {
206     return sqlSessionProxy.selectList(statement, parameter);
207   }
208 
209   @Override
210   public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
211     return sqlSessionProxy.selectList(statement, parameter, rowBounds);
212   }
213 
214   @Override
215   public void select(String statement, ResultHandler handler) {
216     sqlSessionProxy.select(statement, handler);
217   }
218 
219   @Override
220   public void select(String statement, Object parameter, ResultHandler handler) {
221     sqlSessionProxy.select(statement, parameter, handler);
222   }
223 
224   @Override
225   public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
226     sqlSessionProxy.select(statement, parameter, rowBounds, handler);
227   }
228 
229   @Override
230   public int insert(String statement) {
231     return sqlSessionProxy.insert(statement);
232   }
233 
234   @Override
235   public int insert(String statement, Object parameter) {
236     return sqlSessionProxy.insert(statement, parameter);
237   }
238 
239   @Override
240   public int update(String statement) {
241     return sqlSessionProxy.update(statement);
242   }
243 
244   @Override
245   public int update(String statement, Object parameter) {
246     return sqlSessionProxy.update(statement, parameter);
247   }
248 
249   @Override
250   public int delete(String statement) {
251     return sqlSessionProxy.delete(statement);
252   }
253 
254   @Override
255   public int delete(String statement, Object parameter) {
256     return sqlSessionProxy.delete(statement, parameter);
257   }
258 
259   @Override
260   public <T> T getMapper(Class<T> type) {
261     return getConfiguration().getMapper(type, this);
262   }
263 
264   @Override
265   public Connection getConnection() {
266     final SqlSession sqlSession = localSqlSession.get();
267     if (sqlSession == null) {
268       throw new SqlSessionException("Error:  Cannot get connection.  No managed session is started.");
269     }
270     return sqlSession.getConnection();
271   }
272 
273   @Override
274   public void clearCache() {
275     final SqlSession sqlSession = localSqlSession.get();
276     if (sqlSession == null) {
277       throw new SqlSessionException("Error:  Cannot clear the cache.  No managed session is started.");
278     }
279     sqlSession.clearCache();
280   }
281 
282   @Override
283   public void commit() {
284     final SqlSession sqlSession = localSqlSession.get();
285     if (sqlSession == null) {
286       throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
287     }
288     sqlSession.commit();
289   }
290 
291   @Override
292   public void commit(boolean force) {
293     final SqlSession sqlSession = localSqlSession.get();
294     if (sqlSession == null) {
295       throw new SqlSessionException("Error:  Cannot commit.  No managed session is started.");
296     }
297     sqlSession.commit(force);
298   }
299 
300   @Override
301   public void rollback() {
302     final SqlSession sqlSession = localSqlSession.get();
303     if (sqlSession == null) {
304       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
305     }
306     sqlSession.rollback();
307   }
308 
309   @Override
310   public void rollback(boolean force) {
311     final SqlSession sqlSession = localSqlSession.get();
312     if (sqlSession == null) {
313       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
314     }
315     sqlSession.rollback(force);
316   }
317 
318   @Override
319   public List<BatchResult> flushStatements() {
320     final SqlSession sqlSession = localSqlSession.get();
321     if (sqlSession == null) {
322       throw new SqlSessionException("Error:  Cannot rollback.  No managed session is started.");
323     }
324     return sqlSession.flushStatements();
325   }
326 
327   @Override
328   public void close() {
329     final SqlSession sqlSession = localSqlSession.get();
330     if (sqlSession == null) {
331       throw new SqlSessionException("Error:  Cannot close.  No managed session is started.");
332     }
333     try {
334       sqlSession.close();
335     } finally {
336       localSqlSession.remove();
337     }
338   }
339 
340   private class SqlSessionInterceptor implements InvocationHandler {
341     public SqlSessionInterceptor() {
342         // Prevent Synthetic Access
343     }
344 
345     @Override
346     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
347       final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
348       if (sqlSession != null) {
349         try {
350           return method.invoke(sqlSession, args);
351         } catch (Throwable t) {
352           throw ExceptionUtil.unwrapThrowable(t);
353         }
354       } else {
355         try (SqlSession autoSqlSession = openSession()) {
356           try {
357             final Object result = method.invoke(autoSqlSession, args);
358             autoSqlSession.commit();
359             return result;
360           } catch (Throwable t) {
361             autoSqlSession.rollback();
362             throw ExceptionUtil.unwrapThrowable(t);
363           }
364         }
365       }
366     }
367   }
368 
369 }