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

news2024/12/27 2:18:08

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 mapper
        PUBLIC "-//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 {
    
        @Autowired
        DemoMapper demoMapper;
    
        @Test
        void 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 mapper
  PUBLIC "-//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;
    }

    @Override
    public 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 quantity
    FROM product
    WHERE 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 quantity
    FROM product
    WHERE 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"  使用生成的key
     keyProperty="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.coloradmin.cn/o/374495.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【工程实践】python 去除\xa0、\u3000、\n、\u2800、\t等字符

1.问题描述 在处理数据时&#xff0c;会遇到\xa0、\u3000、\u2800、\t等Unicode字符串。需要对其进行处理。 2.空格类型说明 空格可以分为两类&#xff0c;一类为普通文本空格&#xff0c;另一类为html实体空格。普通文本空格介绍普通半角空格和普通全角空格。html实体空格介绍…

【反序列化漏洞-01】为什么要序列化

为什么要序列化百度百科上关于序列化的定义是&#xff0c;将对象的状态信息转换为可以存储或传输的形式(字符串)的过程。在序列化期间&#xff0c;对象将其当前状态写入到临时或持久性存储区(非关系型键值对形式的数据库Redis&#xff0c;与数组类似)。以后&#xff0c;可以通过…

浅谈信安文章搜索引擎

一个搜索引擎的实现流程大概为&#xff1a;首先获取海量的数据&#xff0c;整理成统一的格式&#xff0c;然后交给索引程序建立索引&#xff0c;当索引建立好后&#xff0c;就可以进行搜索。简而言之就是&#xff1a;数据获取->数据检索->数据搜索 0x1数据获取 数据获取…

RK3399+FPGA+MIPI 方案细节之subLVDS to MIPI处理

#CROSSLINK系列 #CROSSLINK vs XO3L 总的来说XO3L的灵活性更强&#xff0c;更近似于一片通用的CPLD&#xff1b;CROSSLINK专用性更强。 针对subLVDS转换到MIPI的需求&#xff0c;CROSSLINK比较有优势&#xff0c;因为集成度更高&#xff0c;所以稳定性也更高。 #要点 #crossl…

死锁的总结

哲学家死锁造成的原因&#xff1a;我有你需要的&#xff0c;但你已经有了 饥饿与死锁的区别 死锁一旦发生一定又饥饿现象&#xff0c;但是饥饿现象产生不一定是死锁 历史上对于死锁的声音 死锁的方案 前面两个都是不允许死锁出现 前面都是概念性的东西 后面我们研究如何破坏…

【vue】vuex数据丢失怎么办?盘一盘vue传值的方法

【问题描述】 vuex的 store 中的数据是保存在运行内存中的&#xff0c;当页面刷新时&#xff0c;页面会重新加载 vue 实例&#xff0c;vuex 里面的数据就会被重新赋值&#xff0c;这样就会出现页面刷新vuex中的数据丢失的问题。 如何解决浏览器刷新数据丢失问题呢&#xff1f; …

Java-Springboot整合支付宝接口

文章目录一、创建支付宝沙箱二、使用内网穿透 nat app三、编写java程序四、访问一、创建支付宝沙箱 跳转 &#xff1a; 支付宝沙箱平台 1、进入控制台 2、创建小程序&#xff0c;编写名称和绑定商家即可 3、返回第一个页面&#xff0c;往下滑进入沙箱 4、进行相关的配置&a…

git push -u参数是什么意思?

背景 git push的时候&#xff0c;有时候会用-u参数&#xff0c;有时候不适用。这是为什么呢&#xff1f; 官方解释 -u--set-upstreamFor every branch that is up to date or successfully pushed, add upstream (tracking) reference, used by argument-less git-pull(1) a…

【 Java 组 】蓝桥杯省赛真题 [世纪末的星期] [幸运数] (持续更新中...)

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 蓝桥杯真题--持续更新中...一、世纪末的星期二…

【设计模式】策略模式在Java工程中应用

