Mybatis 学习笔记总结 (二)

1. Mybatis 生命周期和作用域


在这里插入图片描述
上面的SQL Mapper就是sqlSession通过getMapper来获取内容,sqlSession.getMapper(xxx.class)


生命周期 和 作用域,是至关重要的,因为错误的使用会导致非常严重的并发问题

SqlSessionFactoryBuilder:

  • 一旦创建SqlSessionFactory,就不需要SqlSessionFactoryBuilder了。
  • 因此,SqlSessionFactoryBuilder的作用域最佳是方法作用域也就是局部变量

SqlSessionFactory:

  • sqlSessionfactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。该对象表现的效果就和数据库连接池一样!
  • 因此,SqlSessionFactory的作用域最佳是应用作用域。
  • 最简单的就是就用单例模式或者静态单例模式。

SqlSession:

  • sqlSession是连接到连接池的一个请求。每个线程都应该有它自己的SqlSession实例。
  • SqlSession的实例不是线程安全的,因此是不能被共享的,所以它的最佳作用域是请求或方法作用域
  • 每个SqlSession的实例用完之后,需要赶紧调用close()方法进行关闭,否则资源被占用!

在这里插入图片描述
上面的每一个Mapper,就代表一个具体的业务!

2. 解决实体类的属性名 和 数据库的字段名不一致的问题


如何解决实体类的属性名 和 数据库的字段名不一致的问题?

数据库中的表结构:
在这里插入图片描述
在这里插入图片描述


解决上面的问题,就要理解类型处理器(typeHandlers)的作用效果。

MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型

大体上的流程就是:

-- 我们去数据库中要运行的语句。
select * from mybatis.`user` where id = #{id};
-- 经过类型处理器,从而拿到一些列对应的字段和字段值等。
select id,name,pwd from mybatis.`user` where id = #{id};

-- 而我们这里在数据库中提取的是pwd字段,而我们的实体类中定义的是password属性。
-- 简而言之,就是让password属性和pwd字段对应起来就解决问题了。

解决方法:

  • 在mybatis中配置的xml文件,我们可以给sql语句的字段起别名,来达到我们的目的。
<?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.itholmes.dao.UserMapper">
    <select id="getUserById" resultType="User" parameterType="int">
        select id,name,pwd as password from mybatis.user where id = #{id};
    </select>
</mapper>
  • 还有一种方法就是使用resultMap结果集映射的方法,如下一节。

3. resultMap结果集映射


通过使用resultMap结果集映射来解决上面的问题:

我们在UserMapper.xml文件中,设置了resultMap标签。

resultMap标签中声明了result标签它的column属性和property属性分别对应的就是数据库中的字段和实体类中的属性。通过这种方式一一对应起来。

<?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.itholmes.dao.UserDao">

    <!--
        结果集映射:
            id属性:就是当前resultMap的标识。
            type属性:定义映射后的结果类型。
    -->
    <resultMap id="UserMap" type="User">
        <!--
            column数据库中的字段,property实体类中的属性。
            这就意思就是让column数据库字段和property实体类属性对应起来。
        -->
        <result property="id" column="id"></result>
        <result property="name" column="name"></result>
        <result property="password" column="pwd"></result>
    </resultMap>

    <select id="selectById" resultMap="UserMap">
        select * from `user` where id = #{id};
    </select>
</mapper>

其实,我们不设置resultMap,MyBatis会在幕后自动创建一个resultMap,再基于属性名来映射到JavaBean(Java实体类)的属性上面。

4. 日志

4.1 日志工程


如果一个数据库sql操作,出现了异常,我们需要排错,日志就是最好的助手!

对于这样的异常,以前使用sout,debug。来进行排查找错。

现在,使用日志会更加方便!


在mybatis-config.xml核心配置文件的setting标签中,有个logImpl配置。

