尧图精选

【MyBatis系列1】基础知识(上)

🕒 发布时间:2026/9/25 18:28:01 📁 来源:尧图网络
主要讲解 MyBatis 的基础知识前言上个月完成了“Java 并发编程系列”和“Spring 基础系列”知识的学习这个月我们主要学习 MyBatis。MyBatis 网上的资料真的非常多整个知识体系也非常系统如果要整体学完需要花很多时间我的目的不是把 MyBatis 学精学全只要能完全满足日常的工作然后对相关原理进行初探这个 MyBatis 基础系列的目标就达成了等整个 Java 技术栈的知识都初步掌握一遍后再对 MyBatis 进行深入学习。MyBatis 是什么在移动互联网时代MyBatis 成为了目前互联网 Java 持久框架的首选。MyBatis 本是 Apache 的一个开源项目——iBatis2010 年这个项目由 Apache Software Foundation 迁移到了 Google Code并且改名为 MyBatis。MyBatis 是一个基于 Java 的持久层框架。MyBatis 提供的持久层框架包括 SQL Maps 和 Data Access ObjectsDAO它消除了几乎所有的 JDBC 代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML 或注解用于配置和原始映射将接口和 Java 的 POJOsPlain Old Java Objects普通的 Java 对象映射成数据库中的记录。目前Java 的持久层框架产品有许多常见的有 Hibernate 和 MyBatis。MyBatis 是一个小巧、方便、高效、简单、直接、半自动化的持久层框架Hibernate 是一个强大、方便、高效、复杂、间接、全自动化的持久层框架。MyBatis 的工作原理MyBatis 的工作原理如下读取 MyBatis 配置文件mybatis-config.xml 为 MyBatis 的全局配置文件配置了 MyBatis 的运行环境等信息例如数据库连接信息。加载映射文件。映射文件即 SQL 映射文件该文件中配置了操作数据库的 SQL 语句需要在 MyBatis 配置文件 mybatis-config.xml 中加载。mybatis-config.xml 文件可以加载多个映射文件每个文件对应数据库中的一张表。构造会话工厂通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。创建会话对象由会话工厂创建 SqlSession 对象该对象中包含了执行 SQL 语句的所有方法。Executor 执行器MyBatis 底层定义了一个 Executor 接口来操作数据库它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句同时负责查询缓存的维护。MappedStatement 对象在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数该参数是对映射信息的封装用于存储要映射的 SQL 语句的 id、参数等信息。输入参数映射输入参数类型可以是 Map、List 等集合类型也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。输出结果映射输出结果类型可以是 Map、 List 等集合类型也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。MyBatis 的工作原理我认为对理解 MyBatis 非常重要后面我会单独出一篇文章详细讲解 MyBatis 的工作原理这里仅作初步了解即可。MyBatis 的核心组件我们先来看 MyBatis 的“表面现象”——组件并且讨论它们的作用然后讨论它们的实现原理。MyBatis 的核心组件分为 4 个部分。SqlSessionFactoryBuilder构造器它会根据配置或者代码来生成 SqlSessionFactory采用的是分步构建的 Builder 模式。SqlSessionFactory工厂接口依靠它来生成 SqlSession使用的是工厂模式。SqlSession会话一个既可以发送 SQL 执行返回结果也可以获取 Mapper 的接口。在现有的技术中一般我们会让其在业务逻辑代码中“消失”而使用的是 MyBatis 提供的 SQL Mapper 接口编程技术它能提高代码的可读性和可维护性。SQL Mapper映射器:MyBatis 新设计存在的组件它由一个 Java 接口和 XML 文件或注解构成需要给出对应的 SQL 和映射规则。它负责发送 SQL 去执行并返回结果。SqlSessionFactory在 MyBatis 中既可以通过读取配置的 XML 文件的形式生成 SqlSessionFactory也可以通过 Java 代码的形式去生成 SqlSessionFactory。强烈推荐采用 XML 的形式因为代码的方式在需要修改的时候会比较麻烦。当配置了 XML 或者提供代码后MyBatis 会读取配置文件通过 Configuration 类对象构建整个 MyBatis 的上下文。SqlSessionFactory 是一个接口在 MyBatis 中它存在两个实现类SqlSessionManager 和 DefaultSqlSessionFactory。一般而言具体是由 DefaultSqlSessionFactory 去实现的而 SqlSessionManager 使用在多线程的环境中它的具体实现依靠 DefaultSqlSessionFactory它们之间的关系如图所示。每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为中心的而 SqlSessionFactory 唯一的作用就是生产 MyBatis 的核心接口对象 SqlSession所以它的责任是唯一的。我们往往会采用单例模式处理它下面讨论使用配置文件和 Java 代码两种形式去生成 SqlSessionFactory 的方法。使用 XML 构建 SqlSessionFactory首先在 MyBatis 中的 XML 分为两类一类是基础配置文件通常只有一个主要是配置一些最基本的上下文参数和运行环境另一类是映射文件它可以配置映射关系、SQL、参数等信息。先看一份简易的基础配置文件我们把它命名为 mybatis-config.xml放在工程类路径下其内容如下所示。?xml version1.0 encodingutf-8? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN http://mybatis.org/dtd/mybatis-3-config.dtd configuration typeAliases!--别名-- typeAliases aliasuser typecom.mybatis.po.User/ /typeAliases !-- 数据库环境 -- environments defaultdevelopment environment iddevelopment !-- 使用JDBC的事务管理 -- transactionManager typeJDBC / dataSource typePOOLED !-- MySQL数据库驱动 -- property namedriver valuecom.mysql.jdbc.Driver / !-- 连接数据库的URL -- property nameurl valuejdbc:mysql://localhost:3306/mybatis?characterEncodingutf8 / property nameusername valueroot / property namepassword value1128 / /dataSource /environment /environments !-- 将mapper文件加入到配置文件中 -- mappers mapper resourcecom/mybatis/mapper/UserMapper.xml / /mappers /configuration我们描述一下 MyBatis 的基础配置文件typeAlias元素定义了一个别名 user它代表着 com.mybatis.po.User 这个类。这样定义后在 MyBatis 上下文中就可以使用别名去代替全限定名了。environment 元素的定义这里描述的是数据库。它里面的 transactionManager 元素是配置事务管理器这里采用的是 MyBatis 的 JDBC 管理器方式。dataSource 元素配置数据库其中属性 typePOOLED 代表采用 MyBatis 内部提供的连接池方式最后定义一些关于 JDBC 的属性信息。mapper 元素代表引入的那些映射器在谈到映射器时会详细讨论它。有了基础配置文件就可以用一段很简短的代码来生成 SqlSessionFactory如下所示。SqlSessionFactory factory null; String resource mybatis-config.xml; InputStream is; try { InputStream is Resources.getResourceAsStream(resource); factory new SqlSessionFactoryBuilder().build(is); } catch (IOException e) { e.printStackTrace(); }使用代码创建 SqlSessionFactory虽然笔者不推荐使用这种方式但是我们还是谈谈如何使用它。通过代码来实现与使用 XML 构建 SqlSessionFactory 一样的功能——创建 SqlSessionFactory代码如下所示。// 数据库连接池信息 PooledDataSource dataSource new PooledDataSource(); dataSource.setDriver(com.mysql.jdbc.Driver); dataSource.setUsername(root); dataSource.setPassword (1128); dataSource.setUrl(jdbc:mysql://localhost:3306/mybatis); dataSource.setDefeultAutoCommit(false); // 采用 MyBatis 的 JDBC 事务方式 TransactionFactory transactionFactory new JdbcTransactionFactory(); Environment environment new Environment (development, transactionFactory, dataSource); // 创建 Configuration 对象 Configuration configuration new Configuration(environment); // 注册一个 MyBatis 上下文别名 configuration.getTypeAliasRegistry().registerAlias(role, Role.class); // 加入一个映射器 configuration.addMapper(RoleMapper.class); //使用 SqlSessionFactoryBuilder 构建 SqlSessionFactory SqlSessionFactory SqlSessionFactory new SqlSessionFactoryBuilder().build(configuration); return SqlSessionFactory;注意代码中的注释它和 XML 方式实现的功能是一致的只是方式不太一样而已。但是代码冗长如果发生系统修改那么有可能需要重新编译代码才能继续所以这不是一个很好的方式。除非有特殊的需要比如在配置文件中需要配置加密过的数据库用户名和密码需要我们在生成 SqlSessionFactory 前解密为明文的时候才会考虑使用这样的方式。SqlSession在 MyBatis 中SqlSession 是其核心接口。在 MyBatis 中有两个实现类DefaultSqlSession 和 SqlSessionManager。DefaultSqlSession 是单线程使用的而 SqlSessionManager 在多线程环境下使用。SqlSession 的作用类似于一个 JDBC 中的 Connection 对象代表着一个连接资源的启用。具体而言它的作用有 3 个获取 Mapper 接口。发送 SQL 给数据库。控制数据库事务。先来掌握它的创建方法有了 SqlSessionFactory 创建的 SqlSession 就十分简单了如下所示SqlSession sqlSession SqlSessionFactory.openSession();注意SqlSession 只是一个门面接口它有很多方法可以直接发送 SQL。它就好像一家软件公司的商务人员是一个门面而实际干活的是软件工程师。在 MyBatis 中真正干活的是 Executor我们会在底层看到它。SqlSession 控制数据库事务的方法如下所示//定义 SqlSession SqlSession sqlSession null; try { // 打开 SqlSession 会话 sqlSession SqlSessionFactory.openSession(); // some code... sqlSession.commit(); // 提交事务 } catch (IOException e) { sqlSession.rollback(); // 回滚事务 }finally{ // 在 finally 语句中确保资源被顺利关闭 if(sqlSession ! null){ sqlSession.close(); } }实现映射器的2种方式映射器是 MyBatis 中最重要、最复杂的组件它由一个接口和对应的 XML 文件或注解组成。它可以配置以下内容描述映射规则。提供 SQL 语句并可以配置 SQL 参数类型、返回类型、缓存刷新等信息。配置缓存。提供动态 SQL。本节阐述两种实现映射器的方式XML 文件形式和注解形式。不过在此之前先用以下 SQL 语句创建 role 表。CREATE TABLE role ( id bigint(20) NOT NULL, role_name varchar(20) DEFAULT NULL, note varchar(20) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEInnoDB DEFAULT CHARSETutf8;并且定义一个 POJO如下所示public class Role { private Long id; private String roleName; private String note; /**setter and getter**/ }映射器的主要作用就是将 SQL 查询到的结果映射为一个 POJO或者将 POJO 的数据插入到数据库中并定义一些关于缓存等的重要内容。注意开发只是一个接口而不是一个实现类。初学者可能会产生一个很大的疑问那就是接口不是不能运行吗是的接口不能直接运行。MyBatis 运用了动态代理技术使得接口能运行起来入门阶段只要懂得 MyBatis 会为这个接口生成一个代理对象代理对象会去处理相关的逻辑即可。用 XML 实现映射器用 XML 定义映射器分为两个部分接口和 XML。先定义一个映射器接口如下所示。package com.mybatis.mapper; import com.mybatis.po.Role; public interface RoleMapper { public Role getRole(Long id); }在用 XML 方式创建 SqlSession 的配置文件中有这样一段代码mapper resourcecom/mybatis/mapper/RoleMapper.xml /它的作用就是引入一个 XML 文件。用 XML 方式创建映射器如下所示。?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.mybatis.mapper.RoleMapper select idgetRole parameterTypelong resultTyperole SELECT id,role_name as roleName,note FROM role WHERE id #{id} /select /mapper注解实现映射器除 XML 方式定义映射器外还可以采用注解方式定义映射器它只需要一个接口就可以通过 MyBatis 的注解来注入 SQL如下所示。package com.mybatis.mapper; import org.apache.ibatis.annotations.Select; import com.mybatis.po.Role; public interface RoleMapper2 { Select(select id,role_name as roleName,note from t_role where id#{id}) public Role getRole(Long id); }这完全等同于 XML 方式创建映射器。也许你会觉得使用注解的方式比 XML 方式要简单得多。如果它和 XML 方式同时定义时XML 方式将覆盖掉注解方式所以 MyBatis 官方推荐使用的是 XML 方式因此本教程以 XML 方式为主讨论 MyBatis 的应用。MyBatis执行SQL的两种方式SqlSession 发送 SQL有了映射器就可以通过 SqlSession 发送 SQL 了。我们以 getRole 这条 SQL 为例看看如何发送 SQL。Role role (Role)sqlSession.select(com.mybatis.mapper.RoleMapper.getRole,1L);String 对象是由一个命名空间加上 SQL id 组合而成的它完全定位了一条 SQL这样 MyBatis 就会找到对应的 SQL。如果在 MyBatis 中只有一个 id 为 getRole 的 SQL那么也可以简写如下这是 MyBatis 前身 iBatis 所留下的方式Role role (Role)sqlSession.selectOne(getRole,1L);用 Mapper 接口发送 SQLSqlSession 还可以获取 Mapper 接口通过 Mapper 接口发送 SQL如下所示。RoleMapper roleMapper sqlSession.getMapper(RoleMapper.class); Role role roleMapper.getRole(1L);通过 SqlSession 的 getMapper 方法来获取一个 Mapper 接口就可以调用它的方法了。因为 XML 文件或者接口注解定义的 SQL 都可以通过“类的全限定名方法名”查找所以 MyBatis 会启用对应的 SQL 进行运行并返回结果。对比两种发送 SQL 方式笔者建议采用 SqlSession 获取 Mapper 的方式理由如下使用 Mapper 接口编程可以消除 SqlSession 带来的功能性代码提高可读性而 SqlSession 发送 SQL需要一个 SQL id 去匹配 SQL比较晦涩难懂。使用 Mapper 接口类似 roleMapper.getRole1L则是完全面向对象的语言更能体现业务的逻辑。使用 Mapper.getRole1L方式IDE 会提示错误和校验而使用 sqlSession.selectOne“getRole”,1L语法只有在运行中才能知道是否会产生错误。目前使用 Mapper 接口编程已成为主流尤其在 Spring 中运用 MyBatis 时Mapper 接口的使用就更为简单所以本教程使用 Mapper 接口的方式讨论 MyBatis。4种核心组件生命周期所谓生命周期就是每一个对象应该存活的时间比如一些对象一次用完后就要关闭使它们被 Java 虚拟机JVM销毁以避免继续占用资源所以我们会根据每一个组件的作用去确定其生命周期。SqlSessionFactoryBuilderSqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory创建成功后SqlSessionFactoryBuilder 就失去了作用所以它只能存在于创建 SqlSessionFactory 的方法中而不要让其长期存在。因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域也就是局部方法变量。SqlSessionFactorySqlSessionFactory 可以被认为是一个数据库连接池它的作用是创建 SqlSession 接口对象。因为 MyBatis 的本质就是 Java 对数据库的操作所以 SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中所以一旦创建了 SqlSessionFactory就要长期保存它直至不再使用 MyBatis 应用所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。由于 SqlSessionFactory 是一个对数据库的连接池所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory那么就存在多个数据库连接池这样不利于对数据库资源的控制也会导致数据库连接资源被消耗光出现系统宕机等情况所以尽量避免发生这样的情况。因此在一般的应用中我们往往希望 SqlSessionFactory 作为一个单例让它在应用中被共享。所以说 SqlSessionFactory 的最佳作用域是应用作用域。SqlSession如果说 SqlSessionFactory 相当于数据库连接池那么 SqlSession 就相当于一个数据库连接Connection 对象你可以在一个事务里面执行多条 SQL然后通过它的 commit、rollback 等方法提交或者回滚事务。所以它应该存活在一个业务请求中处理完整个请求后应该关闭这条连接让它归还给 SqlSessionFactory否则数据库资源就很快被耗费精光系统就会瘫痪所以用 try...catch...finally... 语句来保证其正确关闭。所以 SqlSession 的最佳的作用域是请求或方法作用域。MapperMapper 是一个接口它由 SqlSession 所创建所以它的最大生命周期至多和 SqlSession 保持一致尽管它很好用但是由于 SqlSession 的关闭它的数据库连接资源也会消失所以它的生命周期应该小于等于 SqlSession 的生命周期。Mapper 代表的是一个请求中的业务处理所以它应该在一个请求中一旦处理完了相关的业务就应该废弃它。以上我们讨论了 MyBatis 组件的生命周期如图所示
上一篇/下一篇内容由系统自动关联 返回资讯列表 →