[图片] 本篇内容 MyBatis 概述 类比 JDBC 框架配置 Hello MyBatis 操作数据的三种方式 动态 SQL 关联映射 (一)概述 mybatis 是一个优秀的基于 java 的持久层框架,通过封装 jdbc 来提供方便的数据读写操作,开发者只需要关注 sql 语句本身,而不需要花费精力去重复编写很 ..

MyBatis 系列教程之(一)mybatis 基础

本贴最后更新于 372 天前,其中的信息可能已经时移世改

本篇内容

(一)概述
    mybatis 是一个优秀的基于 java 的持久层框架,通过封装 jdbc 来提供方便的数据读写操作,开发者只需要关注 sql 语句本身,而不需要花费精力去重复编写很多模板代码如加载驱动、创建连接、创建 statement 等繁杂的过程。
MyBatis 使用简单的 XML 或注解用于配置和对象与数据库的映射,将要执行的各种 jdbc statement 对象封装起来,最后由 mybatis 框架生成并执行 sql 语句并将结果映射为 java 对象返回。
本篇是系列第一篇,只介绍原生 MyBatis,不涉及 Maven, 以及与 Spring,Spring Boot 等框架的结合。

1. 直接使用 JDBC 的问题
1) 数据库连接创建、释放频繁影响系统性能
2)Sql 语句在代码中硬编码,造成代码不易维护,sql 的变动需要改变 java 代码
3) 对结果集解析存在硬编码(需手工完成数据表列名与 java 对象属性的映射)
4)动态 SQL 较难实现

2.MyBatis 基本原理
MyBatis 应用程序主要使用 SqlSession 对象(可以看成是 JDBC 的 Connection)实现应用程序与数据库间的通讯,SqlSession 由 SqlSessionFactory 创建,SqlSessionFactory 又由 SqlSessionFactoryBuilder 创建,而 SqlSessionFactoryBuilder 则可以从一个 XML 配置文件或者一个预定义的配置类的实例获得。(类比 JDBC 创建连接的过程)。创建顺序为:
SqlSessionFactoryBuilder->SqlSessionFactory->SqlSession

(二)第一个简单的 MyBatis 程序
1. 导入相应 jar 包
最少的依赖仅需要 mybatis 的 jar 和相应数据库 JDBC 驱动 jar(本教程使用 Mysql)

2. 创建实体与表映射
1)User 实体类

  public class User {
	private Integer id;
	private String userName;
	private String userPass;

	public User(){
		
	}

2)创建相关表,表字段同实体属性对应


3. 创建 Mybatis 配置文件用于加载数据源和指定映射文件位置(xml 文件, 放在 classpath 中)
1)配置 JDBC 相关信息 ( 配置数据源)
2)指定 Mapper 映射文件(用于对象 - 关系间的映射)所在路径
完整的文件如下:

<?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="test">
		<environment id="test">
			<transactionManager type="JDBC"></transactionManager>    <!-- 事务管理类型:JDBC、MANAGED -->
			<dataSource type="POOLED">    <!-- 数据源类型:POOLED、UNPOOLED、JNDI -->
				<property name="driver" value="com.mysql.jdbc.Driver" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/mybatistraning?characterEncoding=utf-8" />
				<property name="username" value="root" />
				<property name="password" value="root" />
			</dataSource>
		</environment>
	</environments>

	<!-- 加载映射mapper -->
	<mappers>
		<!-- 映射文件 路径用 斜线(/) 分割,而不是用 点(.) -->
		<mapper resource="mappers/UserMapper.xml"></mapper>
	</mappers>
	
</configuration>


4. 创建 MyBatis 映射文件(Mapper)
mybatis 将相应的 SQL 语句封装在名为 insert,delete,update,select 的元素中用于 CRUD。简单起见,当前例子中只包含查询操作,
使用<select>标签,id 属性作为要执行 SQL 的标识,后面会在程序中调用

