Save Load
GitHub 切换暗/亮/自动模式 切换暗/亮/自动模式 切换暗/亮/自动模式 返回首页

My Batis 5 SQL Session

MyBatis SqlSession

SqlSession 是 MyBatis 的关键对象,通过这个接口可以操作命令,管理事务等。

注意:虽然SqlSession提供select/insert/update/delete方法,在旧版本中使用使用SqlSession接口的这些方法,但是新版的Mybatis中就会建议使用Mapper接口的方法。

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 selectOne(String statement);int insert(String statement, Object parameter);等,也可以获取映射器Mapper: T getMapper(Class 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,关于 ThreadLocal 的用法,请参考:ThreadLocal 的使用场景:Web容器、Spring容器、日志打印

4、SqlSession 的常用方法如下:

SqlSession是应用程序与持久存储层之间执行交互操作的一个单线程对象,也是MyBatis执行持久化操作的关键对象。

SqlSession对象完全包含以数据库为背景的所有执行SQL操作的方法,它的底层封装了JDBC连接,可以用SqlSession实例来直接执行已映射的SQL语句。

SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。也不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。如果你现在正在使用一种 Web 框架,要考虑 SqlSession 放在一个和 HTTP 请求对象相似的作用域中。换句话说,每次收到的 HTTP 请求,就可以打开一个 SqlSession,返回一个响应,就关闭它。这个关闭操作是很重要的,你应该把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

可以考虑使用ThreadLocal来封装SqlSession,关于ThreadLocal的用法,请参考:ThreadLocal的使用场景:Web容器、Spring容器、日志打印

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 selectOne(String slatement)。查询方法,参数statement是在配置文件中定义的<select…/>元素的id,返回执行SQL语句查询结果的泛型对象,通常查询结果只有一条数据时才使用。
  • (8) T selectOne(String statement,Object parameter)。查询方法,参数statement是在配置文件中定义的<select…/>元素的id,parameter是查询所需的参数,通常是对象或者Map,返回执行SQL语句查询结果的泛型对象,通常查询结具只有一条数据时才使用。
  • (9) List selectList(String statemenl)。查询方法,参数是在配置文件中定义的<select…/>素的id,返回执行SQL话句查询结果的泛型对象的集合。
  • (10) List selectList(String statement,Object parameter)。查询方法,参数statement是在配置文件中定义的<select../>元素的id,parameter是查询所需的参数,通常是对象或者Map,返回执行SQL语句查询结果的泛型对象的集合。
  • (11) List 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 getMapper(Class 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来执行数据库操作。