Mybatis之Mapper代理开发

简介: Mybatis之Mapper代理开发

🍎道阻且长,行则将至。🍓


@Toc


一、Mapper概述

通用Mapper都可以极大的方便开发人员。可以随意的按照自己的需要选择通用方法,还可以很方便的开发自己的通用方法。
参考gitee:MyBatis 通用 Mapper4

1.Mapper代理开发

之前我们写的Mybatis代码是基本使用方式,【参考Mybatis快速入门】,它存在硬编码的问题,例如执行sql:sqlSession.selectList("test.selectAll");,传递的字符串参数是映射配置文件中的 namespace.id值,这样写不便于后期的维护。如果使用 Mapper 代理方式则不存在硬编码问题。

2.Mapper开发流程

准备

新建一个Maven项目:
image.png

一个module已建立好:
image.png

在main的java里面创建好你的包mybatis,在这个包下面可以再建立2个包,一个存放你的mapper接口,一个创建一个类来存储我们后面用于接收数据。同时在resource里面建立一个和mapper同样结构的文件目录,里面存放SQL映射文件,这个文件名称要和mapper接口一致
image.png

然后在mapper里面新建一个接口,查询所有数据的例子:

package mybatis.mapper;
import mybatis.pojp.Brand;
import java.util.List;
public interface BrandMapper {
    List<Brand> selectAll();
}

继续编写我们的mapper xml文件,也就是SQL映射文件。namespace是对应接口相对于source的目录+名称, resultType是对应类的目录名称,当在mybatis的配置文件中设置好给类起别名映射,就也可以直接不区分大小写写类名了。

<?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="mybatis.mapper.BrandMapper">
    <select id="selectAll" resultType="brand">
        select *
            from tb_brand;
    </select>
</mapper>
<!-- mybatis的配置文件中设置好给类起别名映射-->
<typeAliases>
        <package name="mybatis.pojp"/>
 </typeAliases>

image.png

至此Mapper的前置文件部分准备好了。

==如果Mapper接口名称和SQL映射文件名称相同,并在同一目录下,则可以使用包扫描的方式简化SQL映射文件的加载。也就是将核心配置文件的加载映射配置文件的配置修改为:==

<mappers>
    <!--加载sql映射文件-->
    <!-- <mapper resource="com/itheima/mapper/UserMapper.xml"/>-->
    <!--Mapper代理方式-->
    <package name="com.itheima.mapper"/>
</mappers>

实现查询

我们可以在test里面建立我们测试项目:mybatis/test/MyBatisTest.java。使用了代理mapper之后我们执行SQL的代码就从字符串参数"test.selectAll"变为UserMapper.class了。
sqlSession.selectList("test.selectAll");—>sqlSession.getMapper(UserMapper.class);

public static void main(String[] args) throws IOException {

    //1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2. 获取SqlSession对象,用它来执行sql
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //3. 执行sql
    //3.1 获取UserMapper接口的代理对象
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = userMapper.selectAll();

    System.out.println(users);
    //4. 释放资源
    sqlSession.close();
}

二、Mybatis-CRUD

这一节我们使用映射配置文件实现CRUD操作,也就是增删改查操作。
create table tb_brand
(
    id           int primary key auto_increment,
    brand_name   varchar(20),
    company_name varchar(20),
    ordered      int,
    description  varchar(100),
    -- 状态:0:禁用  1:启用
    status       int
);

继续上一节的内容,我们操作一个这样的数据表。

0.编辑类Brand

上一节我们在pojp包下创建了 Brand 实体类。我们根据数据表编辑对应的参数:

public class Brand {
    private Integer id;
    private String brandName;
    private String companyName;
    private Integer ordered;
    private String description;
    private Integer status;
}

1.查询所有数据

  • 编写接口方法:
List<Brand> selectAll();
  • 编写SQL
    <select id="selectAll" resultType="brand">
        select *
            from tb_brand;
    </select>
  • 测试代码

