SSM轻量级框架应用实战
上QQ阅读APP看书,第一时间看更新

任务3 掌握MyBatis的核心对象

通过前面的学习,我们对MyBatis有了初步认识,下面继续介绍MyBatis的三个基本要素。

➢ 核心接口和类。

➢ MyBatis核心配置文件(mybatis-config.xml)。

➢ SQL映射文件(mapper.xml)。

MyBatis的核心接口和类,如图1.19所示。

图1.19 MyBatis核心接口和类的结构图

(1)每个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心。

(2)首先获取SqlSessionFactoryBuilder对象,可以根据XML配置文件或Configuration类的实例构建该对象。

(3)然后获取SqlSessionFactory对象,该对象实例可以通过SqlSessionFactoryBuilder对象获得。

(4)有了SqlSessionFactory对象之后,进而可以获取SqlSession实例,SqlSession对象中完全包含以数据库为背景的所有执行SQL操作的方法。可以用该实例来直接执行已映射的SQL语句。

1.3.1 SqlSessionFactory的构造者——SqlSessionFactoryBuilder

1. SqlSessionFactoryBuilder的作用

SqlSessionFactoryBuilder负责构建SqlSessionFactory,并且提供了多个build()方法的重载,如图1.20所示。

图1.20 SqlSessionFactoryBuilder提供的build()方法

通过源码分析,可以发现都是在调用同一个签名方法。

build(InputStream inputStream, String environment, Properties properties)

由于方法参数environment和properties都可以为null,去除重复的,真正的重载方法其实只有如下三种。

➢ build(Reader reader, String environment, Properties properties)。

➢ build(InputStream inputStream, String environment, Properties properties)。

➢ build(Configuration config)。

通过上述分析,发现配置信息以三种形式提供给SqlSessionFactoryBuilder的build()方法,分别是InputStream(字节流)、Reader(字符流)、Configuration(类),由于字节流与字符流都属于读取配置文件的方式,所以从配置信息的来源去构建一个SqlSessionFactory有两种方式:读取XML配置文件构造方式和编程构造方式。本章我们采用读取XML配置文件的方式来构造SqlSessionFactory。

2. SqlSessionFactoryBuilder的生命周期和作用域

SqlSessionFactoryBuilder的最大特点是用过即丢。一旦创建了SqlSessionFactory对象,这个类就不需要存在了,因此SqlSessionFactoryBuilder的最佳使用范围就是存在于方法体内,也就是局部变量。

1.3.2 SqlSession的工厂——SqlSessionFactory

1. SqlSessionFactory的作用

SqlSessionFactory就是创建SqlSession实例的工厂。所有的MyBatis应用都是以Sql SessionFactory实例为中心,SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder对象来获得。有了它之后,就可以通过SqlSessionFactory提供的openSession()方法来获取SqlSession实例,如图1.21所示。

图1.21 SqlSessionFactory提供的openSession( )方法

注意

openSession()方法的参数为boolean值时,若传入true表示关闭事务控制,自动提交;若传入false表示开启事务控制。若不传入参数,默认为true。

openSession(boolean autoCommit)

openSession()//若不传入参数,默认为true,自动提交

2. SqlSessionFactory的生命周期和作用域

SqlSessionFactory对象一旦创建,就会在整个应用运行过程中始终存在。没有理由去销毁或再创建它,并且在应用运行中也不建议多次创建SqlSessionFactory。因此SqlSessionFactory的最佳作用域是Application,即随着应用的生命周期一同存在。那么这种“存在于整个应用运行期间,并且同时只存在一个对象实例“的模式就是所谓的单例模式(指在应用运行期间有且仅有一个实例)。

下面优化获取SqlSessionFactory的代码,最简单的实现方式就是放在静态代码块下,以保证SqlSessionFactory对象只被创建一次,实现步骤如下。

(1)创建工具类MyBatisUtil.java,在静态代码块中创建SqlSessionFactory对象。关键代码如示例4所示。

示例4

