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