当前位置: 首页 > news >正文

第三阶段-03MyBatis 中使用XML映射文件详解

MyBatis 中使用XML映射文件

什么是XML映射

使用注解的映射SQL的问题:

  1. 长SQL需要折行,不方便维护
  2. 动态SQL查询拼接复杂
  3. 源代码中的SQL,不方便与DBA协作

MyBatis建议使用XML文件映射SQL才能最大化发挥MySQL的功能

  • 统一管理SQL, 方便协作
  • 不需要 “ ” + 等语法,方便“长”SQL
  • 方便处理动态SQL连接

参考连接: https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

HelloWorld

开发步骤:

  1. 创建项目(不要使用Spring Boot 3!), 选择依赖:

请添加图片描述

  1. 配置application.properties, 设置数据库连接

    spring.datasource.url=jdbc:mysql://localhost:3306/bootdb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
    spring.datasource.username=root
    spring.datasource.password=root# 设定 mapper xml 文件的位置, classpath 就是指 resources 位置
    mybatis.mapper-locations=classpath:mappers/*.xml
    # 查看MyBatis执行的SQL
    logging.level.cn.tedu.boot2209.mapper=debug
    
  2. 创建文件夹 /resources/mappers

    1. 添加一个XML文件,文件从doc.canglaoshi.org 下载

    2. 改名为 DemoMapper.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">
      <!-- namespace 的值设定为被映射的包名.类名 -->
      <mapper namespace="cn.tedu.boot2209.mapper.DemoMapper"><!-- select 元素用于映射查询语句到方法,id值必须和mapper接口中的方法名一致!需要设定返回值类型resultType,类型与方法返回值类型一致select 元素中定义SQL,SQL查询结果将自动映射到方法返回值, 不要使用分号结尾!!--><select id="hello" resultType="java.lang.String">SELECT 'Hello World!'</select>
      </mapper>
  3. 创建mapper.DemoMapper接口:

    1. 接口名和 xml文件的namespace 一致
    2. 方法名和xml文件的select元素的id一致
    3. 方法返回值类型和 resultType 的值一致
    /*** 编写Mapper接口,用于映射SQL语句*/
    @Mapper
    public interface DemoMapper {String hello();
    }
    
  4. 编写MyBatis配置文件 config.MyBatisConfig

    1. 包名、文件名,没有限制!
    2. 文件中使用 MapprScan 扫描 Mapper包:
    
    /*** 创建一个配置文件,MyBatisConfig* 在配置文件中,启动Mapper接口扫描功能* Mapper 接口扫描功能会自动创建 Mapper接口的实现对象(使用的JDK动态代理技术)*/
    @MapperScan(basePackages = "cn.tedu.boot2209.mapper")
    @Configuration
    public class MyBatisConfig {
    }
    
  5. 测试案例: 测试结果说明,SQL被执行了,方法返回了SQL语句的结果

    @SpringBootTest
    public class DemoMapperTests {@AutowiredDemoMapper demoMapper;@Testvoid test(){String str = demoMapper.hello();System.out.println(str);}
    }
    

Spring Boot 中的配置类(配置文件)

@Configuration 用于声明新的配置文件类。

Spring Boot 中的主配置文件,就是Spring Boot 的启动类,可以作为配置文件使用。如果将全部配置信息放到主配置文件,就会很混乱。一般在开发中,将配置文件分开放置,相关的放到一起。

  • MyBatis 放到一个文件中
  • 安全配置放到一个文件中
  • … …

创建一个配置包 config 管理全部的配置,然后创建MyBatis的配置类, 配置类需要标注 @Configuration

/*** 创建一个配置文件,MyBatisConfig* 在配置文件中,启动Mapper接口扫描功能* Mapper 接口扫描功能会自动创建 Mapper接口的实现对象(使用的JDK动态代理技术)*/
@MapperScan(basePackages = "cn.tedu.boot2209.mapper")
@Configuration
public class MyBatisConfig {
}

MyBatis XML映射文件工作原理

请添加图片描述

