Mybatis学习

2021-02-03 10:09:45 浏览数 (1)

一、原生jdbc操作

使用jdbc进行数据库操作: 首先加载驱动driverManager,然后通过DriverManager获取数据库连接,创建statement,然后执行sql获取结果集,处理结果集,然后关闭连接。

代码语言:javascript复制
@SpringBootApplication
代码语言:javascript复制
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:mysql://127.0.0.1:3306/jdbcTest?serverTimezone=UTC";
        String userName = "root";
        String password = "root";

        User userParam = new User();
        userParam.setSchoolName("Sunny School");

        // 第一步:加载驱动程序
        Class.forName("com.mysql.jdbc.Driver");

        // 第二步:获得数据库的连接
        Connection conn = DriverManager.getConnection(url, userName, password);

        // 第三步:创建语句并执行
        Statement stmt = conn.createStatement();
        ResultSet resultSet = stmt.executeQuery("SELECT * FROM `user` WHERE schoolName = '"   userParam.getSchoolName()   "';");

        // 第四步:处理数据库操作结果
        List<User> userList = new ArrayList<>();
        while(resultSet.next()){
            User user = new User();
            user.setId(resultSet.getInt("id"));
            user.setName(resultSet.getString("name"));
            user.setEmail(resultSet.getString("email"));
            user.setAge(resultSet.getInt("age"));
            user.setSex(resultSet.getInt("sex"));
            user.setSchoolName(resultSet.getString("schoolName"));
            userList.add(user);
        }

        // 第五步:关闭连接
        stmt.close();

        for (User user : userList) {
            System.out.println("name : "   user.getName()   " ;  email : "   user.getEmail());
        }
    }
}

二、使用mybatis执行sql操作

下面是一个mybatis的简单例子:

代码语言:javascript复制
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        // 第一阶段:MyBatis的初始化阶段
        String resource = "mybatis-config.xml";
        // 得到配置文件的输入流
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 得到SqlSessionFactory
        SqlSessionFactory sqlSessionFactory =
                new SqlSessionFactoryBuilder().build(inputStream);

        // 第二阶段:数据读写阶段
        try (SqlSession session = sqlSessionFactory.openSession()) {
            // 找到接口对应的实现
            UserMapper userMapper = session.getMapper(UserMapper.class);
            // 组建查询参数
            User userParam = new User();
            userParam.setSchoolName("Sunny School");
            // 调用接口展开数据库操作
            List<User> userList =  userMapper.queryUserBySchoolName(userParam);
            // 打印查询结果
            for (User user : userList) {
                System.out.println("name : "   user.getName()   " ;  email : "   user.getEmail());
            }
        }
    }
}

从上面我们可以看到首先加载资源文件,然后通过资源流加载,通过创建sqlSessionBuilder来构建sqlSessionFactory。然后通过sqlSessionFactory打开session,基于打开的session获取mapper。接着操作mapper,最后关闭session。

其过程可以概括为:

mybatis流程图

获取资源文件流操作:可以看到在Resource类中获取资源配置有几种方式:

代码语言:javascript复制
inputStream = Resources.getResourceAsStream(resource);
getResourceAsProperties(String resource);
getResourceAsReader(String resource);
getResourceAsFile(String resource);
getUrlAsReader(String urlString);
getUrlAsProperties(String urlString);

重点放在sqlSessionFactory上,可以从测试类中可以看到其构建的过程:

流程图:

sqlSessionFactory构建过程

测试代码:

代码语言:javascript复制
//前置操作构建sqlSessionFactory
@BeforeAll
static void setup() throws Exception {
  createBlogDataSource();
  final String resource = "org/apache/ibatis/builder/MapperConfig.xml";
  final Reader reader = Resources.getResourceAsReader(resource);
  //构建sqlMapper
  sqlMapper = new SqlSessionFactoryBuilder().build(reader);
}

执行SqlSessionFactory构建:执行构建,首先创建xml配置构建对象进行解析,而解析的过程中涉及到将配置解析成xnode,然后进行配置解析,最后执行构建操作,从而获取到sqlSessionFactory。

代码语言:javascript复制
//sqlSessionFactory构造操作
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
  try {
    //创建xml配置构建器对象
    XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
    //进行构建
    return build(parser.parse());
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error building SqlSession.", e);
  } finally {
    ErrorContext.instance().reset();
    try {
      reader.close();
    } catch (IOException e) {
      // Intentionally ignore. Prefer previous error.
    }
  }
}

其涉及的过程:

代码语言:javascript复制
//执行解析操作
public Configuration parse() {
  //如果已经解析,则抛异常
  if (parsed) {
    throw new BuilderException("Each XMLConfigBuilder can only be used once.");
  }
  parsed = true;
  //首先将其解析成XNode,然后解析配置  
  parseConfiguration(parser.evalNode("/configuration"));
  return configuration;
}

执行的具体过程:调用底层的xpath操作

代码语言:javascript复制
//evaluate
private Object evaluate(String expression, Object root, QName returnType) {
  try {
    //xpath
    return xpath.evaluate(expression, root, returnType);
  } catch (Exception e) {
    throw new BuilderException("Error evaluating XPath.  Cause: "   e, e);
  }
}

执行解析配置:

代码语言:javascript复制
//解析配置
private void parseConfiguration(XNode root) {
  try {
    // issue #117 read properties first
    //配置元素  
    propertiesElement(root.evalNode("properties"));
    //setting配置  
    Properties settings = settingsAsProperties(root.evalNode("settings"));
    //加载自定义vfs  
    loadCustomVfs(settings);
    //加载自定义log实现  
    loadCustomLogImpl(settings);
    //类型别名元素  
    typeAliasesElement(root.evalNode("typeAliases"));
    //插件元素  
    pluginElement(root.evalNode("plugins"));
    //对象工厂元素  
    objectFactoryElement(root.evalNode("objectFactory"));
    //对象包装工厂元素  
    objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
    //反射工厂元素  
    reflectorFactoryElement(root.evalNode("reflectorFactory"));
    //setting元素  
    settingsElement(settings);
    // read it after objectFactory and objectWrapperFactory issue #631
    //环境元素  
    environmentsElement(root.evalNode("environments"));
    //databaseId提供者元素  
    databaseIdProviderElement(root.evalNode("databaseIdProvider"));
    //类型处理器元素  
    typeHandlerElement(root.evalNode("typeHandlers"));
    //映射元素  
    mapperElement(root.evalNode("mappers"));
  } catch (Exception e) {
    throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: "   e, e);
  }
}

解析获取了sqlSessionFactory对象,从而通过openSqlSession获取sqlSession对象,而通过sqlSession这个对象,就可以执行查询操作。

执行查询的流程:

首先通过默认的sqlSessionFactory可以拿到执行器executor、配置信息和事务,然后通过指向query操作,首先会去缓存执行器中进行查询,如果有,则进行返回,如果没有,则执行查询操作,然后在查询的过程中将结果返回的同时,将缓存信息写入到缓存中。

sqlsession操作过程

从mabatis的源码测试中可以看到:

代码语言:javascript复制
@Test
void shouldSelectAllAuthors() {
  try (SqlSession session = sqlMapper.openSession(TransactionIsolationLevel.SERIALIZABLE)) {
    List<Author> authors = session.selectList("org.apache.ibatis.domain.blog.mappers.AuthorMapper.selectAllAuthors");
    assertEquals(2, authors.size());
  }
}

执行的过程可以通过上面的列子可以进行追踪。除了这些,还有很多值得我们去学习的地方。

0 人点赞