MyBatis的学习————上篇

news2024/9/22 15:48:29

目录

一、MyBatis简介

1、MyBatis的历史

2、MyBatis的特性

3、和其它持久化层技术的比较

二、搭建MyBatis

1、开发环境

​编辑2、创建Maven工程 

 3、创建MyBatis核心配置文件

4、创建mapper接口

5、创建Mybatis的映射文件

6、测试功能

7、功能优化 

8、修改和删除方法的测试

9、查询功能测试

三、核心配置文件详解

1、environments(环境配置)

1.1、transactionManager(事务管理器)

1.2、dataSource(数据源)

 2、properties(属性)

3、typeAliases(类型别名)

 4、mapper(映射器)

四、封装SqlSessionUtils工具类并测试

五、MyBatis获取参数的两种方式

1、情况1

 2、情况2

3、情况3

 4、情况4

 5、情况5

六、 MyBatis的各种查询功能

1、查询结果只有一条

2、查询结果有多条 

3、MyBatis中默认的类型别名

4、查询的结果用map方式接收

5、查询多条数据用map接收

七、特殊SQL的执行

1、模糊查询

2、批量删除

3、动态设置表名

4、添加功能获取自增主键

八、自定义映射resultMap

1、方法一——给SQL语句的字段起别名

2、方法二 ——设置全局配置

3、方法三——通过resultMap设置自定义的映射关系

4、多对一的映射

4.1、级联属性赋值

4.2、association

4.3、分布查询

5、一对多的映射

5.1、collection

5.2、分布查询


中文网:MyBatis中文网

一、MyBatis简介

1、MyBatis的历史

MyBatis 本是 Apache 的一个开源项目 iBatis,2010年这个项目由 Apache Software Foundation 迁移到了Google Code,并且改名为 MyBatis 。2013年11月迁移到 Github。

iBatis一词来源于 "internet"和 "abatis"的组合,是一个基于Java的持久层框架。iBatis 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAO)。

2、MyBatis的特性

  • MyBatis是支持定制化SQL、存储过程以及高级映射的优秀的持久层框架
  • MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集
  • MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO映射成数据库中的记录
  • MyBatis是一个半自动的ORM框架

3、和其它持久化层技术的比较

JDBC
        SQL夹杂在Java代码中耦合度高,导致硬编码内伤

        维护不易且实际开发需求中SQL有变化,频繁修改的情况多见

        代码冗长,开发效率低

Hibernate和JPA

        操作简便,开发效率高

        程序中的长难复杂SQL需要绕过框架

        内部基于自动生产的SQL,不容易做特殊优化

        基于全映射的全自动框架,大量字段的POJO进行部分映射时比较困难

        反射操作太多,导致数据库性能下降

MyBatis

        轻量级,性能出色

        SQL和Java编码分开,功能边界清晰。Java代码专注业务、SQL语句专注数据

        开发效率稍逊于Hibernate,但是完全能够接受

二、搭建MyBatis

1、开发环境

IDE:idea 2023.3.4

构建工具:maven 3.8.1

MySQL版本:MySQL 8.0.32

MyBatis版本:MyBatis 3.5.5

2、创建Maven工程 

打包方式使用jar

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>org.example</groupId>
    <artifactId>mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <packaging>jar</packaging>

    <dependencies>
        <!--log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>
        <!--MyBatis-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <!--junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
<!--            <scope>test</scope>-->
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
            </plugin>
        </plugins>
    </build>
</project>

 3、创建MyBatis核心配置文件

XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)

 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>
    <!--配置连接数据库的环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/aaa_test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!--引入映射文件-->
    <mappers>
        <mapper resource="cn/ysy/mapper/StudentMapper.xml"/>
    </mappers>
</configuration>

4、创建mapper接口

MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类

实体类三个属性

5、创建Mybatis的映射文件

相关概念:ORM(Object Relationship Mapping)对象关系映射。
        对象:Java的实体类对象

        关系:关系型数据库

        映射:二者之间的对应关系