在这里插入图片描述
(后面的未设置,是没有设置默认值的意思。)

  • SLF4J
  • LOG4J(重点)
  • LOG4J2:LOG4J的升级版本。
  • JDK_LOGGING:Java自带的日志输出。
  • COMMONS_LOGGING:工具包(像之前的commons_io一样的工具包)。
  • STDOUT_LOGGING(重点):标准日志输出。
  • NO_LOGGING:没有日志输出。

在Mybatis中具体使用那个日志实现,都在setting设置中设定。


STDOUT_LOGGING标准日志输出:
在mybatis-config.xml核心配置文件中,配置我们的日志:(注意顺序问题)

<settings>
    <!--
        name就对应logImpl , value对应官方给定的值。
        注意这里不是我们自己设定的,而是官方给出来让我们用的,这些名字和value值我们不能随便改。
    -->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

在这里插入图片描述

4.2 LOG4J日志输出


什么是Log4j?

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台,文件,GUI组件等。
  • Log4j可以控制每一条日志的输出格式。
  • Log4j可以通过定义每一条日志信息的级别,能够更加细致地控制日志的生成过程。
  • Log4j可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码,非常方便。

第一步:导入log4j的包,一般我们在maven仓库加依赖。

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

第二步:创建log4j.properties文件。

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/itholmes.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

第三步:在mybatis核心配置文件中,配置log4j日志的实现(logImpl)。

<settings>
    <setting name="logImpl" value="LOG4J"/>
</settings>

第四步:log4j的测试,直接运行测试类来进行测试。
在这里插入图片描述


简单实用:

  • 1.在要使用Log4j的类中,导入Logger的包,注意这里Logger系统有自带的,我们要使用log4j里面的那个包,import org.apache.log4j.Logger;

  • 2.定义好的Logger日志对象,参数为当前类的class。

在这里插入图片描述

在我们的测试类中,Logger对象一般我们放到上面(提升作用域),并且设置为staitc,方便使用。

package com.itholmes.dao;

import com.itholmes.pojo.User;
import com.itholmes.utils.MybatisSqlSession;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Test;

public class test {

    //这里导入Logger是我们要之前导入import org.apache.log4j.Logger;的包,不要导错了。
    static Logger logger = Logger.getLogger(test.class);

    @Test
    public void test01(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();

        logger.info("测试,进入test01方法进行查询操作。");

        UserDao mapper = sqlSession.getMapper(UserDao.class);
        if (false){
            //一般使用在try-catch中。
            logger.error("发现异常");
        }
        User user = mapper.selectById(1);

        System.out.println(user.toString());

        logger.info("测试结束。");
    }

    @Test
    public void testLog4j(){

        //我们可以根据不同级别信息,给日志追加一些信息等等。
        logger.info("info:进入了testLog4j");
        logger.debug("debug:进入了testLog4j");
        logger.error("error:进入testLog4j");

    }
}

5. 分页

5.1 limit分页


为什么要分页?

  • 减少数据的处理量。

使用Limit分页

-- 语法:
select * from `表名` limit startIndex,pageSize;

使用Mybatis实现分页效果:

  • 1.接口里的分页方法。

UserDao类:

package com.itholmes.dao;

import com.itholmes.pojo.User;

import java.util.List;
import java.util.Map;

public interface UserDao {
    //分页查询的效果
    List<User> getUserByLimit(Map<String,Integer> map);
}
  • 2.Mapper.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.itholmes.dao.UserDao">

    <!--分页查询的结果集映射-->
    <resultMap id="UserMap2" type="User">
        <result property="password" column="pwd"/>
    </resultMap>
    <!--分页查询-->
    <select id="getUserByLimit" parameterType="map" resultMap="UserMap2">
        select * from mybatis.user limit #{startIndex},#{pageSize};
    </select>

</mapper>
  • 3.测试类。
package com.itholmes.dao;

