SSM框架开发应用(五)——MyBatis-核心对象

本文深入介绍了MyBatis框架的三大核心对象:SqlSessionFactoryBuilder、SqlSessionFactory和SqlSession,详细解析了它们的作用、生命周期及使用方式。

MyBatis-核心对象

基于前面的学习,我们对MyBatis有了初步认识。

下面正式介绍一下MyBatis的三个基本要素:

  • 核心接口和类;
  • MyBatis核心配置文件(mybatis-config.xml);
  • SQL映射文件(mapper.xml)。

本篇主要介绍MyBatis的核心接口和类,如图所示:
MyBatis核心接口和类的结构图
(1)每个MyBatis的应用程序都以一个SqlSessionFactory对象的实例为核心;
(2)首先以根据XML配置文件或Configuration类的实例构建该对象;
(3)然后获取SqlSessionFactory对象,该对象实例可以通过SqlSessionFactoryBuilder对象来获得。
(4)有了SqlSessionFactory对象之后,就可以进而获取SqlSession实例,SqlSession对象中完全包含以数据库为背景的所有执行SQL操作的方法。可以用该实例直接执行已映射的SQL语句。

一、SqlSessionFactoryBuilder

1. SqlSessionFactoryBuilder的作用
SqlSessionFactoryBuilder负责构建SqlSessionFactory,并且提供了多个build()方法的重载,如图所示:
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的最佳范围就是存在于方法体内,也就是局部变量而已。

二、SqlSessionFactory

1. SqlSessionFactory的作用
SqlSessionFactory简单的理解就是创建SqlSession实例的工厂。

所有的MyBatis应用都是以SqlSessionFactory实例为中心。

SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder对象来获得。

有了它之后,顾名思义,就可以通过SqlSessionFactory提供的openSession()方法来获取SqlSession实例。

如图所示:
SqlSessionFactory提供的openSession()方法

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

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

2. SqlSessionFactory的声明周期和作用域
SqlSessionFactory对象一旦创建,就会在整个应用运行过程中始终存在。
没有理由去销毁或再创建它,并且在应用运行中也不建议多次创建SqlSessionFactory。
因此,SqlSessionFactory的最佳作用域时Application,即随着应用的生命周期一同存在。

那么这种“存在于整个应用运行期间,并且同时只存在一个对象实例”的模式就是所谓的单例模式(指在应用运行期间有且仅有一个实例)。

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