Java概念数据库概念
属性字段/列
对象记录/行

1、映射文件的命名规则

表所对应的实体类的类名+Mapper.xml

例如:表t_user,映射的实体类为User,所对应的映射文件为UserMapper.xml

因此一个映射文件对应一个实体类,对应一张表的操作

MyBatis映射文件用于编写SQL,访问以及操作表中的数据

MyBatis映射文件存放的位置是src/main/resources/mappers目录下

2、MyBatis中可以面向接口操作数据,要保证两个一致:

        mapper接口的全类名和映射文件的命名空间(namespace)保持一致

        mapper接口中方法的方法名和映射文件中编写SQL的标签的id属性保持一致

 

<?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.ysy.mapper.StudentMapper">
    <insert id="insertStudent">
        insert into student values(null,'ysy',18);
    </insert>
</mapper>

6、测试功能

测试添加方法

 @Test
    public void test1() throws IOException {
       //加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SQLSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取mapper接口对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        int i = mapper.insertStudent();
        //提交事务 因为mybatis-config.xml中设置了以JDBC的方式提交事务,所以这里需要手动提交事务
        sqlSession.commit();
        System.out.println(i);
    }

 SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
SqlSessionFactory:是"生产"SqlSession"的"工厂"。

工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个"工厂类"中,以后都使用这个工厂类来"生产"我们需要的对象

7、功能优化 

opSession(true);设置自动提交事务,默认是不自动提交的
光标放在openSession的参数括号里,ctrl+p可以查看所有参数

    @Test
    public void test1() throws IOException {
       //加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SQLSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象   这里设置为true之后,可以自动提交事务,就不需要手动提交了
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取mapper接口对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        int i = mapper.insertStudent();
        //提交事务 因为mybatis-config.xml中设置了以JDBC的方式提交事务,所以这里需要手动提交事务
        //sqlSession.commit();
        System.out.println(i);
    }

8、修改和删除方法的测试

@Test
    public void testByUpdate() throws IOException {
        //加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SQLSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取mapper接口对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        mapper.updateStudent();
    }

    @Test
    public void testByDel() throws IOException {
        //加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SQLSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取mapper接口对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        mapper.deleteStudent();
    }

都是没有问题的

9、查询功能测试

查询一个实体对象,包括查询一个实体对象和查询一个list对象

@Test
    public void testFindById() throws IOException {
        //加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SQLSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取mapper接口对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        Student student = mapper.findStudentById();
        System.out.println(student);
    }
    


    @Test
    public void testFindAll() throws IOException {
        //加载核心配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        //获取SQLSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //获取sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取mapper接口对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        List<Student> all = mapper.findAll();
        for (Student student : all) {
            System.out.println(student);
        }
    }

 

三、核心配置文件详解

配置_MyBatis中文网:配置

具体的可以去中文网查看,配置的时候应按照以下顺序进行配置,否则会报错

1、environments(环境配置)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景
 

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
 

所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/aaa_test"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

注意一些关键点:

  • 默认使用的环境 ID(比如:default="development")。
  • 每个 environment 元素定义的环境 ID(比如:id="development")。
  • 事务管理器的配置(比如:type="JDBC")。
  • 数据源的配置(比如:type="POOLED")。

默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID

1.1、transactionManager(事务管理器)

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。例如:
    <transactionManager type="MANAGED">
      <property name="closeConnection" value="false"/>
    </transactionManager>

1.2、dataSource(数据源)

dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。

  • 大多数 MyBatis 应用程序会按示例中的例子来配置数据源。虽然数据源配置是可选的,但如果要启用延迟加载特性,就必须配置数据源。

有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]")

UNPOOLED– 这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。 性能表现则依赖于使用的数据库,对某些数据库来说,使用连接池并不重要,这个配置就很适合这种情形

POOLED– 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求

JNDI – 这个数据源实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的数据源引用

 2、properties(属性)

jdbc.properties:

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

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。例如:

设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:

    <properties resource="jdbc.properties"/>
    <!--配置连接数据库的环境-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