package cn.smbms.utils;
import java.io.IOException;
import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class MyBatisUtil {
  private static SqlSessionFactory factory;
  static{//在静态代码块中,factory只会被创建一次
      try {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        factory = new SqlSessionFactoryBuilder().build(is);
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
  }
}

(2)创建SqlSession对象和关闭SqlSession。关键代码如示例5所示。

示例5

public static SqlSession createSqlSession(){
  return factory.openSession(false); //true为自动提交事务
}
public static void closeSqlSession(SqlSession sqlSession){
  if(null ! = sqlSession)
    sqlSession.close();
}

通过以上静态类的方式来保证SqlSessionFactory实例只被创建一次,当然,最佳的解决方案是使用Spring框架来管理SqlSessionFactory的单例模式生命周期。关于和Spring的集成,我们会在后续章节中进行讲解。

注意

设计模式中的单例模式,我们会在后续的SpringMVC章节中具体展开讲解,此处稍作了解即可。

1.3.3 使用SqlSession进行数据持久化操作

1. SqlSession的作用

SqlSession是用于执行持久化操作的对象,类似于JDBC中的Connection。它提供了面向数据库执行SQL命令所需的所有方法,可以通过SqlSession实例直接运行已映射的SQL语句,其方法如图1.22所示。

图1.22 SqlSession提供的方法

2. SqlSession的生命周期和作用域

SqlSession对应着一次数据库会话,由于数据库会话不是永久的,因此SqlSession的生命周期也不是永久的。相反,在每次访问数据库时都需要创建它(注意:并不是说在SqlSession里只能执行一次SQL,它是完全可以执行多次的,但是若关闭了SqlSession,那么就需要重新创建它)。创建SqlSession的方式只有一个,那就是使用SqlSessionFactory对象的openSession()方法。

注意

每个线程都有自己的SqlSession实例,SqlSession实例不能被共享,也不是线程安全的。因此最佳的作用域范围是request作用域或者方法体作用域。

关闭SqlSession是非常重要的。必须确保SqlSession在finally语句块中正常关闭。可以使用下面的标准方式来关闭。

SqlSession session = sqlSessionFactory.openSession();
try {
  // do work
} finally {
  session.close();
}

3. SqlSession的两种使用方式

(1)通过SqlSession实例来直接执行已映射的SQL语句。例如,通过调用selectList方法执行用户表的查询操作,步骤如下。

➢ 修改UserMapper.xml文件,增加查询用户列表的select节点,关键代码如示例6所示。

示例6

<! -- 查询用户列表 -->
<select id="getUserList" resultType="cn.smbms.pojo.User">
  select * from smbms_user
</select>

➢ 修改测试类UserMapperTest.java,调用selectList方法执行查询操作,关键代码如示例7所示。

示例7

@Test
public void testGetUserList(){
  SqlSession sqlSession = null;
  List<User> userList = new ArrayList<User>();
  try {
    sqlSession = MyBatisUtil.createSqlSession();
    //调用selectList方法执行查询操作
    userList = sqlSession.selectList(
              "cn.smbms.dao.user.UserMapper.getUserList");
  } catch (Exception e) {
    // TODO: handle exception
    e.printStackTrace();
  }finally{
    MyBatisUtil.closeSqlSession(sqlSession);
  }
  for(User user: userList){
    logger.debug("testGetUserList userCode: " + user.getUserCode()
              + " and userName: " + user.getUserName());
  }
}

(2)基于mapper接口方式操作数据。修改上一个演示示例,步骤如下。

➢ 创建绑定映射语句的接口UserMapper.java,并提供接口方法getUserList(),关键代码如示例8所示。该接口称为映射器。注意:接口的方法必须与SQL映射文件中SQL语句的ID一一对应。

示例8

package cn.smbms.dao.user;
import java.util.List;
import cn.smbms.pojo.User;
public interface UserMapper {
  /**
    * 查询用户列表
    * @return
    */
  public List<User> getUserList();
}

➢ 修改测试类UserMapperTest.java,调用getMapper(Mapper.class)执行Mapper接口方法来实现对数据的查询操作,关键代码如示例9所示。

示例9

@Test
public void testGetUserList(){
  SqlSession sqlSession = null;
  List<User> userList = new ArrayList<User>();
  try {
    sqlSession = MyBatisUtil.createSqlSession();
    //调用getMapper(Mapper.class)执行Mapper接口方法
    userList = sqlSession.getMapper(UserMapper.class).getUserList();
  } catch (Exception e) {
      // TODO: handle exception
      e.printStackTrace();
  }finally{
      MyBatisUtil.closeSqlSession(sqlSession);
  }
  for(User user: userList){
      logger.debug("testGetUserList userCode: " + user.getUserCode()
                + " and userName: " + user.getUserName());
  }
}

注意

第一种方式是旧版本的MyBatis提供的操作方式,现在也可以正常工作;第二种方式是MyBatis官方推荐使用的,其表达方式也更加直白,代码更加清晰,类型更加安全,也不用担心易错的字符串字面值以及强制类型转换。

技能训练

上机练习2——在超市订单管理系统中实现供应商表的查询操作

需求说明

(1)在上机练习1搭建的环境中,使用MyBatis实现对供应商表的查询操作(查询出全部数据)。

(2)要求编写工具类MyBatisUtil.java,获取SqlSessionFactory实例。

(3)要求分别使用两种方式(通过SqlSession实例直接运行已映射的SQL语句;基于mapper接口方式操作数据)实现对数据的操作,并对比两种方式的区别。

提示

(1)修改SQL映射文件ProviderMapper.xml,增加select元素节点,编写查询语句。

(2)编写MyBatisUtil.java,在静态代码块中实现SqlSessionFactory对象的创建,并且在该类中增加创建SqlSession和关闭SqlSession的静态方法。

(3)创建绑定映射语句的Mapper接口:ProviderMapper.java。

(4)修改测试类ProviderMapperTest.java,按照两种方式分别实现对数据的操作,并在后台运行输出结果。