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

基本使用
全局配置(mybatis-config.xml)
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration><!-- 可以引用一个外部的properties文件 --><properties resource="mybatis/config.properties"><!-- 也可以单独定义属性 --><!--<property name="username" value="root"/>--><!--<property name="password" value="Xiele"/>--></properties><settings><setting name="logImpl" value="STDOUT_LOGGING"/></settings><typeAliases><!-- 每个类都要配置一个别名 --><!--<typeAlias alias="User" type="com.example.start.springdemo.mybatis.User" />--><package name="com.example.start.springdemo.mybatis"/></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><mappers><mapper resource="mybatis/mapper/UserMapper.xml"/></mappers></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文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.start.springdemo.mybatis.dao.UserMapper"><resultMap id="UserMap" type="com.example.start.springdemo.mybatis.User"><id column="id" property="id"/><result column="name" property="name"/><result column="age" property="age"/></resultMap><select id="selectUser" resultMap="UserMap">select * from spring_user where id = #{id}</select><select id="selectUserByType" resultType="User">select * from spring_user where id = #{id}</select><select id="listUsers" resultType="User">select * from ${tableName}</select></mapper>
执行SQL
指定命名空间与SqlId
@Testpublic void testGetStarted() throws IOException {String resource = "mybatis/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);final SqlSession sqlSession = sqlSessionFactory.openSession();User user = sqlSession.selectOne("com.example.start.springdemo.mybatis.dao.UserMapper.selectUser", 1L);System.out.println("User:" + user);User user2 = sqlSession.selectOne("com.example.start.springdemo.mybatis.dao.UserMapper.selectUserByType", 1L);System.out.println(user2);sqlSession.close();}
简单概括
使用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.
如接口定义如下:
/*** Alipay.com Inc.* Copyright (c) 2004-2020 All Rights Reserved.*/package com.example.start.springdemo.mybatis.dao;import java.util.List;import com.example.start.springdemo.mybatis.User;import org.apache.ibatis.annotations.Param;/*** @author xiele.xl* @date 2020-06-04 11:04*/public interface UserMapper {User selectUser(Long id);User selectUserByType(Long id);List<User> listUsers(@Param("tableName") String tableName);}
Mapper XML文件
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.example.start.springdemo.mybatis.dao.UserMapper"><resultMap id="UserMap" type="com.example.start.springdemo.mybatis.User"><id column="id" property="id"/><result column="name" property="name"/><result column="age" property="age"/></resultMap><select id="selectUser" resultMap="UserMap">select * from spring_user where id = #{id}</select><select id="selectUserByType" resultType="User">select * from spring_user where id = #{id}</select><select id="listUsers" resultType="User">select * from ${tableName}</select></mapper>
SqlSession.getMapper
@Testpublic void testMapper() throws IOException {String resource = "mybatis/mybatis-config.xml";InputStream inputStream = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = mapper.selectUserByType(1L);User user2 = mapper.selectUserByType(1L);System.out.println("mapper query -> " + user + user2);}
注: 通过Mapper接口调用,其底层也是获取完整的namespace+sqlId,即完整的statement
配置说明
属性(properties)
mybatis-config.xml中配置,这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:
<properties resource="org/mybatis/example/config.properties"><property name="username" value="dev_user"/><property name="password" value="F2Fa3!33TYyg"/></properties>
类型别名(typeAliases)
在mybatis-config.xml中配置,类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<typeAliases><typeAlias alias="Author" type="domain.blog.Author"/><typeAlias alias="Blog" type="domain.blog.Blog"/><typeAlias alias="Comment" type="domain.blog.Comment"/><typeAlias alias="Post" type="domain.blog.Post"/><typeAlias alias="Section" type="domain.blog.Section"/><typeAlias alias="Tag" type="domain.blog.Tag"/></typeAliases>当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:<typeAliases><package name="domain.blog"/></typeAliases>每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 domain.blog.Author 的别名为 author;若有注解,则别名为其注解值。见下面的例子:@Alias("author")public class Author {...}
Mapper文件
在mybatis-config.xml中配置。
<!-- 使用相对于类路径的资源引用 --><mappers><mapper resource="org/mybatis/builder/AuthorMapper.xml"/><mapper resource="org/mybatis/builder/BlogMapper.xml"/><mapper resource="org/mybatis/builder/PostMapper.xml"/></mappers>
这里所谓的mapper接口路径。实际上就是dao的接口路径。在mybatis中,通常把dao的包叫做mapper。类名,也叫做mapper
1、定义一个接口。
2、在接口所在的包中定义mapper.xml,并且要求xml文件和interface的名称要相同。
3、在mybatis-config.xml 中通过class路径,引入mapper(注解方式)。要求mapper.xml 中的名称空间是类的接口的全路径。
如下的方式为用注解来配置Mapper
<!-- 使用映射器接口实现类的完全限定类名 --><mappers><mapper class="org.mybatis.builder.AuthorMapper"/><mapper class="org.mybatis.builder.BlogMapper"/><mapper class="org.mybatis.builder.PostMapper"/></mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 --><mappers><package name="org.mybatis.builder"/></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为:
<select id="listUsers" resultType="User">select * from #{tableName}</select>
调用方式:
List<User> users = mapper.listUsers("spring_user");System.out.println(users);sqlSession.close();
会抛出如下异常:
Caused by: java.sql.SQLSyntaxErrorException:You have an error in your SQL syntax;check the manual that corresponds to your MySQL server versionfor the right syntax to use near ''spring_user'' at line 1
在表名上添加单引号是非法的SQL。