上面例子中的 username 和.password , driver 和 url 属性将会由 jdbc.properties 文件中对应的值来替换。这样就为配置提供了诸多灵活选择。

3、typeAliases(类型别名)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
 

当这样配置时,Student可以用在任何使用 cn.ysy.pojo.Student 的地方。

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean.

 4、mapper(映射器)

创建resources下的文件目录时,要用斜杠(/),不能再使用创建包时的点号(.),要不然创建出来的目录不是层级的

将包内的映射器接口实现全部注册为映射,不用再一个一个映射器去注册了

其它标签我们遇到再说 

四、封装SqlSessionUtils工具类并测试

SqlSessionutils:

public class SqlSessionUtil {
    public static SqlSession getSqlSession(){
        //获取配置文件
        SqlSession sqlSession = null;
        try {
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            //获取SqlSessionFactory对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //获取SqlSession对象
             sqlSession = sqlSessionFactory.openSession(true);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sqlSession;
    }
}

五、MyBatis获取参数的两种方式

MyBatis获取参数值的两种方式:${}和#{}

${}的本质就是字符串拼接,#{}的本质就是占位符赋值

${}使用字符串拼接的方式拼出sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号

1、情况1

mapper接口方法中的参数为单个的字面量类型
例子:根据用户名查询用户

首先使用#{}去获取参数,运行程序是没有问题的
换成${name}再去执行程序就会报错

实际执行的是:

select * from student where name = 张三 ; 很明显这个语句少了单引号,所以解决方法就是再${}外面天上单引号就可以了,再去执行项目就没有问题了

StudentMapper.java:
//根据用户名查询
Student findByName(String name);


StudentMapper.xml:
<select id="findByName" parameterType="string" resultType="Student">
        select * from student where name = #{name};
</select>



 @Test
    public void testFindByName(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        //获取mapper对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        Student student = mapper.findByName("张三");
        //输出
        System.out.println(student);
    }

 2、情况2

mapper接口方法中的参数为多个时
例子:根据用户名和年龄查询用户

首先还是使用#{}去获取参数:

select * from student where name=#{name} and age=#{age}

这样看确实没啥问题,但是执行的时候报错

是因为:此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储
1、以arg0,rag1...为键,以参数为值

2、以param1,param2...为键,以参数为值

因此只需要通过#{}和${}以键的方式访问值即可,但需要注意${}的单引号问题

select * from student where name=#{arg0} and age=#{arg1}再去执行就没有问题了

StudentMapper.java:
//根据name和age查询
Student findByNameAndAge(String name,int age);


StudentMapper.xml:

<select id="findByNameAndAge" resultType="Student">
        select * from student where name = #{arg0} and age = #{arg1};
</select>


 @Test
    public void testFindByNameAndAge(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        //获取mapper对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        Student student = mapper.findByNameAndAge("张三",11);
        //输出
        System.out.println(student);
    }

3、情况3

mapper接口方法中的参数为多个时,可以手动将这些参数放在一个map中存储


只需要通过#{}和${}以键的方式访问值即可,但是需要注意${}的单引号问题

    //登录
    Student login(Map<String,Object> map);


    <select id="login" resultType="Student">
        select * from student where name = #{name} and age = #{age};
    </select>



@Test
    public void testFindByMap(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        //获取mapper对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //创建mao对象
        Map<String, Object> map = new HashMap<>();
        map.put("name","张三");
        map.put("age",11);
        //执行
        Student student = mapper.login(map);
        //输出
        System.out.println(student);
    }

 4、情况4

mapper接口方法中的参数是实体类类型的参数

只需要通过#{}和${}以属性的方式访问属性值即可,但是需要注意${}的单引号问题

    //添加用户信息
    int add(Student student);