import com.itholmes.pojo.User;
import com.itholmes.utils.MybatisSqlSession;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class test {

    static Logger logger = Logger.getLogger(test.class);

    @Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> list = mapper.getUserByLimit(map);
        for (User user : list) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

5.2 RowBounds分页(了解)


在这里插入图片描述
RowBounds就是不通过使用sql语句进行分页,而是通过java代码层面进行分页。

  • 1.设置的接口中的方法。
package com.itholmes.dao;

import com.itholmes.pojo.User;

import java.util.List;
import java.util.Map;

public interface UserDao {
    //分页通过RowBounds实现
    List<User> getUserByRowBounds();
}
  • 2.配置mapper.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.itholmes.dao.UserDao">

    <!--分页查询的结果集映射-->
    <resultMap id="UserMap2" type="User">
        <result property="password" column="pwd"/>
    </resultMap>

    <!--limit分页-->
    <select id="getUserByLimit" parameterType="map" resultMap="UserMap2">
        select * from mybatis.user limit #{startIndex},#{pageSize};
    </select>

    <!--RowBounds分页-->
    <select id="getUserByRowBounds" resultMap="UserMap2">
        select * from mybatis.user;
    </select>

</mapper>
  • 3.测试。
package com.itholmes.dao;

import com.itholmes.pojo.User;
import com.itholmes.utils.MybatisSqlSession;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;
import org.junit.jupiter.api.Test;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class test {

	//limit sql分页方式
    @Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        Map<String, Integer> map = new HashMap<>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> list = mapper.getUserByLimit(map);
        for (User user : list) {
            System.out.println(user);
        }
        sqlSession.close();
    }

	//RowBounds java代码分页
    @Test
    public void getUserByRowBounds(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();

        //RowBounds实现,两个参数分别对应偏移量(从第几行读取),限制条数。
        RowBounds rowBounds = new RowBounds(1, 2);

        //通过Java代码层面实现分页效果
        List<User> list = sqlSession.selectList("com.itholmes.dao.UserDao.getUserByRowBounds",null,rowBounds);
        for (User user : list) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

5.3 分页插件


在这里插入图片描述
想使用,直接点文档看看就可以了。

6. 使用注解开发

6.1 面向接口编程


理解好面向对象编程和面向接口编程:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.2 Mybatis的注解开发


什么时候用注解,什么时候用xml?
在这里插入图片描述


注解开发的实现:

  • 1.注解在接口上实现。
package com.itholmes.dao;

import com.itholmes.pojo.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;

public interface UserDao {
    @Select("select * from user")
    List<User> getUsers();
}
  • 2.需要在mybatis的核心配置文件中绑定接口。
<?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">
        <property name="username" value="root"/>
        <property name="password" value="0818"/>
    </properties>

    <settings>
        <!--这里我们使用标椎日志工厂实现-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    
    <typeAliases>
        <typeAlias type="com.itholmes.pojo.User" alias="User"/>
    </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.itholmes.dao.UserDao"/>
    </mappers>
</configuration>
  • 3.测试。
import com.itholmes.dao.UserDao;
import com.itholmes.pojo.User;
import com.itholmes.utils.MybatisSqlSession;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class UserTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        List<User> list = mapper.getUsers();
        for (User user : list) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

Mybatis的注解实现开发的本质上是反射机制的实现 , 底层原理使用的动态代理。

6.3 使用注解的 增删改查(CRUD)

6.3.1 自动提交事务


Mybatis的增删改都必须手动提交事务才能完成对数据库的操作。为了方便我们可以在自己写的工具类设置,实现自动提交事务的效果。
在这里插入图片描述

6.3.1 有参数的查询语句 以及@Param注解的使用


对于有参数的查询语句操作:

  • 我们通过@Param注解来设置。
package com.itholmes.dao;

import com.itholmes.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;

public interface UserDao {

    //查询全部
    @Select("select * from user")
    List<User> getUsers();

    //查询单个
    //方法存在多个参数,所有的参数前面必须加上@Param注解。
    @Select("select * from user where name = #{str2} and id = #{id2}")
    User getUserById(@Param("id2") int id,@Param("str2") String str);
    
}

测试类:

import com.itholmes.dao.UserDao;
import com.itholmes.pojo.User;
import com.itholmes.utils.MybatisSqlSession;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

public class UserTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User userById = mapper.getUserById(1,"张三");
        System.out.println(userById);
        sqlSession.close();
    }
}

