zoukankan      html  css  js  c++  java
  • MyBatis 自动关闭 session

    在某些小项目中,需要单独使用到 mybatis,但是网上常见工具类方法获取的 session 通常要么需要手动关闭,这样即麻烦,而且有时又容易出错,要么要需要结合使用spring,但是我们只想写个简单的增删改,不想引入太多框架。

    而下面将要介绍的SqlSessionManager所获取的session以及mapper就无需关心连接关闭的事情了。

    环境搭建

    数据库与实体类:

    工具类:

    public class MybatisUtils {
    	
    	private static SqlSessionManager sessionManager = null;
    
    	static {
    		try {
    			InputStream inputStream = MybatisUtils.class.getClassLoader()
                                                     .getResourceAsStream("mybatis-config1.xml");
    			sessionManager = SqlSessionManager.newInstance(inputStream);
    		} catch (Exception e) {
    			throw new RuntimeException("the Configuration of Mybatis is not exist!");
    		}
    	}
    	
    	/**
    	 * 获取 Mapper
    	 * @param <T>
    	 * @param clazz
    	 * @return
    	 */
    	public static <T> T getMapper(Class<T> clazz) {
    		return sessionManager.getMapper(clazz);
    	}
    	
    	/**
    	 * 获取 SqlSessionManager 
    	 * @return  
    	 */
    	public static SqlSessionManager getSessionManager() {
    		return sessionManager;
    	}
    }
    

    mapper:

    public interface AccountMapper {
    
    	@Select("select * from account")
    	public List<Account> selectAccountList();
    	
    	@Select("select * from account where id = #{id}")
    	public Account selectAccountById(Long id);
    	
    	@Update("update account set money = #{money} where id = #{userId}")
    	public void updateAccount(Account account);
    }
    

    原理

    它的原理就是使用了JDK的动态代理,先看看SqlSessionManager的构造方法

    public class SqlSessionManager implements SqlSessionFactory, SqlSession {
    
      private final SqlSessionFactory sqlSessionFactory;
      private final SqlSession sqlSessionProxy;
    
      private final ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<>();
    
      private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
        this.sqlSessionFactory = sqlSessionFactory;
        this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
            SqlSessionFactory.class.getClassLoader(),
            new Class[]{SqlSession.class},
            new SqlSessionInterceptor());
      }
    

    从上面可以看出SqlSessionManager使用了Proxy.newProxyInstance()即JDK动态代理对默认的session进行了增强,增强类为SqlSessionInterceptor

    下面来结合具体的例子来看一下增强方法

    @Test
    public void test1() {
        AccountMapper mapper = MybatisUtils.getMapper(AccountMapper.class);
        List<Account> list = mapper.selectAccountList();
        System.out.println(list);
    }
    

    上面是一个很简单的查询方法,

    然后我们在源码画线处打一个断点

    然后执行

    因为我们并没有设置localSqlSession,所以很显然跳转到了else块中,当然localSqlSession的设置会在后面事务管理中说到。

    然后我们看②处代码,他使用了增强的try语句,可以自动帮我们释放 session。还有③④处代码,会发现SqlSessionManager自动帮我们进行事务的提交与回滚,所以之后我们使用mapper的方法时,可以随意使用,不再关心连接释放的问题了。

    事务管理

    前面说到通过SqlSessionManager获取的mapper进行了增强,在我们使用单一的增删改时就不用再考虑连接释放的问题了,但是有些问题需要执行多个mapper方法,这时就要通过事务来完成了,并且SqlSessionManager也为我们提供了一些事务提交回滚的方法,下面就来看看。

    假设有个简单的业务转账,用户1向用户2转账指定金额,当程序出错时要能回滚,不能一方扣了钱,另一方钱却没有增加。

    这里最关键的就是①处的startManagedSession()方法,我们能发现这里给localSqlSession设置了一个值

    再回到前面的SqlSessionInterceptor类中

    就能发现,当我们调用了startManagedSession()方法后,SqlSessionManager就不会帮助我们进行session的管理,一切连接的关闭,事务的提交与回滚就需要我们自己手动完成了

    小结

    通过SqlSessionManager获取的mapper,使用单一的接口方法操作时,我们可以不用关心连接的释放。

    只有需要多个接口方法组合操作时我们才需要开启session管理,手动来进行连接的释放,与事务提交回滚。

    作者: 贺墨于
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Unix系统编程():分散输入和集中输出(Scatter-Gather IO):readv和writev
    Unix系统编程()在文件特定偏移量处的IO:pread和pwrite
    Unix系统编程()复制文件描述符
    Unix系统编程()文件描述符和打开文件之间的关系
    主存到Cache直接映射、全相联映射和组相联映射
    Unix系统编程()文件控制操作fcntl
    Unix系统编程()原子操作和竞争条件
    Unix系统编程()深入探究文件IO概述
    Unix系统编程()main函数的命令行参数
    Unix系统编程()通用模型以外的操作ioctl
  • 原文地址:https://www.cnblogs.com/hemou/p/14700091.html
Copyright © 2011-2022 走看看