    <insert id="add">
        insert into student values(null,#{name},#{age});
    </insert>


    @Test
    public void test7(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        //获取mapper对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        int result = mapper.add(new Student(0, "张三", 11));
        //输出
        System.out.println(result);
    }

 5、情况5

使用@Param注解命名参数

此时MyBatis会将这些参数放在一个map集合中,以两种方式进行存储

1、以@Param注解的值为键,以参数为值

2、以param1,param2...为键,以参数为值

因此只需要通过#{}和${}以键的方式访问值即可,但需要注意${}的单引号问题

    //以参数形式查找用户
    Student loginByParam(@Param("name") String name , @Param("age") int age);



    <select id="loginByParam" resultType="Student">
        select * from student where name = #{name} and age = #{age};
    </select>


    @Test
    public void loginByParam(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        //获取mapper对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        //执行
        Student student = mapper.loginByParam("张三",11);
        //输出
        System.out.println(student);
    }

六、 MyBatis的各种查询功能

1、查询结果只有一条

可以通过实体类对象接收

可以通过list集合接收

    //根据用户id查询用户信息
    Student testFindStudentById(@Param("id") int id);


    <select id="testFindStudentById" resultType="Student">
        select * from student where id = #{id};
    </select>



    @Test
    public void findStudentById(){
        //获取SqlSession
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        Student student = studentMapper.testFindStudentById(2);
        System.out.println(student);
    }

2、查询结果有多条 

可以通过list集合接收

注意:一定不能通过实体类对象接收,此时会抛异常TooManyResultsException

    //查询所有
    List<Student> testFindAll();

    <select id="testFindAll" resultType="Student">
        select * from student
    </select>

    @Test
    public void findStudentById(){
        //获取SqlSession
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        Student student = studentMapper.testFindStudentById(2);
        System.out.println(student);
    }

3、MyBatis中默认的类型别名

java.lang.Integer-->int,integer
int --> _int,_integer

Map-->map

String ---> string

    //查询用户的总记录数
    Integer testFindTotal();

    <select id="testFindTotal" resultType="integer">
        select count(*) from student
    </select>

    @Test
    public void testFindTotal(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        System.out.println(studentMapper.testFindTotal());
    }

4、查询的结果用map方式接收

结果:{name=王五, id=3, age=33}

    //根据id查询用户信息为一个Map
    Map<String,Object> testFindStudentByIdToMap(@Param("id") Integer id);

    <select id="testFindStudentByIdToMap" resultType="map">
        select * from student where id = #{id};
    </select>

    @Test
    public void testFindStudentByIdToMap(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        System.out.println(studentMapper.testFindStudentByIdToMap(3));
    }

5、查询多条数据用map接收

结果:[{name=李四, id=2, age=22}, {name=王五, id=3, age=33}, {name=赵六, id=4, age=44}, {name=ysy, id=6, age=18}, {name=ysy, id=7, age=18}, {name=张三, id=8, age=11}, {name=sy, id=9, age=21}]

在mapper接口方法上添加@MapKey注解,此时可以将每条数据转换的map集合作为值,以某个字段的值作为键,放在同一个map集合中

//查询所有用户信息,并将数据封装为map集合
    List<Map<String,Object>> testFindAllToMap();

@MapKey("id")  //以id为key
Map<String,Object> testFindAllToMap();

//结果:{2={name=李四, id=2, age=22}, 3={name=王五, id=3, age=33}, 4={name=赵六, id=4, age=44}, 6={name=ysy, id=6, age=18}, 7={name=ysy, id=7, age=18}, 8={name=张三, id=8, age=11}, 9={name=sy, id=9, age=21}}


    <select id="testFindAllToMap" resultType="map">
        select * from student
    </select>

    @Test
    public void testFindAllToMap(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        System.out.println(studentMapper.testFindAllToMap());
    }

七、特殊SQL的执行

1、模糊查询

    //根据用户名模糊查询
    List<Student> findByNameLike(@Param("name") String name);

    <select id="findByNameLike" resultType="student">
        <!--select * from student where name like '%${name}%'-->
        <!--select * from student where name like concat('%',#{name},'%');-->
        select * from student where name like "%"#{name}"%"
    </select>

    @Test
    public void findNameByLike(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = studentMapper.findByNameLike("y");
        System.out.println(students);
    }

2、批量删除

    //批量删除
    int deleteMore(@Param("ids") String ids);

    <delete id="deleteMore">
        delete from student where id in (${ids})
    </delete>

    @Test
    public void deleteMore(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        int i = studentMapper.deleteMore("2,3,4");
        System.out.println(i);
    }

3、动态设置表名

    //动态设置表名,查询所有
    List<Student> findMoreByTableName(@Param("tableName") String tableName);

    <select id="findMoreByTableName" resultType="student">
        select * from ${tableName}
    </select>

    @Test
    public void findMoreByTableName(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper student = sqlSession.getMapper(StudentMapper.class);
        List<Student> students = student.findMoreByTableName("student");
        System.out.println(students);
    }

4、添加功能获取自增主键

useGeneratedKeys:设置当前标签中的sql使用了自增的主键

keyProperty:将自增的主键的值赋值给传输到映射文件中参数的某个属性

    //添加用户信息
    void addStudent(Student student);

    <insert id="addStudent" useGeneratedKeys="true" keyProperty="id">
        insert into student values(null,#{name},#{age})
    </insert>

    @Test
    public void addStudent(){
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
        Student student = new Student(null, "ysy", 23);
        studentMapper.addStudent(student);
        System.out.println(student);
    }

八、自定义映射resultMap

解决字段名和属性名不一致问题

1、方法一——给SQL语句的字段起别名

    List<TbStudent> getAllStudent();

    <select id="getAllStudent" resultType="TbStudent">
        select * from tb_student;
    </select>

    @Test
    public void testFindAll() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<TbStudent> students = mapper.getAllStudent();
        //lambda
        students.forEach(System.out::println);
    }

当实体类 的属性名和数据库中的字段名对不上就差找不到该属性,就是显示null值,无法映射

通过给sql语句起别名可以解决

2、方法二 ——设置全局配置

<!--设置MyBatis的全局配置-->
    <settings>
        <!--将“_”下划线映射为驼峰————stu_name:stuName-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>


    <select id="getAllStudent" resultType="TbStudent">
        <!--select id,stu_name stuName,stu_age stuAge from tb_student;-->
        select id,stu_name,stu_age from tb_student;
    </select>

这样再去测试案例,就发现就没问题了

3、方法三——通过resultMap设置自定义的映射关系

id是映射主键的关系

result是映射普通字段的关系

    <resultMap id="TbStudentMap" type="TbStudent">
        <id property="id" column="id"/>
        <result property="stuName" column="stu_name"/>
        <result property="stuAge" column="stu_age"/>
    </resultMap>


    <select id="getAllStudent" resultMap="TbStudentMap">
        select * from tb_student;
    </select>

4、多对一的映射

4.1、级联属性赋值

    //查询用户信息及所属班级的信息
    TbStudent getStudentAndClass(@Param("id") Integer id);



    <resultMap id="StudentAndClassesMapOne" type="TbStudent">
        <id property="id" column="id"/>
        <result property="stuName" column="stu_name"/>
        <result property="stuAge" column="stu_age"/>
        <result property="classes.cid" column="cid"/>
        <result property="classes.claName" column="cla_name"/>
    </resultMap>
    <select id="getStudentAndClass" resultMap="StudentAndClassesMapOne">
        <!--左外连接查询-->
        select * from tb_student s left join classes c on s.cid = c.cid where s.id = #{id};
    </select>

    @Test
    public void testFindStudentAndClassesById() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        TbStudent student = mapper.getStudentAndClass(1);
        System.out.println(student);
    }

4.2、association

    <resultMap id="StudentAndClassesMapTwo" type="TbStudent">
        <id property="id" column="id"/>
        <result property="stuName" column="stu_name"/>
        <result property="stuAge" column="stu_age"/>
        <association property="classes" javaType="Classes">
            <id property="cid" column="cid"/>
            <result property="claName" column="cla_name"/>
        </association>
    </resultMap>
    <select id="getStudentAndClass" resultMap="StudentAndClassesMapTwo">
        <!--左外连接查询-->
        select * from tb_student s left join classes c on s.cid = c.cid where s.id = #{id};
    </select>

4.3、分布查询

前提把全局配置打开,避免getClassesStepTwo再用resultMap

select:设置分布查询的sql的唯一标识(namespace.SQLId或mapper接口的全类名.方法名)

column:设置分布查询的条件

    <!--设置MyBatis的全局配置-->
    <settings>
        <!--将“_”下划线映射为驼峰————stu_name:stuName-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>    

//分布查询用户信息和班级信息
    //第一步:查询用户信息
    TbStudent getStudentStepOne(@Param("id") Integer id);
    //第二步:查询班级信息
    Classes getClassesStepTwo(@Param("cid") Integer cid);


    <resultMap id="StudentStepOneMap" type="TbStudent">
        <id property="id" column="id"/>
        <result property="stuName" column="stu_name"/>
        <result property="stuAge" column="stu_age"/>
        <association property="classes"
                     select="cn.ysy.mapper.StudentMapper.getClassesStepTwo"
                     column="cid">
            <id property="cid" column="cid"/>
            <result property="claName" column="cla_name"/>
        </association>
    </resultMap>
    <select id="getStudentStepOne" resultMap="StudentStepOneMap">
        select * from tb_student where id = #{id};
    </select>

    <select id="getClassesStepTwo" resultType="Classes">
        select * from classes where cid = #{cid};
    </select>



    @Test
    public void testFindStudentAndClassesSept() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        TbStudent student = mapper.getStudentStepOne(1);
        System.out.println(student);
    }

