Mybatis - 三种SqlSession的区别


记录学习过程笔记

如果本文有任何错误,请批评指教,不胜感激 !

1、DefaultSqlSession

package org.apache.ibatis.session.defaults;

/**
 * 默认实现
 * 不是线程安全
 */
public class DefaultSqlSession implements SqlSession {

}

1. 使用示例

  1. 需要手动关闭
  2. 不是线程安全
public static void main(String[] args) {
	String resource = "mybatis-config.xml";
    // 读取配置文件
    InputStream inputStream = Resources.getResourceAsStream(resource);
    // 构建sqlSessionFactory
   	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
	// 获取sqlSession
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
    	User user = sqlSession.selectOne("com.hhc.UserMapper.selectUser");
    	System.out.println(user);
    } finally {
   		sqlSession.close();
	}
}

2、SqlSessionManager

  1. 动态代理,由代理对象解决 sqlSession关闭问题
  2. ThreadLocal保存sqlSession,解决线程安全问题
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
	// 生成代理对象,解决 session关闭问题
	private final SqlSession sqlSessionProxy;
	
	// ThreadLocal解决线程安全问题
	private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<SqlSession>();
	
	private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
	    this.sqlSessionFactory = sqlSessionFactory;
	    this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
	        SqlSessionFactory.class.getClassLoader(),
	        new Class[]{SqlSession.class},
	        new SqlSessionInterceptor());
	  }

	// 开启本地线程变量管理
	public void startManagedSession() {
    	this.localSqlSession.set(openSession());
  	}

	// 代理处理
	private class SqlSessionInterceptor implements InvocationHandler {
	
		@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			final SqlSession sqlSession = SqlSessionManager.this.localSqlSession.get();
      		if (sqlSession != null) {
      		}else {
				final SqlSession autoSqlSession = openSession();
				try{}catch (Throwable t) {}
				finally {
          			autoSqlSession.close();
        		}
			}
		}
}

1. 使用示例

public static void main(String[] args) {
	String resource = "mybatis-config.xml";
    // 读取配置文件
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionManager sqlSessionManager =SqlSessionManager.newInstance(inputStream);
   
    // 可选:绑定Session到线程本地变量
    sqlSessionManager.startManagedSession();
    
    User user = sqlSessionManager.selectOne("com.hhc.UserMapper.selectUser");
    System.out.println(user);
}

3、SqlSessionTemplate

  1. 是Mybatis与Spring 整合时使用的线程安全sqlsession
  2. 动态代理,由代理对象解决 sqlSession关闭问题
  3. TransactionSynchronizationManager使用ThreadLocal保存sqlSession,解决线程安全问题
public class SqlSessionTemplate implements SqlSession, DisposableBean {

	// 生成代理对象,解决 session关闭问题
	private final SqlSession sqlSessionProxy;
	
	public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {

	    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
	    notNull(executorType, "Property 'executorType' is required");
	
	    this.sqlSessionFactory = sqlSessionFactory;
	    this.executorType = executorType;
	    this.exceptionTranslator = exceptionTranslator;
	    this.sqlSessionProxy = (SqlSession) newProxyInstance(
	        SqlSessionFactory.class.getClassLoader(),
	        new Class[] { SqlSession.class },
	        new SqlSessionInterceptor());
		
		try{
			// 执行sql
		}catch (Throwable t) {
			// 关闭SqlSession
			closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
		}finally {
			if (sqlSession != null) {
          		closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
        	}
		}
  	}
  
  	private class SqlSessionInterceptor implements InvocationHandler {
		@Override
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		// SqlSessionUtils.getSqlSession
			SqlSession sqlSession = getSqlSession(
          		SqlSessionTemplate.this.sqlSessionFactory,
          		SqlSessionTemplate.this.executorType,
          		SqlSessionTemplate.this.exceptionTranslator);
		}
	}
}

SqlSessionUtils

  1. 尝试从TransactionSynchronizationManager事务同步器获取sqlsesion
  2. 如果获取不到,则从sqlSessionFactory工厂获取,再注册绑定到TransactionSynchronizationManager事务同步器
  3. session 如果是由TransactionSynchronizationManager管理的,则只会更新引用计数器,让Spring在托管事务结束时调用close回调,关闭session。
  4. session不是由TransactionSynchronizationManager 管理的,则直接关闭session
package org.mybatis.spring;

public final class SqlSessionUtils {
	public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
		SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);

	    SqlSession session = sessionHolder(executorType, holder);
	    if (session != null) {
	      return session;
	    }
	
	    if (LOGGER.isDebugEnabled()) {
	      LOGGER.debug("Creating a new SqlSession");
	    }
	
	    session = sessionFactory.openSession(executorType);
	
	    registerSessionHolder(sessionFactory, executorType, exceptionTranslator, session);
	
	    return session;
	}

	// 关闭session
	public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {
	    notNull(session, NO_SQL_SESSION_SPECIFIED);
	    notNull(sessionFactory, NO_SQL_SESSION_FACTORY_SPECIFIED);
		
		// 是否由TransactionSynchronizationManager管理
	    SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
	    if ((holder != null) && (holder.getSqlSession() == session)) {
	      if (LOGGER.isDebugEnabled()) {
	        LOGGER.debug("Releasing transactional SqlSession [" + session + "]");
	      }
	      // 计数-1
	      holder.released();
	    } else {
	      if (LOGGER.isDebugEnabled()) {
	        LOGGER.debug("Closing non transactional SqlSession [" + session + "]");
	      }
	      // 关闭session
	      session.close();
	    }
  }
}

记录学习过程笔记

如果本文有任何错误,请批评指教,不胜感激 !

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值