<?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="dao.UserMapper">   <!-- 命名空间,名字可以随意起,只要不冲突即可 -->

	<!-- 封装SQL用于具体的数据读写操作,设置resultType 用于返回值类型 -->
	<select id="findAllUsers" resultType="entity.User">  <!-- 书写 SQL 语句 -->
		SELECT * FROM User
	</select>
	
    
    <!-- 查询功能,parameterType 设置参数类型,resultType 设置返回值类型 ,这里的#{id}用于接收传入的参数-->
    <select id="selectAllUsersDynamic" parameterType="java.lang.Integer" resultType="entity.User">  <!-- 书写 SQL 语句 -->
        SELECT id,userName,userPass FROM user where id=#{id}
		<!--
        <where>
            <if test="userName !=null">
                username = #{userName}
            </if>
            <if test="userPass != null">
                and userPass = #{userPass}
            </if>
        </where>
		-->
    </select>
</mapper>



5. 创建调用程序

1)创建读取配置文件的输入流, 注意你自己的 Mybatis 配置文件的路径

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);

2)通过 SqlSessionFactoryBuilder 和输入流构建 SqlSessionFactory

SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

3)通过 SqlSessionFactory 创建 SqlSession

SqlSession session = sqlSessionFactory.openSession();

4)使用 SqlSession 完成数据读写

//返回结果为单值用selectOne,多值则用selectList
List<User> allUserList = session.selectList("dao.findAllUsers");
System.out.println(allUserList);

其中,selectList 是 mybatis SqlSession 接口提供的 API,这里用来查询多条记录,也有其他相应数据操作的接口。
该方法的参数(字符串常量)是对之前 Mapper 映射文件中相应元素 (封装 SQL) 的引用,格式为 mapper 文件声明的 "命名空间名(namespace). 相应元素 id"

完整的调用程序及说明:

(三)MyBatis 读写数据的三种方式
1. 方式一:使用 Mybatis 原生 DAO 方法,即直接调用 mapper 映射文件相关 sql 元素的 id。这就是我们前面例子中用的方式。

2. 方式二(最常用,重点掌握):使用 Mapper 接口,即自定义数据读写接口,用方法名映射 mapper 映射文件相关 sql 元素的 id。
创建一个新的 package,比如叫 dao, 里面创建一个接口,比如 UserMapper, 接口里创建响应的数据操作方法,方法名同要
引用的 Mapper 映射文件中元素的 id, 比如你要引用<select id="findAllUsers" resultType="entity.User">,你接口
中的方法名就应该是 findAllUsers,参数类型和返回类型也要同元素声明的相对应。比如 findAllUsers 的 sql 返回的是
多条记录的结果集,java 接口中方法声明中的返回类型就要是集合类型,这里我们用 List 泛型:

/**
	 * 這裡的方法簽名要與mapper映射文件里的id值一致
	 * @return
	 */
	public List<User> findAllUsers();

调用方式跟第一种差不多,只是不再使用 sqlsession 自己的 API 直接执行 sql,而是先通过 getMapper 方法获取自定义接口
的实例,后面就通过自己的接口来执行 sql:
UserMapper userMapper = session.getMapper(UserMapper.class);
List allUserList = userMapper.findAllUser();
可以看出,这种方式相比第一种代码量会增加一些,但是语义更清晰,也不需要取拼写字符串常量。

3. 方式三:与第二种方式类似,也是使用自定义的 Mapper 接口完成 SQL 调用,只是不再使用 XML 配置文件,而是使用 Mabatis 提供
的注解

/**
	 * 使用mybatis sql註解在DAO接口中封裝sql,可脫離映射文件
	 * 適用於sql語句簡單的場景
	 * @return
	 */
	@Select("select * from User")
	public List<User> selectAllUsers();
	

这种方式的优点是将要执行的 sql 直接写在接口方法中(通过注解封装),不用再程序和 XML 中来回切换,思维连贯;
缺点则是如果 SQL 比较复杂,会显得程序较乱,所以只适合 SQL 语句简单的场景,后面我们会介绍使用 Mybatis 的 provider
机制将 Mapper 方法声明和实现分离,用面向对象的方式来编写 SQL。

实际开发当中,第二种方式是最核心的,建议大家结合第二第三种方式来开发,可以最大限度地提高效率并减少出错。