 分布查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息

lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载

aggressiveLazyLoading:当开启时,任何地方的调用都会加载该对象的所有属性。否则,每个属性会按需加载

此时就要可以实现按需加载,获取的书库是什么,就只会执行相应的sql。此时可通过association和collection中的fetchType属性设置当前的分布查询是否使用延迟加载,fetchType="lazy(延迟加载)eager(理解加载)"

5、一对多的映射

5.1、collection

collection:处理一对多的映射关系

ofType:表示该属性所对应的结合中存储数据的类型

    //获取班级所有同学信息
    Classes getAllStudentAndDept(@Param("cid") Integer cid);


    <!--一对多关系映射-->

    <resultMap id="ClassesAndStudentResultMap" type="Classes">
        <id property="cid" column="cid"/>
        <result property="claName" column="cla_name"/>
        <!--collection表示一对多的关系-->
        <collection property="studentList" ofType="TbStudent">
            <id property="id" column="id"/>
            <result property="stuName" column="stu_name"/>
            <result property="stuAge" column="stu_age"/>
        </collection>
    </resultMap>
    <select id="getAllStudentAndDept" resultMap="ClassesAndStudentResultMap">
        <!--使用calsses左外连接查询,左表是classes-->
        select * from classes c left join tb_student s on c.cid = s.cid where c.cid = #{cid};
    </select>