@Param注解详解:

  • 基本类型的参数或者String类型,需要加上该注解。
  • 引用类型不需要加(像我们自己写的实体类)。
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上。

注意:@Param注解一旦给对应的参数设置了不同的名字,不管是注解的语句还是xml的语句都要使用对应@Param定义的名字!

在这里插入图片描述

6.3.2 增删改的实现


UserDao接口:

package com.itholmes.dao;

import com.itholmes.pojo.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface UserDao {

    //查询全部
    @Select("select * from user")
    List<User> getUsers();

    //查询单个
    //方法存在多个参数,所有的参数前面必须加上@Param注解。
    @Select("select * from user where name = #{str2} and id = #{id2}")
    User getUserById(@Param("id2") int id,@Param("str2") String str);

    //像下面的User对象就不需要添加什么@Param注解!!
    //添加
    //注意这里的password要和user对象的属性passowrd名字对应!!
    @Insert("insert into user (id,name,pwd) values (#{id},#{name},#{password})")
    int addUser(User user);

    //修改
    @Update("update user set name=#{name},pwd=#{password} where id = #{id}")
    int updateUser(User user);

    //删除
    @Delete("delete from user where id = #{uuid}")
    int deleteUser(@Param("uuid") int i);
}

测试类:

import com.itholmes.dao.UserDao;
import com.itholmes.pojo.User;
import com.itholmes.utils.MybatisSqlSession;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

public class UserTest {
    //查询单个
    @Test
    public void test(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User userById = mapper.getUserById(1,"张三");
        System.out.println(userById);
        sqlSession.close();
    }
    //添加
    @Test
    public void test2(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        int i = mapper.addUser(new User(4,"hello","90945"));
        if(i>0){
            System.out.println("添加成功");
        }
        sqlSession.close();
    }
    //修改
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        int i = mapper.updateUser(new User(4, "骆驼祥子","90583"));
        if(i>0){
            System.out.println("修改成功");
        }
        sqlSession.close();
    }
    //删除
    @Test
    public void test4(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        int i = mapper.deleteUser(3);
        if(i>0){
            System.out.println("修改成功");
        }
        sqlSession.close();
    }
}

6.3.3 #{} 和 ${}的区别


最大的区别就是#{} 是可以防止sql注入;而${}是不能防止sql注入的。就像Statement和prestatement。

所以说能用#{},就别用${}。

7. Lombok(了解就好)


官方查看Lombok的一些介绍啥的。

在这里插入图片描述

lombok说的直接一点,就是让我们可以简化实体类,实体类的get,set,有参构造器,无参构造器等等,都可以通过注解来生成。


使用步骤:

  • 第一步:安装Lombok的插件,在idea的setting设置中,我们可以在plugins直接查找到。

在这里插入图片描述

  • 第二步:在项目中导入lombok的jar包。
    在这里插入图片描述
  • 第三步:在实体类上面加注解,每个注解的作用。

在这里插入图片描述

@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass

对于上面这些注解常用的介绍:

package com.itholmes.pojo;

import lombok.*;

@Data//生成get,set,无参构造器等等
@AllArgsConstructor//生成有参数构造器(全部属性参数)
@NoArgsConstructor//生成无参数构造器
@ToString//生成toString方法
@EqualsAndHashCode//生成equals和hashcode的方法
public class User {

	//@Setter生成set方法,对应可以是类也可以是属性。
    private int id;
    private String name;
    private String password;

}

在这里插入图片描述


8. 理解 关联 和 集合


在这里插入图片描述

多个学生对应一个老师。

  • 关联的意思就是:对于学生而言,多个学生,关联一个老师[多对一]。
  • 集合的意思就是:对于老师而言,一个老师,有很多(集合)个学生[一对多]。

在sql数据库中的外键关联和集合的效果如下:
在这里插入图片描述
在这里插入图片描述

9. Maven的resource创建 目录时遇到的一个小问题


