1、SqlSession 简介
关于SqlSession的作用,官方文档是这样介绍的:
The primary Java interface for working with MyBatis.
Through this interface you can execute commands, get mappers and manage transactions.
翻译为:SqlSession是MyBatis的关键对象,通过这个接口可以操作命令,管理事务等。
需要注意的是:虽然SqlSession提供select/insert/update/delete方法,在旧版本中使用使用SqlSession接口的这些方法,但是新版的Mybatis中就会建议使用Mapper接口的方法。
从 SqlSessionFactory 中获取 SqlSession
既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。例如:
try (SqlSession session = sqlSessionFactory.openSession()) {
Blog blog = (Blog) session.selectOne("org.mybatis.example.BlogMapper.selectBlog", 101);
}
诚然,这种方式能够正常工作,对使用旧版本 MyBatis 的用户来说也比较熟悉。但现在有了一种更简洁的方式——使用和指定语句的参数和返回值相匹配的接口(比如 BlogMapper.class),现在你的代码不仅更清晰,更加类型安全,还不用担心可能出错的字符串字面值以及强制类型转换。
例如:
try (SqlSession session = sqlSessionFactory.openSession()) {
BlogMapper mapper = session.getMapper(BlogMapper.class);
Blog blog = mapper.selectBlog(101);
}
1.1、SqlSession旧版本用法:
Person p = session.selectOne("cn.mybatis.mydemo.mapper.PersonMapper.selectPersonById", 1);
1.2、SqlSession新版本用法(推荐用法):
// 获得mapper接口的代理对象
PersonMapper pm = session.getMapper(PersonMapper.class);
// 直接调用接口的方法,查询id为1的Peson数据
Person p = pm.selectPersonById(1);
2、MyBatis的SqlSession与JDBC的Connection对比
SqlSession对象,该对象中包含了执行SQL语句的所有方法,类似于JDBC里面的Connection。这种“类似”体现在以下几个方面:
(1)在JDBC中,Connection不直接执行SQL方法,而是生成Statement或者PrepareStatement对象,利用Statement或者PrepareStatement来执行增删改查方法。
(2)在MyBatis中,SqlSession可以直接执行增删改查方法,例如:<T> T selectOne(String statement);int insert(String statement, Object parameter);等,也可以获取映射器Mapper:<T> T getMapper(Class<T> type);然后通过映射器来执行增删改查操作。如下代码所示:
// 获得mapper接口的代理对象
PersonMapper pm = session.getMapper(PersonMapper.class);
// 直接调用接口的方法,查询id为1的Peson数据
Person p = pm.selectPersonById(1);
3、SqlSession 线程安全性分析
SqlSession是应用程序与持久存储层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操作的关键对象。
SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法,它的底层封装了JDBC连接,可以用SqlSession实例来直接执行已映射的SQL语句。
SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。
可以考虑使用ThreadLocal来封装SqlSession
4、SqlSession 的常用方法如下:
(1)int insert(String statement)。插入方法,参数statement是在配置文件中定义的<insert.../>元素的id,返回执行SQL语句所影响的行数。
(2)int insert(String statement,Object parameter)。插入方法,参数statement是在配置文件中定义的<insert.../>元素的id,parameter是插入所需的参数,通常是对象或者Map,返回执行SQL语句所影响的行数。
(3)int update(String statement) 。更新方法,参数statement是在配置文件中定义的<update.../>元素的id,返回执行SQL语句所影响的行数。
(4)int update(String statement,Object parameter)。更新方法,参数statement是在配置文件中定义的<update.../>元素的id,parameter是插入所需的参数,通常是对象或者Map,返回执行SQL语句所影响的行数。
(5)int delete(String statement) 。删除方法,参数statement是在配置文件中定义的<delete.../>元素的id。返回执行SQL语句所影响的行数。
(6)int delete(String statement,Object parameter)。删除方法,参数statement 是在配置文件中定义的<delete.../>元素的id,parameter是插入所需的参数,通常是对象或者Map,返回执行SQL语句所影响的行数。
(7)<T> T selectOne(String slatement)。查询方法,参数statement是在配置文件中定义的<select.../>元素的id,返回执行SQL语句查询结果的泛型对象,通常查询结果只有一条数据时才使用。
(8)<T> T selectOne(String statement,Object parameter)。查询方法,参数statement是在配置文件中定义的<select.../>元素的id,parameter是查询所需的参数,通常是对象或者Map,返回执行SQL语句查询结果的泛型对象,通常查询结具只有一条数据时才使用。
(9)<E> List<E> selectList(String statemenl)。查询方法,参数是在配置文件中定义的<select.../>素的id,返回执行SQL话句查询结果的泛型对象的集合。
(10)<E> List<E> selectList(String statement,Object parameter)。查询方法,参数statement是在配置文件中定义的<select../>元素的id,parameter是查询所需的参数,通常是对象或者Map,返回执行SQL语句查询结果的泛型对象的集合。
(11)<E> List<E> selectList(String statement,Object parameter,RowBounds rowBounds)。查询方法,参数statement是在配置文件中定义的<select.../>元素的id,parameter是查询所需的参数,通常是对象或者Map,RowBounds对象用于分页,它的两个属性: offset指查询的当前页数; limit指当前页显示多少条数据。返回执行SQL语句查询结果的泛型对象的集合。
(12)<K,V> Map<K,V> selectMap(String statement,String mapKey) 。查询方法,参数statement是在配置文件中定义的<select.../>元素的id,mapKey是返回数据的其中一个列名,执行SQL语句查询结果将会被封装成一个Map集合返回,key就是参数mapKey传入的列名,value是封装的对象。
(13)<K,V> Map<K,V> selectMap(String statement,0bject parameler,Sting mapKey)。查询方法,参数statement是在配置文件中定义的<select.../>元素的id,parameter是查询所需的参数,通常是对象或者Map,mapKey 是返回数据的其中一个列名,执行SQL语句查询结果将会被封装成一个Map集合返回,key就是参数mapKey传入的列名,value是封装的对象。
(14)<K,V> Map<K,V>selectMap(Sting statement,Object parameter,Sting mapKey,RowBounds rowBounds)。查询方法,参数statement 是在配置文件中定义的<select.../>元素的id,parameter 是否询所需的参数,通常是对象或者Map,mapKey 是返回数据的其中一个列名,RowBounds 对象用于分页。执行SQL 语句查询结果将会被封装成一个Map集合返回,key就是参数mapKey传入的列名,value是封装的对象。
(15)void select(String statement,ResultHandler handler)。查询方法,参数statement是在配置文件中定义的<select../>元素的id,ResultHandler对象用来处理查询返回的复杂结果集,通常用于多表查询。
(16)void select(String statement,Object parameter,ResultHander handler)。查询方法,参数statement是在配置文件中定义的<select../>元素的id,parameter 是查询所需的参数,通常是对象或者Map, ResultHandler对象用来处理查询返回的复杂结果集,通常用于多表查询。
(17)void select(String statement,Object parameter,RowBounds rowBounds,ResultHandr handler)。查询方法,参数statement是在配置文件中定义的<select.../>元素的id,是查询所需的参数,通常是对象或者Map,RowBounds 对象用于分页,ResultHandr对象用来处理查询返回的复杂结果集,通常用于多表查询。
(18)void commit()。提交事务。
(19)void rollback()。回滚事务。
(20)void close()。关闭SqlSession对象。
(21)Connection getConnection()。获得JDBC的数据库连接对象。
(22)<T> T getMapper(Class<T> type)。返回mapper接口的代理对象,该对象关联了SqlSession对象,开发者可以通过该对象直接调用方法操作数据库,参数type是Mapper的接口类型。Mybatis官方手册建议通过mapper对象访问MyBatis。
5、SqlSession.getMapper方法详解
SqlSession有一个重要的方法getMapper,顾名思义,这个方式是用来获取Mapper映射器的。
6、SqlSession与Executor
SqlSession只是一个前台客服,真正发挥作用的是Executor,对SqlSession方法的访问最终都会落到Executor的相应方法上去。Executor分成两大类:一类是CachingExecutor,另一类是普通的Executor。
(1)CachingExecutor有一个重要属性delegate,它保存的是某类普通的Executor,在构造函数时候传入。执行数据库update操作时,它直接调用delegate的update方法,执行query方法时先尝试从cache中取值,取不到再调用delegate的查询方法,并将查询结果存入cache中。
(2)普通Executor分三类:SimpleExecutor、ReuseExecutor和BatchExecutor。它们都继承于BaseExecutor,BatchExecutor专门用于执行批量sql操作,ReuseExecutor会重用Statement执行sql操作,SimpleExecutor只是简单执行sql。
SimpleExecutor是一种常规执行器,每次执行都会创建一个Statement,用完后关闭。
ReuseExecutor是可重用执行器,将Statement存入map中,操作map中的Statement而不会重复创建Statement。
BatchExecutor是批处理型执行器,doUpdate预处理存储过程或批处理操作,doQuery提交并执行过程。
总之,Executor最终是通过JDBC的java.sql.Statement来执行数据库操作。