    @Test
    public void getAllStudentAndDept() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Classes classes = mapper.getAllStudentAndDept(1);
        System.out.println(classes);
    }

5.2、分布查询

    //分步查询班级信息以及班级下的所有同学信息
    Classes getClassesAndStudentStepOne(@Param("cid") Integer cid);
    //第二步:根据cid查询班级下的所有同学信息
    List<Student> getClassesAndStudentStepTwo(@Param("cid") Integer cid);


    <resultMap id="ClassesAndStudent" type="Classes">
        <id property="cid" column="cid"/>
        <result property="claName" column="cla_name"/>
        <collection property="studentList"
                    select="cn.ysy.mapper.StudentMapper.getClassesAndStudentStepTwo"
                    column="cid">
        </collection>
    </resultMap>
    <select id="getClassesAndStudentStepOne" resultMap="ClassesAndStudent">
        select * from classes where cid = #{cid};
    </select>
    <select id="getClassesAndStudentStepTwo" resultType="tbStudent">
        select * from tb_student where cid = #{cid};
    </select>


    @Test
    public void getClassesAndStudentStep() {
        SqlSession sqlSession = SqlSessionUtil.getSqlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Classes classes = mapper.getClassesAndStudentStepOne(1);
        System.out.println(classes);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2085054.html

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

相关文章

重生奇迹MU最合适PK的几个职业

重生奇迹MU是一款备受玩家青睐的经典游戏&#xff0c;其中的PK系统更是吸引了众多玩家的关注。在众多职业中&#xff0c;哪些职业最适合PK呢&#xff1f; PK作为重生奇迹MU的一种娱乐方式&#xff0c;已成为该游戏核心系统之一&#xff0c;并在多年的流行中仍能带给玩家许多乐…

python正则表达式的一些问题

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

Matplotlib中twinx() 函数的用法

ax1.twinx() 是 Matplotlib 库中的一个函数&#xff0c;用于在同一个图中创建一个共享 x 轴但具有独立 y 轴的双 y 轴图表。这个函数非常适合用来在同一张图中绘制两组具有不同 y 轴度量的变量&#xff0c;使得它们可以共享 x 轴&#xff0c;但彼此之间有不同的 y 轴尺度。 ax…

SpringBoot日常:Spring扩展接口之InitializingBean

文章目录 简介源码分析应用场景代码示例运行示例 简介 这篇文章主要介绍了Spring中InitializingBean的使用详细解析&#xff0c;InitializingBean是Spring提供的拓展性接口&#xff0c;提供了属性初始化后的处理方法,它只有一个afterPropertiesSet方法&#xff0c;凡是继承该接…

中断的引入

中断系统是为使CPU具有对外界紧总事件的实时处理能力而设置的 当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求&#xff0c;要求CPU暂停当前的工作&#xff0c;转而去处理这个紧急事件&#xff0c;处理完以后&#xff0c;再回到原来被中断的地方&#xff0c;继续原…

进程间的同步与互斥

1、计数信号量及其初始化 由于事件发生的次数可能不止一次&#xff0c;或者资源可用的数量可能不止一个&#xff0c;因此&#xff0c;信号量内部会维护一个计数器&#xff0c;用于表示某种事件发生的次数或者某种资源可用的数量。 信号量至少提供两种操作&#xff1a;一种等待…

flutter 手写时钟

前言&#xff1a; 之前看过别人写的 js实现的 时钟表盘 挺有意思的&#xff0c;看着挺好 这边打算自己手动实现以下。顺便记录下实现过程&#xff1a;大致效果如下&#xff1a; 主要技术点&#xff1a; 表盘内样 倒角&#xff1a; 表盘下半部分是有一点倒角的感觉&#xff0c;…

YOLOv8独家改进:轻量化改进 | 高效移动应用的卷积加性自注意Vision Transformer

💡💡💡本文独家改进:轻量化改进之高效移动应用的卷积加性自注意Vision Transformer,构建了一个新颖且高效实现方式——卷积加性相似度函数,并提出了一种名为卷积加性标记混合器(CATM) 的简化方法来降低计算开销 💡💡💡性能比较:计算量参数量均有一定程度降低…

别盲目选择!2024年超级兔子与TOP3数据恢复,效率比拼全记录

在现在这个数字化的社会里&#xff0c;数据对我们来说太重要了。不管是家里的照片、工作文件&#xff0c;还是那些记录着美好时光的视频&#xff0c;要是弄丢了&#xff0c;肯定特别着急。不过别担心&#xff0c;今天咱们就来聊聊几款Windows系统上的数据恢复好帮手——超级兔子…

布局容器Grid、StackPanel、GroupBox、DockPanel、WrapPanel

Grid——网格布局&#xff0c;其中控件或容器需指定位置 StackPanel——堆叠面板&#xff0c;其中的控件水平布局、竖直布局 DockPanel——停靠面板&#xff0c;内部控件或容器可以放置在上、下、左、右 WrapPanel——可以看作是具有自动换行功能的StackPanel容器。窗体太小…

360杀毒恢复查杀的软件

360的查杀恢复区不太好找&#xff0c;特此记录&#xff1a; 主界面/管理中心面板/安全操作中心 安全操作中心/可恢复区&#xff1a;

UE5蓝图 抽卡出货概率

SSR概率0.1 SR概率0.2 R概率0.7 ps&#xff1a;数组内相加为1。且从小到大排序。

单片机相关面试问题精选

1. 基础概念类问题 什么是单片机&#xff1f;它有哪些主要应用&#xff1f; 答案要点&#xff1a;单片机是一种集成在单一芯片上的微型计算机&#xff0c;包含CPU、存储器、输入输出接口等&#xff0c;广泛应用于工业自动化、智能家居、汽车电子、医疗设备等领域。它能够实现复…

黑神话:悟空热背后的散热秘密:无压烧结银

黑神话&#xff1a;悟空热背后的散热秘密&#xff1a;无压烧结银 随着《黑神话:悟空》这款高画质、高性能要求的游戏在全球范围内的火爆&#xff0c;玩家们对于游戏设备的性能需求也达到了前所未有的高度。为了满足这种对极致游戏体验的追求&#xff0c;游戏主机和高端显卡等硬…

谷歌首页快捷方式变为一行的解决办法

也挺离谱的&#xff0c;今早上班刚打开谷歌浏览器&#xff0c;首页快捷方式就变成一排了&#xff0c;对于而且快捷方式还不能拖拽自定义排序&#xff0c;这使得我这位用习惯6年的双排老用户完全不能忍&#xff0c;打工人上班的怨气更重了。 经过几番周折中关于找到如下解决方案…

高级测试进阶 Centos7安装 Docker容器

前言 OS 安装环境要求 要安装 Docker Engine&#xff0c;需要 CentOS 7 的维护版本&#xff0c;不支持或未测试存档版本&#xff08;一句话&#xff1a;需要正常迭代版本的 Centos 7 系统&#xff0c;其他系统都不行&#xff09; 必须启用 centos-extras 存储库&#xff0c;…

Mysql 巧秒避开 varchar 类型的 max()、min() 函数的坑

比如&#xff0c;有一个这样的表&#xff0c; 里面存储的 数字 但是数据库表类型 是varchar 比如这个表的 nums &#xff1a; 样例数据&#xff1a; 如果我现在需要查询出这表里面&#xff0c;nums 最大的值 &#xff1a; 很多人可能不注意就会去使用 max &#xff08;&#…

08--kubernetes可视化界面与Daemonset

前言&#xff1a;前几章写的内容太多了&#xff0c;后面打算写k8s持久化篇幅也不小&#xff0c;这一章算作过度章节&#xff0c;内容简单一些&#xff0c;主要是K8S_web界面与Daemonset控制器。 1、Dashboard Dashboard是一个图形化界面&#xff0c;用于汇总和展示来自不同数…

酶荧光底物;Ac-ESEN-AMC;Ac-Glu-Ser-Glu-Asn-AMC;CAS:896420-43-2

【Ac-ESEN-AMC 简介】 Ac-Glu-Ser-Glu-Asn-AMC 通常用作酶的荧光底物&#xff0c;特别是作为溶酶体处理酶&#xff08;Vacuolar Processing Enzyme, VPE&#xff09;的选择性底物。在生物化学研究中&#xff0c;这类底物可以用于检测和定量特定酶的活性&#xff0c;因为当底物被…

最新盘点!适合制造业的工单管理系统有哪些?

本文带大家盘点好用的工单管理系统&#xff1a; 易维帮助台、金万维帮我吧、青鸟云报修、沃丰科技 ServiceGo、泛微工单管理系统、致远互联工单管理系统、腾讯云智服工单系统、Zendesk、Freshdesk。 工单管理系统就如同企业的高效调度员。它能把企业的各种任务和问题安排得有条…