在创建resource中的目录时,目录有时并不会展开,并且在target文件它也不会合并到一起相反会出现一个名字为com.itholmes.dao的目录,而不是分开的:

请添加图片描述
上面没有合并到一起,是因为系统以为resource下有一个名字为com.itholmes.dao的目录,并不是我们想的叠加目录。

解决办法好解决就是一层一层的定义目录就好了。
在这里插入图片描述

10. 多对一的处理

10.1 准备工作


两个实体类(使用了lombok的注解):
student类:

package com.itholmes.pojo;

import lombok.Data;

@Data
public class Student {

    private int id;
    private String name;

    //学生需要关联一个老师,多对一关联的效果。
    private Teacher teacher;

}

(注意:这里我们与数据库不对应!原本是tid,这里我们设置为teacher对象来达到数据库中外键关联的效果。)
在这里插入图片描述


teacher类:

package com.itholmes.pojo;

import lombok.Data;

@Data
public class Teacher {
    private int id;
    private String name;
}

StudentMapper接口类:

package com.itholmes.dao;

import com.itholmes.pojo.Student;

import java.util.List;

public interface StudentMapper {
    //查询所有的学生信息,以及对应的老师的信息
    public List<Student> getStudent();
}

TeacherMapper接口类:

package com.itholmes.dao;

import com.itholmes.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface TeacherMapper {
    @Select("select * from teacher where id = #{tid}")
    Teacher getTeacher(@Param("tid") int id);
}

在resources中准备上面两个接口对应的Mapper.xml文件,注意resources中创建包的问题!
在这里插入图片描述
在这里插入图片描述

为了方便测试,我们写一个select语句查询student。


测试类:

package com.itholmes;

import com.itholmes.dao.StudentMapper;
import com.itholmes.dao.TeacherMapper;
import com.itholmes.pojo.Student;
import com.itholmes.pojo.Teacher;
import com.itholmes.utils.MybatisSqlSession;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class MyTest {

    @Test
    public void test(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> list = mapper.getStudent();

        for (Student student : list) {
            System.out.println(student);
        }

        sqlSession.close();
    }

}

在这里插入图片描述

10.2 resultMap中的association关联(一对多处理)


为了达到让teacher对象得到数据库的效果:

通过resultMap和association来关联处理对象有两种形式:

第一种:按照查询嵌套处理:

修改StudentMapper.xml的配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itholmes.dao.StudentMapper">

	<!--方式一:按照查询嵌套处理-->

    <select id="getStudent" resultMap="StudentTeacher">
        select * from student;
    </select>
    
    <resultMap id="StudentTeacher" type="Student">

        <result property="id" column="id"/>
        <result property="name" column="name"/>

        <!--
            对于复杂的属性,我们需要单独处理!
                association专门处理对象
                collection专门处理集合

                association处理的是对象因此需要设置类型,这里使用javaType给他设置类型。此外,还有嵌套查询:select属性。
        -->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" resultType="Teacher">
        select * from teacher where id = #{id}
    </select>

</mapper>

StudentMapper接口类:

package com.itholmes.dao;

import com.itholmes.pojo.Student;

import java.util.List;

public interface StudentMapper {
    //查询所有的学生信息,以及对应的老师的信息
    public List<Student> getStudent();
    public List<Student> getStudent2();
}

测试类:

@Test
public void test(){
    SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();

    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    List<Student> list = mapper.getStudent();

    for (Student student : list) {
        System.out.println(student);
    }

    sqlSession.close();
}

第二种:按照结果嵌套处理:

修改StudentMapper.xml的配置:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itholmes.dao.StudentMapper">

    <!--方式二:按照结果嵌套处理-->
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id as sid , s.name as sname , t.name as tname
        from student s,teacher t
        where s.tid = t.id;
    </select>

    <resultMap id="StudentTeacher2" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="name" column="tname"/>
        </association>
    </resultMap>

</mapper>

测试类:

