看了下SqlSessionManger類的源碼,記錄一下。 java
先看了一下類定義 sql
public class SqlSessionManager implements SqlSessionFactory, SqlSession
實現了SqlSessionFactory和SqlSession接口。猜測,實例化後能夠直接用的。 session
看類就先看一下構造函數 ide
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) { this.sqlSessionFactory = sqlSessionFactory; this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance( SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionInterceptor()); }
是個private,看來是不能直接new的,發現有一堆的public static SqlSessionManager newInstance方法,查看一下,發現都是new SqlSessionManager,那就是用newInstance獲取實例了。 函數
public static SqlSessionManager newInstance(Reader reader) { return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null)); }
再回過頭來看一下構造函數。 測試
有個this.sqlSessionFactory和this.sqlSessionProxy,看看定義是什麼 fetch
private final SqlSessionFactory sqlSessionFactory; private final SqlSession sqlSessionProxy;
是2個常量引用的SqlSessionFactory和SqlSession。 ui
構造函數就是給這2個成員賦值,第一個很簡單,看看第二個sqlSessionProxy, 搞了個代理,看看實現代碼,發現一個內部類 this
private class SqlSessionInterceptor implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //取線程局部變量 SqlSession final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get(); if (sqlSession != null) { try { //若是不爲空,則直接執行 //用於startManagedSession方法的後續使用 return method.invoke(sqlSession, args); } catch (Throwable t) { throw ExceptionUtil.unwrapThrowable(t); } } else { //直接用於selctOne,update等方法的使用 final SqlSession autoSqlSession = openSession(); try { final Object result = method.invoke(autoSqlSession, args); autoSqlSession.commit(); return result; } catch (Throwable t) { autoSqlSession.rollback(); throw ExceptionUtil.unwrapThrowable(t); } finally { //結束後,自動關閉 autoSqlSession.close(); } } } }
這裏能夠看出來,執行sql的時候有2種狀況,一個是localSqlSession有SqlSession對象的,一個是沒有的,對於第二種狀況sqlsessionfactory會open一個session後,用完了自動close掉。 spa
public SqlSession openSession() { return sqlSessionFactory.openSession(); }
對於第一種狀況,使用下面倆個方法。
public void startManagedSession() { this.localSqlSession.set(openSession()); }
public void close() { final SqlSession sqlSession = localSqlSession.get(); if (sqlSession == null) throw new SqlSessionException("Error: Cannot close. No managed session is started."); try { sqlSession.close(); } finally { localSqlSession.set(null); } }
對於第二種狀況,使用下面的一堆方法
public <T> T selectOne(String statement) { return sqlSessionProxy.<T> selectOne(statement); }
public int update(String statement) { return sqlSessionProxy.update(statement); }
看一下測試用例
public class Run implements Runnable { private static String lock = "lock"; @Override public void run() { for (int i = 0; i < 20; i++) { SqlSession session = OwnerSessionFactory.getSqlSessionTest(); Abc item = session.selectOne("txtpakage.Abc.fetchByNumId", 12342013333L); synchronized (lock) { log.info("***********{}***************",Thread.currentThread().getName()); log.info("index:{}, item:{}", i, item.getTitle()); log.info("********************************"); } } } }
@Test public void testSqlManager() throws InterruptedException { Run run = new Run(); List<Thread> threads = new ArrayList<Thread>(); for (int i = 0; i < 100; i++) { Thread t = new Thread(run); threads.add(t); log.info("thread:{}, start", t.getName()); t.start(); } for (Thread t : threads) { log.info("thread:{},join", t.getName()); t.join(); } log.info("main thread closed"); }
private static SqlSession sqlSession; public static synchronized SqlSession getSqlSessionTest(){ if(sqlSession == null){ Reader reader = getReader(); sqlSession = SqlSessionManager.newInstance(reader); } return sqlSession; }
ok,沒有爆掉,說明正常.