Java:MyBatis动态SQL实践

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Java:MyBatis动态SQL实践

项目结构

$ tree
.
├── README.md
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── mouday
    │   │           ├── mapper
    │   │           │   ├── PersonMapper.java
    │   │           │   └── PersonMapper.xml
    │   │           ├── pojo
    │   │           │   └── Person.java
    │   │           └── util
    │   │               └── MyBatisUtil.java
    │   └── resources
    │       ├── db.properties
    │       ├── mybatis-config.xml
    │       └── sql
    │           └── person.sql
    └── test
        └── java
            └── com
                └── mouday
                    └── PersonTest.java

依赖 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mouday</groupId>
    <artifactId>mybatis-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <resources>
            <!--编译src/main/java目录下的xml文件-->
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.12</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

数据库配置

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/data
username=root
password=123456

MyBatis配置 mybatis-config.xml

<?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>
    <!-- 加载数据库配置 -->
    <properties resource="db.properties" />
    <!-- 打印sql日志 -->
    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!-- 指定整个包下的类都是别名 -->
    <typeAliases>
        <package name="com.mouday.pojo"/>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper class="com.mouday.mapper.PersonMapper"/>
    </mappers>
</configuration>

建表插入数据 person.sql

-- 建表
create table person(
    id int not null primary key auto_increment,
    name varchar(20),
    age int
);
-- 插入数据
insert into person(name, age) values('刘备', 25);
insert into person(name, age) values('关羽', 24);
insert into person(name, age) values('张飞', 23);
insert into person(name, age) values('曹操', 25);
insert into person(name, age) values('许褚', 24);
insert into person(name, age) values('孙权', 25);
insert into person(name, age) values('周瑜', 24);

工具类 MyBatisUtil.java