关于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="cn.tedu.boot2209.mapper.ProductMapper"><select id="countProduct" resultType="java.lang.Integer">SELECT COUNT(*) FROM product</select>
</mapper>
  • 处理节点: <?xml version="1.0" encoding="UTF-8" ?> 从来没有变过!
    • 可以省略,但是不建议省略!
  • 文档定义: ”DOCTYPE“ 用于约定XML文件中的 元素、属性、嵌套关系
    • 可以约束标签和属性
  • 标签/标记: <mapper>
    • 必须成对使用,有开启标签就必须结束标签: <mapper></mapper>
  • 开始标签上可以定义属性: id="countProduct"
    • 属性名不可以重复,属性无顺序
  • XML文件只能有唯一的根元素!!!
  • XML 可扩展的标记语言:
    • 标签可以任意名称,标签名可以扩展
    • 标签嵌套关系可以扩展,标签可以任意嵌套
    • 属性可以扩展
  • XML 中大小写敏感,不同!

有参数的查询

处理一个参数查询

例子:

SELECT count(*) FROM product WHERE price > ?

请添加图片描述

处理多个参数查询

请添加图片描述

处理实体类型返回值

使用 Product 实体类作为返回值, 在resultType上指定实体类型就可以了

请添加图片描述

desc product;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | int(11)      | NO   | PRI | NULL    | auto_increment |
| title | varchar(50)  | YES  |     | NULL    |                |
| price | double(10,2) | YES  |     | NULL    |                |
| num   | int(11)      | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+

定义实体类型 Product

/*** 产品实体类型*/
public class Product {private Integer id;private String title;private Double price;private Integer quantity; //数量public Product() {}public Product(Integer id, String title, Double price, Integer quantity) {this.id = id;this.title = title;this.price = price;this.quantity = quantity;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}public Integer getQuantity() {return quantity;}public void setQuantity(Integer quantity) {this.quantity = quantity;}@Overridepublic String toString() {return "Product{" +"id=" + id +", title='" + title + '\'' +", price=" + price +", quantity=" + quantity +'}';}
}

编写ProductMapper接口方法

/*** 根据ID返回一个对象*/
Product findById(Integer id);

编写映射文件 ProductMapper.xml

<select id="findById" resultType="cn.tedu.boot2209.entity.Product">SELECT id, title, price, num AS quantityFROM productWHERE id = #{id}
</select>

测试:ProductMapperTests

@Test
void findById(){Product product = productMapper.findById(4);System.out.println(product);
}

返回实体集合

在ProductMapper接口中添加方法:

/*** 返回一组实体对象* @param title %手机* @return 匹配的一组对象*/
List<Product> findByTitle(String title);

在 ProductMapper.xml 添加SQL语句:

<!-- 返回一组实体对象,必须有 resultType 值是返回集合中的元素类型-->
<select id="findByTitle" resultType="cn.tedu.boot2209.entity.Product">SELECT id, title, price, num AS quantityFROM productWHERE title LIKE #{title}
</select>

测试方法 ProductMapperTests

@Test
void findByTitle(){List<Product> products = productMapper.findByTitle("%手机");for (Product  product : products){System.out.println(product);}
}

插入和更新

使用变量传递参数

参数少,没有问题,但是参数多了以后就麻烦了,书写繁琐复杂

插入数据SQL:

INSERT INTO product (id, title, price, num ) VALUES (null, ?, ? ,?)

ProductMapper接口:插入、更新、删除方法只有一个默认返回int值,表示SQL影响行数

Integer saveProduct(@Param("title") String title,@Param("price") Double price,@Param("quantity") Integer quantity);

在MyBatis ProductMapper.xml:

