第三阶段-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 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,就是更新失败!!
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值