package com.mouday.util;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;
public class MyBatisUtil {
    private static SqlSessionFactory factory = null;
    // 使用static静态代码块,随着类的加载而加载,只执行一次
    static {
        try {
            String resource = "mybatis-config.xml";
            // 加载MyBatis的主配置文件
            InputStream inputStream = Resources.getResourceAsStream(resource);
            // 通过构建器(SqlSessionFactoryBuilder)构建一个SqlSessionFactory工厂对象
            factory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession() throws IOException {
        return factory.openSession();
    }
}

实体Person.java

package com.mouday.pojo;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class Person {
    private Integer id;
    private String name;
    private Integer age;
}

mapper接口 PersonMapper.java

package com.mouday.mapper;
import com.mouday.pojo.Person;
import java.util.List;
public interface PersonMapper {
    List<Person> selectAll();
    /**
     * 根据输入的信息进行条件检索
     * 1. 当只输入用户名时, 使用用户名进行 【模糊检索】
     * 2. 当只输入年龄时, 使用性别进行 【完全匹配】
     * 3. 当用户名和年龄都存在时, 用这两个条件进行查询匹配的用
     */
    List<Person> selectByPersonSelective(Person person);
    /**
     * 更新非空属性
     */
    int updateByPrimaryKeySelective(Person person);
    /**
     * 插入非空字段
     */
    int insertSelective(Person person);
    /**
     * 当 name 没有值时, 使用 name 进行查询
     * 否则使用 id 进行查询
     */
    List<Person> selectByNameOrId(Person person);
}

mapper映射文件 PersonMapper.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="com.mouday.mapper.PersonMapper">
    <sql id="Base_Column_List">
        id, name, age
    </sql>
    <select id="selectAll" resultType="Person">
    select
    <include refid="Base_Column_List"/>
    from person
    </select>
    <select id="selectByPersonSelective" resultType="Person" parameterType="Person">
        select
        <include refid="Base_Column_List" />
        from person
        <where>
            <if test="name != null and name !=''">
                and name like concat('%', #{name}, '%')
            </if>
            <if test="age != null">
                and age=#{age}
            </if>
        </where>
    </select>
    <update id="updateByPrimaryKeySelective" parameterType="Person">
    update person
    <set>
        <if test="name != null">
            `name` = #{name,jdbcType=VARCHAR},
        </if>
        <if test="age != null">
            `age` = #{age,jdbcType=INTEGER},
        </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
    </update>
    <insert id="insertSelective" parameterType="Person">
        insert into person
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="id != null">
                id,
            </if>
            <if test="name != null">
                `name`,
            </if>
            <if test="age != null">
                age,
            </if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">
                #{id,jdbcType=INTEGER},
            </if>
            <if test="name != null">
                #{name,jdbcType=VARCHAR},
            </if>
            <if test="age != null">
                #{age,jdbcType=INTEGER},
            </if>
        </trim>
    </insert>
    <select id="selectByNameOrId" resultType="Person" parameterType="Person">
        select
        <include refid="Base_Column_List" />
        from person
        where 1=1
        <choose>
            <when test="id != null">
                and id=#{id}
            </when>
            <otherwise>
                and name=#{name}
            </otherwise>
        </choose>
    </select>
</mapper>

测试文件PersonTest.java

package com.mouday;
import com.mouday.mapper.PersonMapper;
import com.mouday.pojo.Person;
import com.mouday.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
public class PersonTest {
    private SqlSession session;
    private PersonMapper mapper;
    @Before
    public void init() throws IOException {
        this.session = MyBatisUtil.getSqlSession();
        this.mapper = this.session.getMapper(PersonMapper.class);
    }
    @After
    public void destroy() {
        this.session.close();
    }
    @Test
    public void testSelect() {
        System.out.println(mapper.selectAll());
    }
    /**
     * 选择数据
     */
    @Test
    public void testSelectByStudentSelective() {
        Person person = new Person();
        System.out.println(mapper.selectByPersonSelective(person));
        // select id, name, age from person
        person.setName("操");
        System.out.println(mapper.selectByPersonSelective(person));
        // select id, name, age from person WHERE name like concat('%', ?, '%')
        person.setAge(25);
        System.out.println(mapper.selectByPersonSelective(person));
        // select id, name, age from person WHERE name like concat('%', ?, '%') and age=?
    }
    /**
     * 更新数据
     */
    @Test
    public void testUpdateByPrimaryKeySelective() {
        Person person = new Person();
        person.setId(1);
        person.setAge(26);
        mapper.updateByPrimaryKeySelective(person);
        // update person SET `age` = ? where id = ?
        session.commit();
        person.setName("刘禅");
        mapper.updateByPrimaryKeySelective(person);
        session.commit();
        // update person SET `name` = ?, `age` = ? where id = ?
    }
    /**
     * 插入数据
     */
    @Test
    public void testInsertSelective() {
        Person person = new Person();
        person.setName("司马懿");
        mapper.insertSelective(person);
        // insert into person ( `name` ) values ( ? )
        session.commit();
        person.setAge(26);
        mapper.insertSelective(person);
        // insert into person ( `name`, age ) values ( ?, ? )
        session.commit();
    }
    /**
     * 选择查询
     */
    @Test
    public void testSelectByNameOrId() {
        Person person = new Person();
        person.setName("司马懿");
        mapper.selectByNameOrId(person);
        // select id, name, age from person where 1=1 and name=?
        person.setId(1);
        mapper.selectByNameOrId(person);
        // select id, name, age from person where 1=1 and id=?
    }
}

Where

set 和 where 其实都是 trim 标签的一种类型

where 等价于

<trim prefix="where" prefixOverrides="AND |OR">
</trim>

表示当 trim 中含有内容时, 添加 where, 且第一个为 and 或 or 时, 会将其去掉。

而如果没有内容, 则不添加 where。

set 等价于

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

表示当 trim 中含有内容时, 添加 set, 且最后的内容为 , 时, 会将其去掉。而没有内容, 不添加 set

trim 的几个属性

prefix: 当 trim 元素包含有内容时, 增加 prefix 所指定的前缀
prefixOverrides: 当 trim 元素包含有内容时, 去除 prefixOverrides 指定的 前缀
suffix: 当 trim 元素包含有内容时, 增加 suffix 所指定的后缀
suffixOverrides:当 trim 元素包含有内容时, 去除 suffixOverrides 指定的后缀

参考

  1. 你用过Mybatis的动态SQL后,就知道写SQL有多爽了!
  2. https://mybatis.org/mybatis-3/zh/dynamic-sql.html


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
设计模式 安全 Java
Java编程中的单例模式:理解与实践
【10月更文挑战第31天】在Java的世界里,单例模式是一种优雅的解决方案,它确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的实现方式、使用场景及其优缺点,同时提供代码示例以加深理解。无论你是Java新手还是有经验的开发者,掌握单例模式都将是你技能库中的宝贵财富。
38 2
|
8天前
|
安全 Java 程序员
Java内存模型的深入理解与实践
本文旨在深入探讨Java内存模型(JMM)的核心概念,包括原子性、可见性和有序性,并通过实例代码分析这些特性在实际编程中的应用。我们将从理论到实践,逐步揭示JMM在多线程编程中的重要性和复杂性,帮助读者构建更加健壮的并发程序。
|
1月前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
27天前
|
存储 安全 Java
Java多线程编程的艺术:从基础到实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及其实现方式,旨在帮助开发者理解并掌握多线程编程的基本技能。文章首先概述了多线程的重要性和常见挑战,随后详细介绍了Java中创建和管理线程的两种主要方式:继承Thread类与实现Runnable接口。通过实例代码,本文展示了如何正确启动、运行及同步线程,以及如何处理线程间的通信与协作问题。最后,文章总结了多线程编程的最佳实践,为读者在实际项目中应用多线程技术提供了宝贵的参考。 ####
|
24天前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
28天前
|
SQL Java 数据库连接
从理论到实践:Hibernate与JPA在Java项目中的实际应用
本文介绍了Java持久层框架Hibernate和JPA的基本概念及其在具体项目中的应用。通过一个在线书店系统的实例,展示了如何使用@Entity注解定义实体类、通过Spring Data JPA定义仓库接口、在服务层调用方法进行数据库操作,以及使用JPQL编写自定义查询和管理事务。这些技术不仅简化了数据库操作,还显著提升了开发效率。
37 3
|
27天前
|
Java UED
Java中的多线程编程基础与实践
【10月更文挑战第35天】在Java的世界中,多线程是提升应用性能和响应性的利器。本文将深入浅出地介绍如何在Java中创建和管理线程,以及如何利用同步机制确保数据一致性。我们将从简单的“Hello, World!”线程示例出发,逐步探索线程池的高效使用,并讨论常见的多线程问题。无论你是Java新手还是希望深化理解,这篇文章都将为你打开多线程的大门。
|
1月前
|
存储 安全 Java
系统安全架构的深度解析与实践:Java代码实现
【11月更文挑战第1天】系统安全架构是保护信息系统免受各种威胁和攻击的关键。作为系统架构师,设计一套完善的系统安全架构不仅需要对各种安全威胁有深入理解,还需要熟练掌握各种安全技术和工具。
106 10
|
1月前
|
Java 程序员 数据库连接
Java中的异常处理:理解与实践
【10月更文挑战第29天】在Java编程的世界里,异常像是不请自来的客人,它们可能在任何时候闯入我们的程序宴会。了解如何妥善处理这些意外访客,不仅能够保持我们程序的优雅和稳健,还能确保它不会因为一个小小的失误而全盘崩溃。本文将通过浅显易懂的方式,带领读者深入异常处理的核心概念,并通过实际示例展现如何在Java代码中实现有效的异常管理策略。
|
1月前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
25 3