【SSM】MyBatis

2023-12-20 14:41:17

MyBatis

1. 简介

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

2. 使用流程

  1. 导入依赖
<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.11</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.3.1</version>
    </dependency>
</dependencies>
  1. 定义 mapper类及对应 xml 文件
public interface StuMapper {
	Stu selectOne(Integer id);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.mapper.StuMapper">
    <select id="selectOne" resultType="com.mybatis.pojo.Stu">
        select * from stu where id = #{args0}
    </select>
</mapper>
  1. 配置 MyBatis 配置文件
<?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="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/niuke"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mappers/StuMapper.xml"/>
    </mappers>
</configuration>
  1. 运行和测试
	@Test
	public void tryTest() throws IOException {

		String mybatisConfigFilePath = "mybatis-config.xml";
		InputStream inputStream = Resources.getResourceAsStream(mybatisConfigFilePath);
		SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

		SqlSession session = sessionFactory.openSession();
		StuMapper stuMapper = session.getMapper(StuMapper.class);
		Stu stu = stuMapper.selectOne(1);
		System.out.println("stu = " + stu);

		session.commit(); //提交事务 [DQL不需要,其他需要]
		session.close(); //关闭会话
	}

3. 基本使用

3.1 配置文件

MyBatis配置文件设计标签和顶层结构如下:配置 MyBatis 配置文件时需按如下顺序及层级配置

  • configuration(配置)
    • properties(属性):用于配置属性,一般指定 resource 路径直接读取文件
    • settings(设置):配置 MyBatis 缓存,主键,日志 logImpl ,驼峰命名 mapUnderscoreToCamelCase
    • typeAliases(类型别名):一般指定包路径,则会包下类都会以首字母小写的非全限定类名作为别名,部分常用类已经定义了别名,如 byte、long 等
    • typeHandlers(类型处理器):java类型与数据库数据类型转换使用,一般使用默认的即可
    • objectFactory(对象工厂):默认即可。每次 MyBatis 创建结果对象的新实例时,它都会使用一个对象工厂(ObjectFactory)实例来完成实例化工作。
    • plugins(插件):较常使用的即 pageHelper 分页插件
    • environments(环境配置)
      • environment(环境变量)
        • transactionManager(事务管理器):一般用 “JDBC”
        • dataSource(数据源):一般类型用 “POOLED”
    • databaseIdProvider(数据库厂商标识)
    • mappers(映射器):指定 xml 文件位置,一般采取 package 的方式

上面各字段配置具体可参考官网,很详细 https://mybatis.net.cn/configuration.html

3.2 SQL语句传参

  • #{} 形式传参:Mybatis会将SQL语句中的 #{} 转换为问号占位符,一般用该形式,可以防止SQL注入
  • ${} 形式传参:底层Mybatis做的是字符串拼接操作,当上面格式无法使用时,才使用该格式,如表名、列名或关键字

3.2 数据输入

这里数据输入具体是指上层方法(例如Service方法)调用Mapper接口时,数据传入的形式。