在测试项目mybatis/test/MyBatisTest.java中开始我们的测试代码。我们可以使用@Test注解。

    @Test
    public void testSelectAll() throws IOException {
        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 获取Mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        
        //4. 执行方法
        List<Brand> brands = brandMapper.selectAll();
        System.out.println(brands);

        //5. 释放资源
        sqlSession.close();

    }

成功运行测试:
image.png

写到这里,我们会发现使用mapper代理后面只需要==操作三个文件内容==,
image.png

其实在测试方法里面我们需要修改的也只是执行方法,在后面会有具体体现。

但是在这里我们发现一个问题,就是打印出来的内容有一些是null,但是数据库里面的表是存在数据的。还有注意是不是写了tostring。从打印结果可以看到 brandNamecompanyName 这两个属性的数据没有封装成功,查询 实体类 和 表中的字段 发现,是因为他们的名称不一致,这个问题可以通过两种方式进行解决

1.给字段**起别名**;
2.使用resultMap定义字段和属性的**映射关系**。
  • 起别名

写sql语句时给这两个字段起别名,将别名定义成和属性名一致:

<select id="selectAll" resultType="brand">
    select
    id, brand_name as brandName, company_name as companyName, ordered, description, status
    from tb_brand;
</select>

SQL语句中一大串的内容很麻烦也不美观,Mybatis提供了sql 片段可以提高sql的复用性。id属性值是唯一标识,后面通过该值进行引用。

<sql id="brand_column">
    id, brand_name as brandName, company_name as companyName, ordered, description, status
</sql>

原sql语句引用 id="selectAll"

<select id="selectAll" resultType="brand">
    select
    <include refid="brand_column" />
    from tb_brand;
</select>
  • 映射

使用resultMap定义字段和属性(不一致)的映射关系。

<resultMap id="brandResultMap" type="brand">
    <result column="brand_name" property="brandName"/>
    <result column="company_name" property="companyName"/>
</resultMap>

sql语句的resultType改为resultMap并引用其id。

<select id="selectAll" resultMap="brandResultMap">
    select *
    from tb_brand;
</select>

2.根据id查询

  • 编写接口方法

Brand selectById(int id);

  • 编写SQL语句

这里是根据id来查询,所以就有了参数的传入。就需要用到参数占位符,参数占位符在sql中就是?
image.png

mybatis提供了==两种参数占位符==:
==1. #{} ==:执行SQL时,会将 #{} 占位符替换为?,将来自动设置参数值。
==2. ${}== :拼接SQL。底层使用的是 Statement,会存在==SQL注入问题==。

编写如下的SQL语句:

<select id="selectById"  resultMap="brandResultMap">
    select *
    from tb_brand where id = #{id};
</select>
  • 测试代码
@Test
public void testSelectById() throws IOException {
    //接收参数id
    int id = 1;

    //1. 获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

    //2. 获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();

    //3. 获取Mapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

    //4. 执行方法
    Brand brand = brandMapper.selectById(id);
    System.out.println(brand);

    //5. 释放资源
    sqlSession.close();
}

是不是测试代码就是修改了对应执行方法。

  • 特殊字段处理

映射配置文件是xml类型的问题,而 > < 等字符在xml中有特殊含义,所以这些符号需要转义,有两种方式进行转义:转义字符、CDATA区<![CDATA[内容]]>

3.多条件查询

使用条件查询返回多个结果,所以我们需要使用list来存储。还需要考虑如何实现条件。

  • 编写接口方法

我们需要传多个参数,所以这里也有多个写法:

1、使用 @Param("参数名称") 标记每一个参数,在编写SQL时使用 #{参数名称} 进行占位

  List<Brand> selectByCondition(@Param("status") int status, 
  @Param("companyName") String companyName,
  @Param("brandName") String brandName
  );

2、将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。在SQL中使用 #{内容}内容和实体类属性名一致。

  List<Brand> selectByCondition(Brand brand);

3、将多个参数封装到map集合中,将map集合作为接口的方法参数。在SQL中使用 #{内容}内容和map集合中键的名称一致。

  List<Brand> selectByCondition(Map map);
  • SQL语句
