MyBatis

MyBatis上手教程–面向接口编程

一存在问题

在上一个快速上手教程「Mybatis上手教程」中,我们最后的代码如下:

 @Test
    public void test() throws IOException {
        //1读取配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //2根据配置文件,创建1个SqlSessionFactory类的对象
        SqlSessionFactory sqlSessionFactory =
                new SqlSessionFactoryBuilder().build(inputStream);
        //3根据SqlSessionFactory的对象,新建一个SqlSession类的对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //4调用SqlSession的方法selectOne(),返回Employee类的对象
        Employee e = sqlSession.selectOne("selectEmployee", 1);
        System.out.println(e);
    }

在该代码中,有2个不太好的地方:

跟SQL脚本绑定太死;sql mapper文件中的SQL id是什么,这里的第1个参数就得写什么;Employee e = sqlSession.selectOne(“selectEmployee”, 1);

第2个参数传递可能会出现错误;如果不看SQL mapper文件的定义的话,我们是不知道第2个参数只能传递整型值的;

二 改进问题

mybatis提供了一种新的执行方式,通过将接口和SQL mapper文件绑定在一起的形式,最后的Java代码里通过反射的机制来获取接口的实现类对象,通过该对象来调用接口中的预定义的方法,并最终达到目的的。具体实现思路为:

1 定义接口和方法

创建src/main/java/com/knockatdatabase/dao/EmployeeMapper.java该接口,并定义一个方法,用于返回Employee类型的对象。

package com.knockatdatabase.dao;
​
import com.knockatdatabase.Employee;
​
/**
 * @Author:asher
 * @Date:2021/10/2 10:24
 * @Description:com.knockatdatabase.dao
 * @Version:1.0
 */
public interface EmployeeMapper {
    Employee getEmployeeById(Integer id);
}

注意,这里的方法签名里,规定了一种规范,即参数值只能接受Integer类型。

2创建新的SQL mapper文件

在resources路径下,创建新的名为EmployeeMapper.xml的SQL mapper文件,注意,该文件名可以任意取,不一定非得要叫EmployeeMapper.xml。其内容为:

<?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.knockatdatabase.dao.EmployeeMapper">
    <select id="getEmployeeById" resultType="com.knockatdatabase.Employee">
    select id,last_name as lastname,gender,email as mail from tbl_employee where id = #{id}
  </select>
</mapper>

注意:

  • 此时的namespace要和上面定义的接口的全类名匹配,表示的是将接口和SQL mappper文件绑定在一起;
  • 同时该文件的SQL id就是上述接口EmployeeMapper.java中定义的方法名,绑定在一起的意思很明显,Java接口中的方法是通过id获取员工信息,这里的SQL语句的意思也是根据id获取员工信息。
3修改配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE configuration
                PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
                "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://172.16.11.35:3306/mybatis_project"/>
            <property name="username" value="mybatis_project"/>
            <property name="password" value="mybatis_project"/>
        </dataSource>
    </environment>
</environments>
<mappers>
<!--    <mapper resource="org/mybatis/example/BlogMapper.xml"/>-->
    <mapper resource="Employee.xml"/>
    <mapper resource="EmployeeMapper.xml"/>
</mappers>
</configuration>

在mappers属性标签下,要把刚刚新建的这个SQL mapper配置文件引入进来。不然,将来通过读取该配置文件时,就无法读取SQL mapper文件,进而也就无法执行程序了。这里的方式,新增加了一个mapper标签,并引入了新的EmployeeMapper.xml配置文件。

4编写Java代码

大体思路还是跟原来的思路差不多,先读取配置文件,通过SQLSessionFactoryBuilder获取1个SQLSessionFactory对象,根据SqlSessionFactory来获取1个SQLSession对象。

@Test
    public void test2() {
        String resource = "mybatis-config.xml";
        try {
            //1 读取配置文件
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //2 获取SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //3 获取SQLSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            //4 获取一个接口类的实现类对象,通过反射的方式,
            EmployeeMapper mapper = (EmployeeMapper) sqlSession.getMapper(Class.forName("com.knockatdatabase.dao.EmployeeMapper"));
            //5 通过接口实现类的对象,调用该接口的方法,其实就是相当于在执行和接口绑定的SQL mapper中的对应的SQL语句
            Employee employee = mapper.getEmployeeById(1);
            System.out.println(employee);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

注意:这里的方式是通过获取的SQL session对象之后,并没有像之前的方式那样,立即执行对应的SQL语句,而是先获取一个接口实现类的对象mapper,通过反射的方式。

获取这个接口实现类的对象之后,就可以直接调用该接口的方法getEmployeeById()了,这就回到Java的世界里了,对象.方法,熟悉的方式,舒适的方式。

当然,通过反射的方式取获取EmployeeMapper接口的实现类的对象,可以有2种方式:Class.forName(“接口的全类名”);或者是EmployeeMapper.class的方式也行。

        EmployeeMapper mapper = (EmployeeMapper) sqlSession.getMapper(Class.forName("com.knockatdatabase.dao.EmployeeMapper"));
        EmployeeMapper mapper = sqlSession.getMapper(EmployeeMapper.class);

上面的2行,任选1个都可以。当然了,这是Java里的反射的相关知识。

5 getMapper()代码
 /**
   * Retrieves a mapper.
   * @param <T> the mapper type
   * @param type Mapper interface class
   * @return a mapper bound to this SqlSession
   */
  <T> T getMapper(Class<T> type);

多看看框架的源代码,肯定是益处多多。

6 mybatis官方文档

2.1.4 Acquiring a SqlSession from SqlSessionFactory章节的内容如下:

Now that you have a SqlSessionFactory, as the name suggests, you can acquire an instance of SqlSession. The SqlSession contains absolutely every method needed to execute SQL commands against the database. You can execute mapped SQL statements directly against the SqlSession instance. For example:

try (SqlSession session = sqlSessionFactory.openSession()) {
 Blog blog = session.selectOne(
   "org.mybatis.example.BlogMapper.selectBlog", 101);
}

While this approach works, and is familiar to users of previous versions of MyBatis, there is now a cleaner approach. Using an interface (e.g. BlogMapper.class) that properly describes the parameter and return value for a given statement, you can now execute cleaner and more type safe code, without error prone string literals and casting.

For example:

try (SqlSession session = sqlSessionFactory.openSession()) {
 BlogMapper mapper = session.getMapper(BlogMapper.class);
 Blog blog = mapper.selectBlog(101);
}

三 小结

  • 多看官方文档,多动手敲代码;
  • Java基础很重要,之前学习的Java反射、输入输出流等基础知识,这不慢慢的都用上了嘛;