  • 简单类型:基础数据类型及其包装类,还有 String
  • 复杂类型:除简单数据类型以为的类,如实体类,集合,数组,复合类型

3.2.1 单个简单类型参数

单个简单类型参数,在 #{} 中可以随意命名,但是没有必要。通常还是使用和接口方法参数同名。

Stu selectOne(Integer id);
<select id="selectOne" resultType="com.mybatis.pojo.Stu">
    select * from stu where id = #{id}
</select>

3.2.2 多个简单类型数据

多个简单类型参数,如果没有特殊处理,那么Mybatis无法识别自定义名称:故一般需使用 @Param 注解,指定名称

List<Stu> selectList(@Param("name") String name, @Param("age") Integer age);
<select id="selectList" resultType="com.mybatis.pojo.Stu">
    select * from stu where name = #{name} and age = #{age}
</select>

当然,也可使用 arg0, arg1 ... argnparam1, param2 ... paramn 表示第 1 , 2 ... n 个参数

3.2.3 实体类类型参数

Mybatis会根据 #{} 中传入的数据,加工成 getXxx() 方法,通过反射在实体类对象中调用这个方法,从而获取到对应的数据。填充到 #{} 解析后的问号占位符这个位置。

int insert(Stu stu);
<insert id="insert">
    insert into stu(name, age) values(#{name}, #{age})
</insert>

3.2.4 Map类型参数

#{} 中写Map中的key 即可。

int update(Map<String, Object> map);
<update id="update">
    update stu set name = #{name} where id = #{id}
</update>

3.3 数据输出

数据输出总体上有两种形式:

  • 增删改操作返回的受影响行数:直接使用 intlong 类型接收即可
  • 查询操作的查询结果

3.3.1 resultType指定输出类型

使用 resultType 指定查询返回值类型即可,resultType="全限定符 | 别名 | 集合类型写泛型类型"

int selectCount();
<select id="selectCount" resultType="int">
    select count(*) from stu
</select>

关于别名https://mybatis.net.cn/configuration.html#typeAliases ,可在配置文件中配置别名包扫描,同时MyBatis也为常见的Java类型内建了一些类型别名。

3.3.2 返回实体类对象注意点

  1. 如果 Java 类型属性值与数据库字段名称不符,可通过 sql 语句的 as 别名,将名字改为一致;也可使用 resultMap 属性,配置对应 resultMap
  2. 通过配置 mapUnderscoreToCamelCase=true 将自动映射数据库带下划线名称的字段,映射上 Java 实体中首字母小写的驼峰式命名
  3. 关于实体类属性的约定:getXxx() 方法、setXxx() 方法把方法名中的 getset 去掉,首字母小写

resultMap定义及使用:

<resultMap id="stuMap" type="com.mybatis.pojo.Stu">
    <id property="id" column="id" />
    <result property="name" column="name" />
    <result property="age" column="age" />
</resultMap>
<select id="selectOne" resultMap="stuMap">
    select * from stu where id = #{id}
</select>

3.3.3 返回主键值

  1. 返回自增类型主键 :使用 useGeneratedKeys="true" keyProperty="id" 属性
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
    insert into stu(name, age) values(#{name}, #{age})
</insert>
  1. 返回非自增长类型主键 :使用 <selectKey> 标签
<insert id="insertUser" parameterType="User">
    <selectKey keyProperty="id" resultType="java.lang.String" order="BEFORE">
        SELECT UUID() as id
    </selectKey>
    INSERT INTO stu (id, username, age) VALUES ( #{id}, #{username}, #{age} )
</insert>

3.4 mapper.XML标签总结

select 元素允许配置很多属性来配置每条语句的行为细节

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。

insert, update 和 delete标签:

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段),默认值:false。
keyProperty(仅适用于 insert 和 update)指定能够唯一识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)。如果生成列不止一个,可以用逗号分隔多个属性名称。
keyColumn(仅适用于 insert 和 update)设置生成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列不是表中的第一列的时候,是必须设置的。如果生成列不止一个,可以用逗号分隔多个属性名称。

4. 多表映射

关联关系配置项关键词所在配置文件和具体位置
对一association标签/javaType属性/property属性Mapper配置文件中的resultMap标签内
对多collection标签/ofType属性/property属性Mapper配置文件中的resultMap标签内

对一映射:使用 <association> 标签,property 属性指定属性名,javaType 指定对应类型

@Data
public class Order {
  private Integer orderId;
  private String orderName;
  private Customer customer;// 对一的关系
}
<resultMap id="selectOrderWithCustomerResultMap" type="order">
  <id column="order_id" property="orderId"/>
  <result column="order_name" property="orderName"/>
  <!-- 使用association标签配置“一对一”关联关系 -->
  <!-- property属性:在Order类中对一的一端进行引用时使用的属性名 -->
  <!-- javaType属性:一的一端类的全类名 -->
  <association property="customer" javaType="customer">
    <!-- 配置Customer类的属性和字段名之间的对应关系 -->
    <id column="customer_id" property="customerId"/>
    <result column="customer_name" property="customerName"/>
  </association>
</resultMap>

对多映射:使用 <collection> 标签,property 属性指定属性名,ofType 指定泛型类型

@Data
public class Customer {
  private Integer customerId;
  private String customerName;
  private List<Order> orderList;// 对多的关系
}  
<resultMap id="selectCustomerWithOrderListResultMap"type="customer">
  <id column="customer_id" property="customerId"/>
  <result column="customer_name" property="customerName"/>
  <!-- collection标签:映射“对多”的关联关系 -->
  <!-- property属性:在Customer类中,关联“多”的一端的属性名 -->
  <!-- ofType属性:集合属性中元素的类型 -->
  <collection property="orderList" ofType="order">
    <!-- 映射Order的属性 -->
    <id column="order_id" property="orderId"/>
    <result column="order_name" property="orderName"/>
  </collection>
</resultMap>

多表映射优化:设置 autoMappingBehavior 属性为 FULL

setting属性属性含义可选值默认值
autoMappingBehavior指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。NONE, PARTIAL, FULLPARTIAL

autoMappingBehavior 设置为 full ,进行多表 resultMap 映射的时候,可以省略符合列和属性命名映射规则(列名=属性名,或者开启驼峰映射也可以自定映射)的 result 标签

修改 mybati-sconfig.xml

<!--开启resultMap自动映射 -->
<setting name="autoMappingBehavior" value="FULL"/>
<resultMap id="selectCustomerWithOrderListResultMap"type="customer">
  <id column="customer_id" property="customerId"/>
  <!-- 开启自动映射,并且开启驼峰式支持,可以省略 result -->
  <!-- <result column="customer_name" property="customerName"/> -->
  <collection property="orderList" ofType="order">
    <id column="order_id" property="orderId"/>
    <!-- <result column="order_name" property="orderName"/> -->
  </collection>
</resultMap>

5. 动态语句

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

  1. where 标签:where 标签结合 if 标签使用会自动去掉“标签体内前面多余的 and/or
  2. if 标签:有选择的加入SQL语句,当判断结果为 true 时才执行该标签内语句
  3. set 标签:使用set标签动态管理set子句,标签内会自动去掉两端多余的逗号
  4. choose/when/otherwise 标签:类似于 Java中的 switch 语句,用 choose 包裹逻辑判断代码,根据条件从上到下判断,执行第一个满足条件 when 的分支,没有则执行 otherwise
  5. foreach 标签:遍历集合,批量插入或根据一些条件查询经常用到,批量更新需要注意在jdbc.url 添加 allowMultiQueries=true 参数
    • collection 属性:要遍历的集合
    • item 属性:遍历集合的过程中的每一个具体对象
    • separator 属性:指定当 foreach 标签的标签体重复拼接字符串时,各个标签体字符串之间的分隔符
    • open 属性:指定整个循环把字符串拼好后,字符串整体的前面要添加的字符串
    • close 属性:指定整个循环把字符串拼好后,字符串整体的后面要添加的字符串
    • index 属性:这里起一个名字,便于后面引用。遍历List集合,这里能够得到List集合的索引值;遍历Map集合,这里能够得到Map集合的key
  6. sqlinclude 抽取重复 sql 片段:用 sql 标签定义 sql 片段,include 标签引用 sql 片段

6. 配置文件批量映射优化

在 3.1 中配置 mappers 映射器时采用 package 方法,这个包下所有 Mapper 配置文件将被自动加载、注册。

<mappers>
    <package name="com.mybatis.mapper"/>
</mappers>

要求 Mapper 接口和 Mapper 配置文件名称一致,且 Mapper 接口与 Mapper 配置文件编译后的文件都在指定包下

7. 插件机制及分页插件PageHelper

7.1 插件机制

MyBatis 对插件进行了标准化的设计,并提供了一套可扩展的插件机制。插件可以在用于语句执行过程中进行拦截,并允许通过自定义处理程序来拦截和修改 SQL 语句、映射语句的结果等。

具体来说,MyBatis 的插件机制包括以下三个组件:

  1. Interceptor(拦截器):定义一个拦截方法 intercept,该方法在执行 SQL 语句、执行查询、查询结果的映射时会被调用。
  2. Invocation(调用):实际上是对被拦截的方法的封装,封装了 Object targetMethod methodObject[] args 这三个字段。
  3. InterceptorChain(拦截器链):对所有的拦截器进行管理,包括将所有的 Interceptor 链接成一条链,并在执行 SQL 语句时按顺序调用。

插件的开发非常简单,只需要实现 Interceptor 接口,并使用注解 @Intercepts 来标注需要拦截的对象和方法,然后在 MyBatis 的配置文件中添加插件即可。

7.2 分页插件PageHelper

详细文档可看:https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.md

这里提供基本使用参考:

  1. 导入依赖
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.11</version>
</dependency>
  1. MyBatis配置文件中配置分页插件
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="helperDialect" value="mysql"/>
    </plugin>
</plugins>
  1. 分页插件的使用
PageHelper.startPage(2, 4);
PageInfo<Stu> pageInfo = new PageInfo<>(stuMapper.selectPage()); // List<Stu> selectPage();
System.out.println(pageInfo);

8. 逆向工程

MyBatis 的逆向工程是一种自动化生成持久层代码和映射文件的工具,它可以根据数据库表结构和设置的参数生成对应的实体类、Mapper.xml 文件、Mapper 接口等代码文件,简化了开发者手动生成的过程。逆向工程使开发者可以快速地构建起 DAO 层,并快速上手进行业务开发。

MyBatis 的逆向工程有两种方式:通过 MyBatis Generator 插件实现和通过 Maven 插件实现。无论是哪种方式,逆向工程一般需要指定一些配置参数,例如数据库连接 URL、用户名、密码、要生成的表名、生成的文件路径等等。

注意:逆向工程只能生成单表crud的操作,多表查询依然需要我们自己编写

这里提供一种使用插件实现逆向工程的方法:逆向工程插件MyBatisX

  1. 首先在 idea 中下载并安装插件,注意要 apply 才能生效
  2. 配置 idea database,在idea的右侧

在这里插入图片描述

  1. 选中要逆向的表进行逆向,可选多个

在这里插入图片描述

  1. 按需求填写并最后生成即可

文章来源:https://blog.csdn.net/xxx1276063856/article/details/135104858
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。