<!-- insert 插入语句不需要定义 resultType,默认就有int返回值 -->
<insert id="saveProduct">INSERT INTO product (id, title, price, num ) VALUES (null, #{title}, #{price}, #{quantity})
</insert>

测试:ProductMapperTests

@Test
void saveProduct(){Integer n = productMapper.saveProduct("大力手机", 2000.0, 100);System.out.println(n);
}

使用POJO对象打包传递参数

POJO 就是传统Java对象,实体对象 Product 对象就是 POJO。

请添加图片描述

使用POJO对象作为Mapper方法参数: ProductMapper, 无需定义@Parm

Integer saveProductItem(Product product);

MyBatis 自动将POJO对象的属性, 映射传递到 #{占位符}

<!-- MyMatis 会自动的将 product 的属性 映射到#{title}, #{price}, #{quantity}要求 #{title}, #{price}, #{quantity} 占位符必须和 product 的属性(getXXX)一致-->
<insert id="saveProductItem">INSERT INTO product (id, title, price, num ) VALUES (null, #{title}, #{price}, #{quantity})
</insert>

测试

@Test
void saveProductItem(){Product product = new Product(null, "大力手机", 2000.0, 100);Integer n = productMapper.saveProductItem(product);System.out.println(n);
}

返回自动增加的ID

使用POJO作为参数插入数据时候,可以返回自增的ID:

  • useGeneratedKeys=“true” 使用生成的key
  • keyProperty=“id” key 的属性名
<!-- useGeneratedKeys="true"  使用生成的keykeyProperty="id" key 的属性名 -->
<insert id="saveProductItem" useGeneratedKeys="true" keyProperty="id">INSERT INTO product (id, title, price, num)VALUES (null, #{title}, #{price}, #{quantity})
</insert>

测试:

@Test
void saveProductItem(){Product product = new Product(null, "他的手机", 3000.0, 100);Integer n = productMapper.saveProductItem(product);System.out.println(n);System.out.println(product); //输出刚刚生成的 ID
}

更新数据 update

更新数据 SQL, 更新一行的全部数据:

UPDATE product SET title=?, price=?, num=? WHERE id=?

ProductMapper接口:

Integer updateProduct(Product product);

ProductMapper.xml:

<update id="updateProduct">UPDATE product SET title=#{title}, price=#{price}, num=#{quantity} WHERE id=#{id}
</update>

测试:

@Test
void updateProduct(){Product product = new Product(12, "老虎的手机", 100.99, 10);Integer num = productMapper.updateProduct(product);System.out.println(product);System.out.println(num);
}

MyBatis 动态SQL拼接

根据参加参数条件动态生成SQL,提示SQL效率。

动态SQL标签: if choose when for 等

/*** 动态SQL更新* @param product* @return*/
Integer updateProductPart(Product product);

XML:

<!-- 检查参数,动态拼接SQL -->
<!-- test="title != null" 检查title不为空,这拼接一段SQL title=#{title}<set> 标签会自动删除多余的逗号 -->
<update id="updateProductPart">UPDATE product<set><if test="title != null">title=#{title},</if><if test="price != null">price=#{price},</if><if test="quantity != null">num=#{quantity}</if></set>WHERE  id = #{id}
</update>

测试:

@Test
void updateProductPart(){Product product = new Product(10, null, 1500.0, null);Integer num = productMapper.updateProductPart(product);System.out.println(product);System.out.println(num);//一定要检查 SQL 处理结果!不是1,就是更新失败!!
}
http://www.lryc.cn/news/22712.html

相关文章:

  • 从0开始学python -41
  • 如何将Google浏览器安装到D盘(内含教学视频)
  • 三战阿里测试岗,成功上岸,面试才是测试员涨薪真正的拦路虎...
  • Java代码弱点与修复之——ORM persistence error(对象关系映射持久错误)
  • 原始GAN-pytorch-生成MNIST数据集(原理)
  • Vue下载安装步骤的详细教程(亲测有效) 1
  • [Android Studio] Android Studio生成数字证书,为应用签名
  • 应用IC 卡继续教育网络管理系统前后影响因素比较
  • Clickhouse学习(一):MergeTree概述
  • Windows离线安装rust
  • Android与flutter混合开发
  • Linux和C语言的学习方法你真的知道吗?
  • 代码随想录day42
  • 【笔记】两台1200PLC进行S7 通信(1)
  • 统一网关Gateway
  • 6、kubernetes(k8s)安装
  • python-批量下载某短视频平台音视频标题、评论、点赞数
  • 【数据结构与算法】单链表的增删查改(附源码)
  • 华为OD机试 - 回文字符串
  • C语言太简单?这14道C语言谜题,你能答对几个
  • Benchmark测试——fio——源码分析
  • 测量 R 代码运行时间的 5 种方法
  • Qt 第9课、计算器中缀转后缀算法
  • docker的使用方法
  • Kafka(五)生产者向发送消息的执行流程
  • 华为OD机试模拟题 用 C++ 实现 - 简易压缩算法(2023.Q1)
  • MATLAB R2022b 安装教程
  • PCI子系统
  • Spring源码之IoC容器的Bean创建和依赖注入,DefaultListableBeanFactory容器为例
  • 解决小程序页面scroll-view块自身滑动问题