@Test
public void test2(){
    SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

    List<Student> list = mapper.getStudent2();

    for (Student student : list) {
        System.out.println(student);
    }

    sqlSession.close();
}

上面的这些效果操作,就是多对一的效果,多个学生的tid对应了老师的id。

在我们mysql中操作方式,多对一的效果一般是靠两种:

  • 子查询(嵌套查询语句),就像上面的按照查询嵌套处理。
  • 联表查询,就像上面的按照结果嵌套处理。

11. 一对多处理

11.1 准备工作


就像一个老师拥有(集合)多个学生。

这就是一对多的效果。

重新修改实体类:

Teacher类

package com.itholmes.pojo;

import lombok.Data;
import java.util.List;

@Data
public class Teacher {
    private int id;
    private String name;

    //一个老师拥有多个学生,一对多集合的效果。
    private List<Student> students;
}

Student类

package com.itholmes.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}

11.2 resultMap中的collection集合(一对多处理)


同样的两种方式。

方式一:按照结果嵌套处理。

修改TeacherMapper.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itholmes.dao.TeacherMapper">
    <!--方式一:按照结果嵌套处理-->
    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid ,s.name sname,t.name tname ,t.id tid
        from student s , teacher t
        where s.tid = t.id and t.id = #{tid};
    </select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>

        <!--
            一对多,这里就用到了集合。

                javaType来指定属性的类型。但是这里的类型是List<Studnet>的类型。
                对于这种集合中的泛型信息,我们使用ofType获取。
        -->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

</mapper>

TeacherMapper接口类:

package com.itholmes.dao;

import com.itholmes.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface TeacherMapper {

    //获取指定老师下的所有学生以及老师的信息,也就是多对一
    Teacher getTeacher(@Param("tid") int id);

}

测试类:

import com.itholmes.dao.StudentMapper;
import com.itholmes.dao.TeacherMapper;
import com.itholmes.pojo.Student;
import com.itholmes.pojo.Teacher;
import com.itholmes.service.MybatisSqlSession;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class MyTest {

    @Test
    public void test(){
        SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);

        /*
            查询出来的结果如下:
        * Teacher(
        * id=1,
        * name=秦老师,
        * students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)]
        * )
        * */

        sqlSession.close();
    }

}

方式二:按照查询嵌套处理。

TeacherMapper.xml文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itholmes.dao.TeacherMapper">

    <!--第二种方式:按照查询嵌套处理-->
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from mybatis.teacher where id = #{tid};
    </select>
    
    <resultMap id="TeacherStudent2" type="Teacher">
        <result property="id" column="id"/>
        <result property="name" column="name"/>

        <!--
            这里注意了Teacher实体类中,有一个Student的List集合,来做映射了。
            这里的column就是得到我们老师的id的字段,将老师的id的字段内容传入到下面的#{xxx}中,这里的xxx可以随便写。
        -->
        <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherID" column="id"/>
    </resultMap>

    <select id="getStudentByTeacherID" resultType="Student">
        select * from mybatis.student where tid = #{ABCdedv};
    </select>
    
</mapper>

TeacherMapper接口类:

package com.itholmes.dao;

import com.itholmes.pojo.Teacher;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface TeacherMapper {

    //获取指定老师下的所有学生以及老师的信息,也就是多对一
    Teacher getTeacher(@Param("tid") int id);

    Teacher getTeacher2(@Param("tid") int id);

}

测试类:

@Test
public void test2(){
    SqlSession sqlSession = MybatisSqlSession.getMybatisSqlSession();

    TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
    Teacher teacher2 = mapper.getTeacher2(1);
    System.out.println(teacher2);

    /*
        Teacher(
        id=1,
        name=秦老师,
        students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)]
        )
     */

    sqlSession.close();
}

在这里插入图片描述

SQL语句是有快慢的问题,加不加索引等等一系列问题。SQL语句的优化是很重要的!

面试高频的问题:

  • mysql引擎。
  • innodb底层原理。
  • 索引。
  • 索引优化。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xupengboo

你的鼓励将是我创作最大的动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值