实现步骤如下。
(1)创建工具类MyBatisUtil.java,在静态代码块中创建SqlSessionFactory对象。

        package com.smbms.util;

        import java.io.IOException;
        import java.io.InputStream;

        import org.apache.ibatis.io.Resources;
        import org.apache.ibatis.session.SqlSessionFactory;
        import org.apache.ibatis.session.SqlSessionFactoryBuilder;

        public class MyBatisUtil {
            private static SqlSessionFactory factory;
            
            static{
                try {
                    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
                    factory = new SqlSessionFactoryBuilder().build(is);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

(2)创建SqlSession对象和关闭SqlSession。

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

通过以上静态类的方式来保证SqlSessionFactory实例只被创建一次。

当然,最佳的解决方案是使用依赖注入容器 – Spring框架来管理SqlSessionFactory的单例声明周期。

关于和Spring的集成,我们会在以后的学习中进行讲解。

完整的com.smbms.util.MyBatisUtil.java代码如下:

package com.smbms.util;

        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;

        /**
         * @文件描述 MyBatis工具类 
         * @创建用户 lkw
         * @创建时间 2017年5月19日 上午2:08:11
         */
        public class MyBatisUtil {
            // SqlSession工厂
            private static SqlSessionFactory factory;
            
            // 初始化SqlSessionFactory
            static{
                try {
                    InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
                    factory = new SqlSessionFactoryBuilder().build(is);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            
            /**
             * 创建SqlSession实例
             */
            public static SqlSession createSqlSession(){
                return factory.openSession(false);  // true为自动提交事务
            }
            
            /**
             * 关闭SqlSession实例
             */
            public static void closeSqlSession(SqlSession sqlSession){
                if(null != sqlSession)
                    sqlSession.close();
            }
        }
// 示例:MyBatisDemo02

【注意】
设计模式中的单例模式,我们会在后续的SpringMVC学习中具体展开讲解,此处先稍作了解即可。

三、SqlSession

1. SqlSession的作用
SqlSession是用于执行持久化操作的对象,类似于JDBC中的Connection。

它提供了面向数据库执行SQL命令所需的所有方法,可以通过SqlSession实例直接运行已映射的SQL语句。

如图所示:
:SqlSession提供的方法

2. SqlSession的生命周期和作用域
正如其名,SqlSession对应着一次数据库会话。

由于数据库会话不是永久的,因此SqlSession的生命周期也不应该是永久的。

相反,在每次访问数据库时都需要创建它。

(注意,并不是说在SqlSession里只能执行一次SQL,是完全可以执行多次的,但是如果关闭了SqlSession,那么就需要重新创建它)

需要注意的是,每个线程都有自己的SqlSession实例,SqlSession实例不能被共享,也不是线程安全的。

因此最佳的作用域范围是request作用域或者方法体作用域内。

关闭SqlSession是非常重要的,必须要确保SqlSession在finally语句块中正常关闭。

可以使用下面的标准方式来关闭:

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

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

添加User实体类(com.smbms.pojo.User.java):

package com.smbms.pojo;

        import java.util.Date;
        /**
         * @文件描述 实体类,用户信息 
         * @创建用户 lkw
         * @创建时间 2017年5月19日 上午2:15:01
         */
        public class User {
            // 字段
            private Integer id; //id 
            private String userCode; //用户编码
            private String userName; //用户名称
            private String userPassword; //用户密码
            private Integer gender;  //性别
            private Date birthday;  //出生日期
            private String phone;   //电话
            private String address; //地址
            private Integer userRole;    //用户角色
            private Integer createdBy;   //创建者
            private Date creationDate; //创建时间
            private Integer modifyBy;     //更新者
            private Date modifyDate;   //更新时间
            
            // 省略 getters & setters
        }

新增User的SQL映射文件(com/smbms/dao/user/UserMapper.xml),并增加查询用户列表的select节点:

 <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
        <mapper namespace="com.smbms.dao.user.UserMapper">

            <!-- 查询用户表记录数 -->
            <select id="count" resultType="int">
                select count(1) as count from smbms_user
            </select>
            
            <!-- 查询用户列表 -->
            <select id="getUserList" resultType="com.smbms.pojo.User">
                select * from smbms_user
            </select>   
            
        </mapper>

在mybatis-config.xml的mappers中添加UserMapper.xml的映射:

 <!-- 将mapper文件加入到配置文件中 -->
        <mappers>
            <mapper resource="com/smbms/dao/user/UserMapper.xml"/>
        </mappers>

在test下新建测试类com.smbms.dao.user.UserMapperTest.java,调用selectList()方法执行查询操作:

package com.smbms.dao.user;

        import java.util.ArrayList;
        import java.util.List;
        import org.apache.ibatis.session.SqlSession;
        import org.apache.log4j.Logger;
        import org.junit.Test;
        import com.smbms.pojo.User;
        import com.smbms.util.MyBatisUtil;

        /**
         * @文件描述 测试类,用户信息 
         * @创建用户 lkw
         * @创建时间 2017年5月19日 上午2:19:07
         */
        public class UserMapperTest {
            // LOG4J
            private Logger logger = Logger.getLogger(UserMapperTest.class);
            
            @Test
            public void testGetUserList(){
                SqlSession sqlSession = null;
                List<User> userList = new ArrayList<User>();
                try {
                    sqlSession = MyBatisUtil.createSqlSession();
                    //第一种方式:调用selectList方法执行查询操作
                    userList = sqlSession.selectList("com.smbms.dao.user.UserMapper.getUserList");
                } catch (Exception e) {
                    e.printStackTrace();
                }finally{
                    MyBatisUtil.closeSqlSession(sqlSession);
                }
                for(User user: userList){
                    logger.debug("UserCode: " + user.getUserCode() + ", UserName: " + user.getUserName());
                }
            }   
            
        }

// 示例:MyBatisDemo03

(2)方法2
创建绑定映射语句的接口UserMapper.java,并提供接口方法getUserList(),该接口成为映射器。
注意,接口的方法必须与SQL映射文件中SQL语句的ID一一对应:

package com.smbms.dao.user;

        import java.util.List;
        import com.smbms.pojo.User;

        public interface UserMapper {
            /**
             * 查询用户表记录数
             * @return
             */
            public int count();
            /**
             * 查询用户列表
             * @return
             */
            public List<User> getUserList();
            
        }

修改测试类UserMapperTest.java,调用getMapper(Mapper.class)执行Mapper接口方法来实现对数据的查询操作:

 package com.smbms.dao.user;

        import java.util.ArrayList;
        import java.util.List;
        import org.apache.ibatis.session.SqlSession;
        import org.apache.log4j.Logger;
        import org.junit.Test;
        import com.smbms.pojo.User;
        import com.smbms.util.MyBatisUtil;

        /**
         * @文件描述 测试类,用户信息 
         * @创建用户 lkw
         * @创建时间 2017年5月19日 上午2:19:07
         */
        public class UserMapperTest {
            // LOG4J
            private Logger logger = Logger.getLogger(UserMapperTest.class);
            
            @Test
            public void testGetUserList(){
                SqlSession sqlSession = null;
                List<User> userList = new ArrayList<User>();
                try {
                    sqlSession = MyBatisUtil.createSqlSession();
                    
                    //第一种方式:调用selectList方法执行查询操作
                    //userList = sqlSession.selectList("com.smbms.dao.user.UserMapper.getUserList");
                    
                    //第二种方式:调用getMapper(Mapper.class)执行dao接口方法来实现对数据库的查询操作
                    userList = sqlSession.getMapper(UserMapper.class).getUserList();
                    
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }finally{
                    MyBatisUtil.closeSqlSession(sqlSession);
                }
                for(User user: userList){
                    logger.debug("UserCode: " + user.getUserCode() + ", UserName: " + user.getUserName());
                }
            }   
            
        }

// 示例:MyBatisDemo03

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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值