(四)两个小技巧
1. 使用 SQL 标签和 include 标签指定返回哪些字段
当多处调用相同的字段时,可以使用 Sql 标签,完成底层的字符串拼接,例如:

<!-- 定义 Sql 标签 -->
<sql id="cols">
    id,name,age
</sql>
<!-- 使用示例 -->
SELECT <include refid="cols"/> FROM person

2. 为实体类设置别名。在 Mapper.xml 文件中可以通过引用实体类别名简化工作,例如:
当然,需要先在 mybatis 配置文件 中先定义别名,例如:

<!-- 赋别名 -->
<typeAliases>
        <typeAlias type="yeepay.payplus.Person" alias="Person"/>
</typeAliases>

(五)MyBatis 实现动态 SQL
1. 动态查询(查询条件不定):where 标签和 if 标签

注意使用 where 标签可以去掉 sql 语句中的 where 1=1 并自动处理第一个 and

2. 动态修改(要修改的字段不定):set 标签和 if 标签

3. 批量删除(根据入参同时删除一条或多条记录):foreach 标签


(六)关联查询 MyBatis 作为一种半自动化 ORM 框架,关联映射没有 Hibernate 强大好用,使用 Mybatis 的项目中也很少使用对象关联场景, 这里简单介绍下,主要涉及一对多和多对一的关联。 1.** 一对多关联 **,需要单独创建结果集。 1)使用 *resultmap* 和 *association* 标签映射双方结果集


2)无参一对多关联查询

3)有(入)参的一对多关联查询

2. 多对一查询,也需要单独创建结果集
1)依然使用 resultmap 和 association 标签

2)无入参的多对一关联查询

3)有入参的多对一关联查询

3. 关于 resultMap 的说明
ResultMap 用于将复杂的查询结果映射到统一的结果集中, 通常用在多表关联查询中
不一定只在存在一对多或多对一的关联中使用,只是在这种场景中使用的比较多
1) 常用属性:
id:resultMap 标签的标识。
type:返回值的全限定类名,或类型别名。

2) 常用子元素 -- 用于非关联属性 ORM
id 元素 ,用于设置主键字段与领域模型属性的映射关系
result 元素 ,用于设置普通字段(非主键字段)与领域模型属性的映射关系
id,result 子元素常用属性

3) 常用子元素 -- 用于关联属性 ORM
association -- 指定单个对象的对应关系(一对一或多对一),属性:
property: 领域对象中关联对方的属性名(单值)
javaType: 对方的类型
子元素:同样是 id 和 result,用于关联的对方的 ORM

(七) 本篇要点总结
1. 两个配置文件:
mybatis 基础配置文件,此文件作为 mybatis 的全局配置文件,配置了 mybatis 的运行环境等信息。
mybatis 映射文件,文件中配置了操作数据库的 sql 语句,实现了 ORM。所有映射文件都需要在基础配置文件中声明。

  1. 会话工厂和会话:通过 mybatis 环境等配置信息构造 SqlSessionFactory 即会话工厂,由会话工厂创建 sqlSession 即会话,操作数据库需要通过 sqlSession 进行。

  2. Mapped Statement 对象完成具体的 CRUD:MappedStatement 包装了 mybatis 配置信息及 sql 映射信息等。映射文件中一个具体的 sql 标签对应一个 Mapped Statement 对象

  3. 参数的传入:Mapped Statement 对 sql 执行输入参数进行定义,包括基本类型、业务对象、集合等,Mapped Statement 在执行 sql 前将输入的 java 对象映射至 sql 中,输入参数映射就是 jdbc 编程中对 preparedStatement 设置参数。

  4. 结果集的处理: Mapped Statement 对 sql 执行输出结果进行定义,包括基本类型、业务对象、集合等

(八)练习:实现饭店、菜单和菜单项三个业务对象的关联查询,假设一个饭店只有一个菜单,一个菜单有多个菜单条目(菜单项),
自行创建实体对象,resultmap 和实现查询逻辑

  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    118 引用 • 394 回帖 • 765 关注
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    581 引用 • 1195 回帖 • 838 关注
回帖   
请输入回帖内容...