前言

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

官方文档: https://mybatis.org/mybatis-3/zh/getting-started.html

框架架构

image.png

基本使用

全局配置(mybatis-config.xml)

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!-- 可以引用一个外部的properties文件 -->
  7. <properties resource="mybatis/config.properties">
  8. <!-- 也可以单独定义属性 -->
  9. <!--<property name="username" value="root"/>-->
  10. <!--<property name="password" value="Xiele"/>-->
  11. </properties>
  12. <settings>
  13. <setting name="logImpl" value="STDOUT_LOGGING"/>
  14. </settings>
  15. <typeAliases>
  16. <!-- 每个类都要配置一个别名 -->
  17. <!--<typeAlias alias="User" type="com.example.start.springdemo.mybatis.User" />-->
  18. <package name="com.example.start.springdemo.mybatis"/>
  19. </typeAliases>
  20. <environments default="development">
  21. <environment id="development">
  22. <transactionManager type="JDBC"/>
  23. <dataSource type="POOLED">
  24. <property name="driver" value="${jdbc.driver}"/>
  25. <property name="url" value="${jdbc.url}"/>
  26. <property name="username" value="${jdbc.username}"/>
  27. <property name="password" value="${jdbc.password}"/>
  28. </dataSource>
  29. </environment>
  30. </environments>
  31. <mappers>
  32. <mapper resource="mybatis/mapper/UserMapper.xml"/>
  33. </mappers>
  34. </configuration>

注: 配置文件的元素需要保证顺序,严格按照如下顺序:

configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?

定义别名可以针对每个类作定义,也可以直接扫描包,默认别名为小写的类目,但mybatis不区分大小写,在resultType,或parameterType可以指定大小的短类目或小写的类目。因此可建议直接扫描包来定义别名。

官方文档描述如下: 每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子: @Alias(“author”) public class Author { … }


Mapper文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.example.start.springdemo.mybatis.dao.UserMapper">
  6. <resultMap id="UserMap" type="com.example.start.springdemo.mybatis.User">
  7. <id column="id" property="id"/>
  8. <result column="name" property="name"/>
  9. <result column="age" property="age"/>
  10. </resultMap>
  11. <select id="selectUser" resultMap="UserMap">
  12. select * from spring_user where id = #{id}
  13. </select>
  14. <select id="selectUserByType" resultType="User">
  15. select * from spring_user where id = #{id}
  16. </select>
  17. <select id="listUsers" resultType="User">
  18. select * from ${tableName}
  19. </select>
  20. </mapper>

执行SQL

指定命名空间与SqlId

  1. @Test
  2. public void testGetStarted() throws IOException {
  3. String resource = "mybatis/mybatis-config.xml";
  4. InputStream inputStream = Resources.getResourceAsStream(resource);
  5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  6. final SqlSession sqlSession = sqlSessionFactory.openSession();
  7. User user = sqlSession.selectOne("com.example.start.springdemo.mybatis.dao.UserMapper.selectUser", 1L);
  8. System.out.println("User:" + user);
  9. User user2 = sqlSession.selectOne("com.example.start.springdemo.mybatis.dao.UserMapper.selectUserByType", 1L);
  10. System.out.println(user2);
  11. sqlSession.close();
  12. }

简单概括

使用mybatis的步骤如下:

1)配置mybatis-config.xml 全局的配置文件 (1、数据源,2、外部的mapper) 2)创建SqlSessionFactory 3)通过SqlSessionFactory创建SqlSession对象 4)通过SqlSession操作数据库 CRUD 5)调用session.commit()提交事务 6)调用session.close()关闭会话

通过动态代理Mapper方式

定义Mapper接口

Mapper接口也就是DAO接口,接口全限定接口名(包名+接口名)即为SqlMap XML中的namespace,接口的方法名称为SqlMap中的SqlId.
如接口定义如下:

  1. /**
  2. * Alipay.com Inc.
  3. * Copyright (c) 2004-2020 All Rights Reserved.
  4. */
  5. package com.example.start.springdemo.mybatis.dao;
  6. import java.util.List;
  7. import com.example.start.springdemo.mybatis.User;
  8. import org.apache.ibatis.annotations.Param;
  9. /**
  10. * @author xiele.xl
  11. * @date 2020-06-04 11:04
  12. */
  13. public interface UserMapper {
  14. User selectUser(Long id);
  15. User selectUserByType(Long id);
  16. List<User> listUsers(@Param("tableName") String tableName);
  17. }

Mapper XML文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.example.start.springdemo.mybatis.dao.UserMapper">
  6. <resultMap id="UserMap" type="com.example.start.springdemo.mybatis.User">
  7. <id column="id" property="id"/>
  8. <result column="name" property="name"/>
  9. <result column="age" property="age"/>
  10. </resultMap>
  11. <select id="selectUser" resultMap="UserMap">
  12. select * from spring_user where id = #{id}
  13. </select>
  14. <select id="selectUserByType" resultType="User">
  15. select * from spring_user where id = #{id}
  16. </select>
  17. <select id="listUsers" resultType="User">
  18. select * from ${tableName}
  19. </select>
  20. </mapper>