<select id="selectByCondition" resultMap="brandResultMap">
    select *
    from tb_brand
    where status = #{status}
    and company_name like #{companyName}
    and brand_name like #{brandName}
</select>
  • 测试代码

存在一个模糊匹配,所以需要进行参数处理:%

@Test
    public void testSelectByCondition() throws IOException {
        //接收参数
        int status = 1;
        String companyName = "华为";
        String brandName = "华为";
        // 处理参数
        companyName = "%" + companyName + "%";
        brandName = "%" + brandName + "%";
        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 获取Mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4. 执行方法   3kind
        //方式一 :接口方法参数使用 @Param 方式调用的方法
//        List<Brand> brands = brandMapper.selectByCondition(status,companyName,brandName);

        //方式二 :接口方法参数是 实体类对象 方式调用的方法
/*        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
        List<Brand> brands = brandMapper.selectByCondition(brand);*/

        //方式三 :接口方法参数是 map集合对象 方式调用的方法
        Map map = new HashMap();
//        map.put("status" , status);
        map.put("companyName", companyName);
        map.put("brandName" , brandName);
        List<Brand> brands = brandMapper.selectByCondition(map);

        System.out.println(brands);
        //5. 释放资源
        sqlSession.close();

    }
  • 动态SQL

使用动态SQL可以解决输入条件时,不需要填写全部条件,自动根据输入内容进行匹配。
我们可以利用mybatis提供的if 标签和 where 标签

【if标签】
可以判断是不是存在对于参数,进行sql的拼接。

<select id="selectByCondition" resultMap="brandResultMap">
    select *
    from tb_brand
    where
        <if test="status != null">
            status = #{status}
        </if>
        <if test="companyName != null and companyName != '' ">
            and company_name like #{companyName}
        </if>
        <if test="brandName != null and brandName != '' ">
            and brand_name like #{brandName}
        </if>
</select>

这样的情况又会出现问题:如果第一个参数没有,那么首位出现and,SQL语句肯定报错。
【where标签】
where标签就是解决这一问题的,会自动去掉非法的and,如果没有参数则不加where关键字。第一个条件也写了and。

<where>
    <if test="status != null">
        and status = #{status}
    </if>
    <if test="companyName != null and companyName != '' ">
        and company_name like #{companyName}
    </if>
    <if test="brandName != null and brandName != '' ">
        and brand_name like #{brandName}
    </if>
</where>

4.动态单个条件查询

  • 编写接口方法

List<Brand> selectByConditionSingle(Brand brand);

  • SQL语句

为了实现动态查询我们使用 choose(when,otherwise)标签 , choose 标签相当于Java 的switch。

<select id="selectByConditionSingle" resultMap="brandResultMap">
    select *
    from tb_brand
    <where>
        <choose><!--相当于switch-->
            <when test="status != null"><!--相当于case-->
                status = #{status}
            </when>
            <when test="companyName != null and companyName != '' "><!--相当于case-->
                company_name like #{companyName}
            </when>
            <when test="brandName != null and brandName != ''"><!--相当于case-->
                brand_name like #{brandName}
            </when>
        </choose>
    </where>
</select>
  • 测试代码
@Test
public void testSelectByConditionSingle() throws IOException {
    //接收参数
    int status = 1;
    String companyName = "华为";
    String brandName = "华为";
    // 处理参数
    companyName = "%" + companyName + "%";
    brandName = "%" + brandName + "%";
    //封装对象
    Brand brand = new Brand();
    //brand.setStatus(status);
    brand.setCompanyName(companyName);
    //brand.setBrandName(brandName);
    
    //1. 获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //3. 获取Mapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    
    //4. 执行方法
    List<Brand> brands = brandMapper.selectByConditionSingle(brand);
    System.out.println(brands);

    //5. 释放资源
    sqlSession.close();
}

5.添加数据

  • 编写接口方法

void add(Brand brand);

  • SQL语句
<insert id="add">
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
</insert>
  • 测试代码
