【MyBatis学习笔记】2:接口编程模式,生命周期中的各个对象,log4j使用,MyBatis工具类

MyBatis特有的接口编程模式

简述

上篇中获取查询结果使用的是iBatis遗留的”namespace.id”即提供Mapper接口方法的全限名,用反射的方式使用映射器中的方法的。

在MyBatis中,可以直接获得Mapper接口的一个实现类对象,这个对象是由MyBatis为Mapper接口生成的代理类对象(动态代理),然后调用其所实现的接口中的方法。这种方式相比iBatis遗留的方式,主要有以下好处:

  • 使用SqlSession的对象的方法,传入需要执行的接口和方法,不符合OOP的理念,而且这个长字符串并不能体现业务逻辑(语义缺失,可读性差)。
  • 使用Mapper接口的代理类对象调用其实现的成员方法,则IDE可以检查语法,不像前面传入一个字符串难以做语法检查。
  • 这种方法进一步屏蔽了SqlSession这个对象,真正完成数据库操作需求的是Mapper代理类对象,可读性更好。

使用

注释的是上篇使用的iBatis遗留方式,下面两行是接口编程模式获取Mapper代理类对象再做操作。

//Student student = sqlSession.selectOne("mapper.StudentMapper.getStudent", 2);
StudentMapper studentMapper=sqlSession.getMapper(StudentMapper.class);
Student student=studentMapper.getStudent(2);

生命周期中的各个对象

SqlSessionFactoryBuilder

它用XML或者Java程序获取配置信息,来构建SqlSessionFactory的实现类对象,所以一旦构建完成就可以废弃了。

SqlSessionFactory(接口)

它用来创建SqlSession会话,从前面指定的配置信息中构建出来的这个工厂作用都是一样的,所以每个数据库只需要对应一个SqlSessionFactory的实现类对象,它应使用单例模式

SqlSession(接口)

一个会话,相当于JDBC中的一次连接(Connection),线程不安全,使用完应在finally块中确保及时关闭。

Mapper(接口+XML/Annotation)

用来发送SQL对数据库进行操作,或返回需要的结果。应在一个SqlSession的生命周期事务方法内使用若干Mapper中的若干方法,然后废弃代理类对象。

为MyBatis使用log4j

在MyBatis中使用log4j可以记录具体执行了什么SQL等日志信息,在前面的例子中加入一个src/log4j.properties配置文件:

#定义日志的记录级别为DEBUG(则更高级的INFO,WARN,ERROR也会被输出),日志信息输出到标准输出
log4j.rootLogger=DEBUG,stdout
log4j.logger.org.mybatis=DEBUG
#指定标准输出为控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
#标准输出的布局是log4j的PatternLayout模式
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#指定模式,这里指定为"%5p至少5字符的日志优先级,%d日志记录时间,%C调用logger的类的全名,%m输出消息,%n当前平台下的换行符"
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n

就能够看到按照这里配置的格式进行输出的日志了:
这里写图片描述

书写MyBatis工具类

了解了前面生命周期中的各个对象,就可以像使用Hibernate时候那样书写一个工具类了,为MyBatis书写这个工具类可以简化MyBatis的使用,对某些对象做了进一步封装。

MyBatis工具类实际上是最核心的SqlSessionFactory的工具类,这个类去实现它的单例模式,并且保证了返回的SqlSession实现类对象的线程安全。

package util;

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

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

public class SqlSessionFactoryUtil {
    //单例的SqlSessionFactory实现类对象设置为类变量
    private static SqlSessionFactory sqlSessionFactory = null;
    //类线程锁用SqlSessionFactory的class对象
    private static final Class CLASS_LOCK = SqlSessionFactory.class;

    //将构造函数私有化,不允许外部创建该工具类对象
    private SqlSessionFactoryUtil() {

    }

    //初始化组合的SqlSessionFactory单例
    public static SqlSessionFactory initSqlSessionFactory() {
        //输入流放在try块外声明,这样在try块外可以使用
        InputStream inputStream = null;
        try {
            //从配置文件读到输入流
            inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        } catch (IOException e) {
            //发生异常时记录到日志(这里用的是JDK内置的Logger,而没使用log4j)
            //第一个参数是日志级别:在内置Logger中SEVERE>WARNING>INFO>CONFIG>FINE>FINER>FINESET
            //第二个参数是字符串信息,或作为信息目录中的key
            //第三个参数是一个Throwable实现类对象,关联到这个信息上
            Logger.getLogger(SqlSessionFactory.class.getName()).log(Level.SEVERE, null, e);
        }

        //使用synchronized对SqlSessionFactory类加锁,避免多线程环境中多次初始化造成对象不唯一
        synchronized (CLASS_LOCK) {
            //如果还没创建这个单例,用SqlSessionFactoryBuilder创建它
            if (null == sqlSessionFactory)
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }

        //返回创建好的这个单例
        return sqlSessionFactory;
    }

    //使用这个SqlSessionFactory单例来打开SqlSession
    public static SqlSession openSqlSession(){
        //如果这个单例还没创建,调用init初始化并创建之(但其实不必使用其返回值)
        if(null==sqlSessionFactory)
            initSqlSessionFactory();
        //打开SqlSession并返回
        return sqlSessionFactory.openSession();
    }

}

实现单例的方法往往像前面这样:

  • 构造方法私有化。
  • 提供静态的初始化方法,使之返回(唯一一次)构造好的单例。
  • 在多线程环境初始化单例,需要加上线程锁以避免多次初始化造成单例不唯一。

猜你喜欢

转载自blog.csdn.net/shu15121856/article/details/81042401