SqlSession.getMapper

  1. @Test
  2. public void testMapper() throws IOException {
  3. String resource = "mybatis/mybatis-config.xml";
  4. InputStream inputStream = Resources.getResourceAsStream(resource);
  5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  6. SqlSession sqlSession = sqlSessionFactory.openSession();
  7. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  8. User user = mapper.selectUserByType(1L);
  9. User user2 = mapper.selectUserByType(1L);
  10. System.out.println("mapper query -> " + user + user2);
  11. }

注: 通过Mapper接口调用,其底层也是获取完整的namespace+sqlId,即完整的statement

配置说明

属性(properties)

mybatis-config.xml中配置,这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:

  1. <properties resource="org/mybatis/example/config.properties">
  2. <property name="username" value="dev_user"/>
  3. <property name="password" value="F2Fa3!33TYyg"/>
  4. </properties>

类型别名(typeAliases)

在mybatis-config.xml中配置,类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

  1. <typeAliases>
  2. <typeAlias alias="Author" type="domain.blog.Author"/>
  3. <typeAlias alias="Blog" type="domain.blog.Blog"/>
  4. <typeAlias alias="Comment" type="domain.blog.Comment"/>
  5. <typeAlias alias="Post" type="domain.blog.Post"/>
  6. <typeAlias alias="Section" type="domain.blog.Section"/>
  7. <typeAlias alias="Tag" type="domain.blog.Tag"/>
  8. </typeAliases>
  9. 当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。
  10. 也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
  11. <typeAliases>
  12. <package name="domain.blog"/>
  13. </typeAliases>
  14. 每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:
  15. @Alias("author")
  16. public class Author {
  17. ...
  18. }

Mapper文件

在mybatis-config.xml中配置。

  1. <!-- 使用相对于类路径的资源引用 -->
  2. <mappers>
  3. <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  4. <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  5. <mapper resource="org/mybatis/builder/PostMapper.xml"/>
  6. </mappers>

这里所谓的mapper接口路径。实际上就是dao的接口路径。在mybatis中,通常把dao的包叫做mapper。类名,也叫做mapper
1、定义一个接口。
2、在接口所在的包中定义mapper.xml,并且要求xml文件和interface的名称要相同。
3、在mybatis-config.xml 中通过class路径,引入mapper(注解方式)。要求mapper.xml 中的名称空间是类的接口的全路径。

如下的方式为用注解来配置Mapper

  1. <!-- 使用映射器接口实现类的完全限定类名 -->
  2. <mappers>
  3. <mapper class="org.mybatis.builder.AuthorMapper"/>
  4. <mapper class="org.mybatis.builder.BlogMapper"/>
  5. <mapper class="org.mybatis.builder.PostMapper"/>
  6. </mappers>
  1. <!-- 将包内的映射器接口实现全部注册为映射器 -->
  2. <mappers>
  3. <package name="org.mybatis.builder"/>
  4. </mappers>

Mapper XML文件详解

CRUD标签

select

select – 书写查询sql语句
select中的几个属性说明:
id属性:当前名称空间下的statement的唯一标识。必须。要求id和mapper接口中的方法的名字一致。
resultType:将结果集映射为java的对象类型。必须(和 resultMap 二选一)
parameterType:传入参数类型。可以省略

insert

insert 的几个属性说明:
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
useGeneratedKeys:开启主键回写,默认为false,
keyColumn:指定数据库的主键,一般指定为id
keyProperty:主键对应的pojo属性名,一般指定为id
标签内部:具体的sql语句。

update

id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。

delete

delete 的几个属性说明:
id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。

#{}和${}

{} 只是替换?,相当于PreparedStatement使用占位符去替换参数,可以防止sql注入。
${} 是进行字符串拼接,相当于sql语句中的Statement,使用字符串去拼接sql,$可以是sql中的任一部分传入到Statement中,不能防止sql注入。

使用${} 去取出参数值信息,需要使用${value}
#{} 只是表示占位,与参数的名字无关,如果只有一个参数,会自动对应。
因此:推荐用[@Param](#)("xxx") 来解决SQL里的参数名称与接口方法里的参数名称一一对应,做到更好的可读性。

${} 占位符不会插入单引号,直接用原始字符串替换变量。
#{}占位符会在变量里插入一对单引号,'' 因此使用#{}替换表名时,会出现异常:
如SQL为:

  1. <select id="listUsers" resultType="User">
  2. select * from #{tableName}
  3. </select>

调用方式:

  1. List<User> users = mapper.listUsers("spring_user");
  2. System.out.println(users);
  3. sqlSession.close();

会抛出如下异常:

  1. Caused by: java.sql.SQLSyntaxErrorException:
  2. You have an error in your SQL syntax;
  3. check the manual that corresponds to your MySQL server version
  4. for the right syntax to use near ''spring_user'' at line 1

在表名上添加单引号是非法的SQL。