@Test
public void testAdd() throws IOException {
    //接收参数
    int status = 1;
    String companyName = "AA科技";
    String brandName = "AA";
    String description = "AA创新生活!";
    int ordered = 100;

    //封装对象
    Brand brand = new Brand();
    brand.setStatus(status);
    brand.setCompanyName(companyName);
    brand.setBrandName(brandName);
    brand.setDescription(description);
    brand.setOrdered(ordered);

    //1. 获取SqlSessionFactory
    String resource = "mybatis-config.xml";
    InputStream inputStream = Resources.getResourceAsStream(resource);
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    //2. 获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    //3. 获取Mapper接口的代理对象
    BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
    //4. 执行方法
    brandMapper.add(brand);
    //提交事务
    sqlSession.commit();
    
    //5. 释放资源
    sqlSession.close();
}

是不是发现大多是一个套路!都是类似的。

三、注解实现CRUD

使用注解开发会比配置文件开发更加方便。
Mybatis 针对 CURD 操作都提供了对应的注解:

  • 查询 :@Select
  • 添加 :@Insert
  • 修改 :@Update
  • 删除 :@Delete

例如在接口中就可以这样写,不需要处理配置文件了:

@Select(value = "select * from tb_user where id = #{id}")
public User select(int id);

只是注解适用于完成简单功能,配置文件可以处理复杂功能。

1.使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂-点的语句,JAVA注解不仅力不从心,还会让你本就复杂的SQL语句更加混乱不堪。因此,如果你需要做一些很复杂的操作,最好用xml来映射语句。

2.选择何种方式来配置映射,以及认为是否应该要统一映射语句定义的形式,完全取决于你和你的团队.换句话说,永远不要拘泥于种方式,你可以很轻松的在基于注解和xml的语句映射方式间自由移植和切换。


🍇end🍑

☕物有本末,事有终始,知所先后。🍭

相关文章
|
2月前
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
93 2
|
2月前
|
SQL Java 数据库连接
【潜意识Java】深入理解MyBatis的Mapper层,以及让数据访问更高效的详细分析
深入理解MyBatis的Mapper层,以及让数据访问更高效的详细分析
111 1
|
3月前
|
SQL Java 数据库连接
MyBatis-Plus高级用法:最优化持久层开发
MyBatis-Plus 通过简化常见的持久层开发任务,提高了开发效率和代码的可维护性。通过合理使用条件构造器、分页插件、逻辑删除和代码生成器等高级功能,可以进一步优化持久层开发,提升系统性能和稳定性。掌握这些高级用法和最佳实践,有助于开发者构建高效、稳定和可扩展的企业级应用。
197 13
|
5月前
|
SQL Java 数据库连接
mybatis使用四:dao接口参数与mapper 接口中SQL的对应和对应方式的总结,MyBatis的parameterType传入参数类型
这篇文章是关于MyBatis中DAO接口参数与Mapper接口中SQL的对应关系,以及如何使用parameterType传入参数类型的详细总结。
110 10
|
5月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
124 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
7月前
|
SQL Java 数据库连接
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
文章讲述了在使用Mybatis时遇到的资源文件找不到的问题,并提供了通过修改Maven配置来解决资源文件编译到target目录下的方法。
Mybatis系列之 Error parsing SQL Mapper Configuration. Could not find resource com/zyz/mybatis/mapper/
|
6月前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
6月前
|
SQL XML Java
mybatis :sqlmapconfig.xml配置 ++++Mapper XML 文件(sql/insert/delete/update/select)(增删改查)用法
当然,这些仅是MyBatis功能的初步介绍。MyBatis还提供了高级特性,如动态SQL、类型处理器、插件等,可以进一步提供对数据库交互的强大支持和灵活性。希望上述内容对您理解MyBatis的基本操作有所帮助。在实际使用中,您可能还需要根据具体的业务要求调整和优化SQL语句和配置。
103 1
|
7月前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
536 0
|
7月前
|
SQL Java 数据库连接
后端框架的学习----mybatis框架(7、使用注解开发)
这篇文章讲述了如何使用MyBatis框架的注解方式进行开发,包括在接口上使用注解定义SQL语句,并通过动态代理实现对数据库的增删改查操作,同时强调了接口需要在核心配置文件中注册绑定。