在之前的文章中&#xff0c;曾经给大家介绍过策略模式&#xff1a;【设计模式】策略模式&#xff0c;在该篇文章中&#xff0c;我们曾很清楚的说到&#xff0c;策略模式主要解决的问题是&#xff1a;在有多种算法相似的情况下&#xff0c;解决使用 if...else 所带来的复杂和难以…

【Spring从成神到升仙系列 一】2023年再不会动态代理,就要被淘汰了

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙…

BingGPT 国内中转

BingGPT 国内中转 本项目的github地址 本项目最上层是提供一个使用BingGPT的web接口&#xff0c;仅供学习&#xff0c;如有侵权请联系作者。 预先准备&#xff1a; 一个可以访问bingGPT的外网服务器&#xff08;可在tencent cloud 选购)一个在已经注册new_bing_list的账号 …

泰克示波器MD03012-一款高性能、高可靠性的仪器

泰克示波器MD03012是一款常见的仪器&#xff0c;以其出色的性能和高可靠性被广泛应用于电子工程、教学演示等领域。它采用先进的电子技术&#xff0c;具有高精度、高灵敏度和高可靠性等特点&#xff0c;能够满足工程师们在实际工作中的要求。泰克示波器MD03012拥有一套强大的功…

华为OD机试题,用 Java 解【数组排序】问题

最近更新的博客 华为OD机试题,用 Java 解【停车场车辆统计】问题华为OD机试题,用 Java 解【字符串变换最小字符串】问题华为OD机试题,用 Java 解【计算最大乘积】问题华为OD机试题,用 Java 解【DNA 序列】问题华为OD机试 - 组成最大数(Java) | 机试题算法思路 【2023】使…

Clickhouse学习(二):MergeTree存储结构

MergeTree一、MergeTree逻辑存储结构二、MergeTree物理存储结构三、总结一、MergeTree逻辑存储结构 如上图所示,在排序键(CountrID、Date)上做索引,数据会按照这两个字段先后排序ClickHouse是稀疏索引,每隔8192行做一个索引,如(a,1),(a,2),比如想查a,要读取[0,3)之间的内容,稀疏…

Python安装教程(附带安装包)

首先&#xff0c;打开python安装包的下载地址&#xff0c;https://www.python.org/downloads/&#xff0c;会有些慢 点击downloads中的windows 左侧是稳定的版本&#xff0c;我这边下的是3.8的&#xff0c;不想去官网下载的可以直接用我下载的这个3.8版本&#xff0c;https://…

隐私计算头条周刊(2.20-2.26)

开放隐私计算收录于合集#企业动态45个#周刊合辑45个#政策聚焦38个#隐私计算92个#行业研究37个开放隐私计算开放隐私计算OpenMPC是国内第一个且影响力最大的隐私计算开放社区。社区秉承开放共享的精神&#xff0c;专注于隐私计算行业的研究与布道。社区致力于隐私计算技术的传播…

Reids实战—黑马点评(三)秒杀篇

Reids实战—黑马点评&#xff08;三&#xff09;秒杀篇 来自黑马的redis课程的笔记 【黑马程序员Redis入门到实战教程&#xff0c;深度透析redis底层原理redis分布式锁企业解决方案黑马点评实战项目】 目录Reids实战—黑马点评&#xff08;三&#xff09;秒杀篇一、全局唯一I…

改进的 A*算法的路径规划(路径规划+代码+毕业设计)

引言 近年来&#xff0c;随着智能时代的到来&#xff0c;路径规划技术飞快发展&#xff0c;已经形成了一套较为成熟的理论体系。其经典规划算法包括 Dijkstra 算法、A算法、D算法、Field D算法等&#xff0c;然而传统的路径规划算法在复杂的场景的表现并不如人意&#xff0c;例…

一些cmake error fixed

建完虚拟环境后 运行 pip install . 出现报错&#xff0c;显示svox2安装出错&#xff0c;然后开始进入到svox2中进行手动编译和安装。 1. cmake svox2/csrc pybind11找不到 conda install pybind11用 pip install 在虚拟环境中安装不行&#xff0c;据说会安装到全局下… 2. c…