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

相关文章
相关标签/搜索