Mybatis SqlSessionManager

看了下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,沒有爆掉,說明正常.

相關文章
相關標籤/搜索