Mybatis

Mybatis

1、简介

1.0、相关知识

DAO 模式

DAO (DataAccessobjects 数据存取对象)是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。

对外提供相应的接口

在面向对象设计过程中,有一些"套路”用于解决特定问题称为模式。

DAO 模式提供了访问关系型数据库系统所需操作的接口,将数据访问和业务逻辑分离对上层提供面向对象的数据访问接口。

从以上 DAO 模式使用可以看出,DAO 模式的优势就在于它实现了两次隔离。

  • 1、隔离了数据访问代码和业务逻辑代码。业务逻辑代码直接调用DAO方法即可,完全感觉不到数据库表的存在。分工明确,数据访问层代码变化不影响业务逻辑代码,这符合单一职能原则,降低了藕合性,提高了可复用性。
  • 2、隔离了不同数据库实现。采用面向接口编程,如果底层数据库变化,如由 MySQL 变成 Oracle 只要增加 DAO 接口的新实现类即可,原有 MySQ 实现不用修改。这符合 “开-闭” 原则。该原则降低了代码的藕合性,提高了代码扩展性和系统的可移植性。

一个典型的DAO 模式主要由以下几部分组成。

  • 1、DAO接口: 把对数据库的所有操作定义成抽象方法,可以提供多种实现。
  • 2、DAO 实现类: 针对不同数据库给出DAO接口定义方法的具体实现。
  • 3、实体类:用于存放与传输对象数据。
  • 4、数据库连接和关闭工具类: 避免了数据库连接和关闭代码的重复使用,方便修改。

1.1、什么是Mybatis?

​ MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.2、持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化
  • 生活:冷藏,罐头

为什么需要持久化?

  • 有一些对象,不能让他丢掉
  • 内存太贵了、

1.3、持久层

Dao层、Service层、Controller层

  • 完成持久化工作的代码快
  • 层界限十分明显

1.4、为什么需要Mybatis?

  • 帮助程序员将数据存到数据库里
  • 传统的JDBC代码太复杂了,简化,框架,自动化

2、第一个Mybatis程序

2.1、搭建环境

搭建数据库

CREATE DATABASE `Mybatis`;
USE `Mybatis`;

CREATE TABLE `user`(
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(10) DEFAULT NULL,
`pwd` VARCHAR(10) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `user`(`id`,`name`,`pwd`) VALUES 
(1,'zhangsan','123456'),
(2,'lisi','123456'),
(3,"wangwu","123456");

新建项目

  1. 新建一个普通的Maven项目

  2. 删除src目录

  3. 导入Maven依赖

      <!--  导入依赖  -->
        <dependencies>
            <!--Mybatis-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.2</version>
            </dependency>
            <!--MySQL驱动-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
            <!--junit-->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.13.2</version>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    
  4. 当配置文件不在resources目录下时,为时Maven能读到配置文件,可在核心配置文件中配置

    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
    

2.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>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="org/mybatis/example/BlogMapper.xml"/>
        </mappers>
    </configuration>
    
  • 编写Mybatis工具类

    public class MybatisUtils {
        private static SqlSessionFactory sqlSessionFactory;
        static {
            try {
                // 使用Mybatis第一步,获取sqlSessionFactory对象
                String resource = "mybatis-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        // 获得SqlSession对象,该对象中包含了面向数据库执行SQL的所有方法,相当于JDBC中的prestatement
        public static SqlSession getSqlSession(){
            return sqlSessionFactory.openSession();
        }
    }								
    

2.3、编写代码

实体类

package com.sjq.pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

Dao

package com.sjq.dao;

import com.sjq.pojo.User;

import java.util.List;

public interface UserDao {
    List<User> getUserList();
}

接口实现类:由原来的UserDaoImpl变为UserMapper

UserDaoImpl

package com.sjq.dao;

import com.sjq.pojo.User;

import java.util.List;

public class UserDaoImpl implements UserDao{
    @Override
    public List<User> getUserList() {
        return null;
    }
}

UserMapper

<?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 = 绑定一个对应的Dao/mapper接口-->
<mapper namespace="com.sjq.dao.UserDao">
    <select id="getUserList" resultType="com.sjq.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

易错点

<!--namespace 路径用的”.“,不能用"/"-->
<mapper namespace="com.sjq.dao.UserDao">
    <select id="getUserList" resultType="com.sjq.pojo.User">
        select * from mybatis.user
    </select>
</mapper>

<mapper namespace="com/sjq/dao/UserDao">
    <select id="getUserList" resultType="com.sjq.pojo.User">
        select * from mybatis.user
    </select>
</mapper>
org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 189 milliseconds ago.  The last packet sent successfully to the server was 184 milliseconds ago.
### The error may exist in com/sjq/dao/UserMapper.xml
### The error may involve com.sjq.dao.UserDao.getUserList
### The error occurred while executing a query
### Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure


解决办法:将useSSL设置为false

编写测试类

package com.sjq.dao;

import com.sjq.pojo.User;
import com.sjq.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class TestUserDao {

    @Test
    public void test(){
        // 获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        try {
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            List<User> userList = userDao.getUserList();
            
            for (User user : userList) {
                System.out.println(user);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        // 官网建议写法,用try catch finally,保证每次请求后SqlSession都被关闭
        finally {
            // 关闭SqlSession
            sqlSession.close();
        }
    }
}

3、CRUD

3.1、namespace

namespace中的包名要和Dao/Mapper 接口的包名一致

3.2、select

选择查询语句:

  • id:就是对应的namespace中的方法名
  • resultType:Sql语句执行的返回值
  • parameterType:参数类型
  1. 编写接口

    // 查询指定id的用户
    User getUserById(int id);
    
  2. 编写对应的Mapper中的Sql语句

    <select id="getUserById" parameterType="int" resultType="com.sjq.pojo.User">
        select * from mybatis.user where id = #{id}
    </select>
    
  3. 测试

    @Test
    public void TestGetUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
    
        sqlSession.close();
    }
    
  4. 注意:增删改需要提交事务

3.3、万能Map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑使用Map

  1. 创建方法

    // 使用Map修改部分信息
    int updateUserByMap(Map<String,Object> map);
    
  2. 编写Sql

    <!--用map修改信息-->
    <update id="updateUserByMap" parameterType="map">
        update mybatis.user
        set pwd  = #{password}
        where id = #{userId};
    </update>
    
  3. 测试

    // 用map修改信息
    @Test
    public void TestUpdateUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        HashMap<String, Object> map = new HashMap<>();
        map.put("userId",2);
        map.put("password","111222333");
        int i = mapper.updateUserByMap(map);
    
        sqlSession.commit();
        sqlSession.close();
    
    }
    
  4. 小结:Map传递参数,直接在SQL中取出key即可

    ​ 对象传递参数,直接在sql中取对象的属性即可

    ​ 只有一个基本类型参数的情况下,可以直接在sql中取到

    ​ 多个参数用Map,或者注解

3.4、模糊查询

模糊查询怎么写?

  1. Java代码执行的时候,传递通配符%%

  2. 在sql拼接中使用通配符!

    SELECT * FROM USER where name like "%"#{value}"%"
    

4、配置分析

4.1、核心配置文件

configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

4.2、环境配置

Mybatis可以配置成适应多种环境

不过要记住:每个SqlSessionFactory实例只能选择一种环境

Mybatis默认的事务管理器是JDBC,连接池:POOLED

4.3、属性(properties)

我们可以通过properties属性来实现引用配置文件。

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

  1. 写一个配置文件db.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC
username=root
password=123456
  1. 引入配置文件

    <properties resource="db.properties"/>
    

    注:如果需要文件找不到,则在pom.xml中配置资源过滤

4.4、类型别名

  • 类型别名是为Java类型设置一个短的名字

  • 存在的意义仅在于用来减少类完全限定名的冗余

    <!--给实体类取别名-->
    <typeAliases>
        <typeAlias type="com.sjq.pojo.User" alias="user"/>
    </typeAliases>
    
    <!--指定一个包取别名,mybatis会扫描包下的所有实体类,默认别名为类的类名,首字母小写-->
    <typeAliases>
        <package name="com.sjq.pojo"/>
    </typeAliases>
    

    在实体类比较少的时候,用第一种方式。

    实体类较多,用第二种。

    也可用注解。

    @Alias("hello")
    public class User {
        private int id;
        private String name;
        private String pwd;
    
    

4.5、设置

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUY24wAw-1629453620826)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210813025148185.png)]

4.6、映射器(Mapper)

MapperRegistry:注册绑定我们的Mapper文件

方式一:配置文件绑定

<!--每一个Mapper.xml都需要在mybatis的核心配置文件中注册-->
<mappers>
    <mapper resource="com/sjq/mapper/UserMapper.xml"/>
</mappers>

方式二:使用class文件绑定注册

<mappers>
    <mapper class="com.sjq.mapper.UserMapper"/>
</mappers>

注意点:

  • 接口与它的Mapper配置文件必须同名
  • 接口与它的Mapper配置文件必须在同一个包下

方式三:使用扫描包进行注入绑定

<mappers>
    <package name="com.sjq.mapper"/>
</mappers>

注意点:

  • 接口与它的Mapper配置文件必须同名
  • 接口与它的Mapper配置文件必须在同一个包下

4.7、生命周期与作用域

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

数据库中的字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rKD394tw-1629453620828)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210813034216029.png)]

新建一个项目,拷贝之前的,测试实体类字段不一致的情况

public class User {
    private int id;
    private String name;
    private String password;

测试出现问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IkLbwuht-1629453620829)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210813034339900.png)]

解决办法:

  • 起别名

    <select id="getUserById" parameterType="int" resultType="com.sjq.pojo.User">
        <!--如果报错,将#改成%-->
        select id,`name`,pwd as password from mybatis.user where id = #{id}
    </select>
    
  • 结果集映射

    <mapper namespace="com.sjq.mapper.UserMapper">
        <!--结果集映射-->
        <resultMap id="UserMap" type="User">
            <result  column="id" property="id"/>
            <result  column="name" property="name"/>
            <result  column="pwd" property="password"/>
        </resultMap>
        <select id="getUserById" resultMap="UserMap">
            select * from mybatis.user where id = #{id}
        </select>
    </mapper>
    

6、日志

6.1、日志工厂

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

曾经:sout,debug

现在:日志工厂

配置日志

<settings>
    <!--标准的日志工厂实现-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

输出结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Pj02LVM-1629453620830)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210813044059306.png)]

6.2、Log4j

什么是log4j?

  • Log4j是Apache的一个开源项目
  • 通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;
  • 可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
  • 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。
  1. 先导入log4j的包

    <!--log4j-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  2. 编写log4j的配置文件

    
    # priority  :debug<info<warn<error
    #you cannot specify every priority with different file for log4j 
    log4j.rootLogger=debug,stdout,info,debug,warn,error 
     
    #console
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender 
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
    log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
    #info log
    log4j.logger.info=info
    log4j.appender.info=org.apache.log4j.DailyRollingFileAppender 
    log4j.appender.info.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.info.File=./src/com/hp/log/info.log
    log4j.appender.info.Append=true
    log4j.appender.info.Threshold=INFO
    log4j.appender.info.layout=org.apache.log4j.PatternLayout 
    log4j.appender.info.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #debug log
    log4j.logger.debug=debug
    log4j.appender.debug=org.apache.log4j.DailyRollingFileAppender 
    log4j.appender.debug.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.debug.File=./src/com/hp/log/debug.log
    log4j.appender.debug.Append=true
    log4j.appender.debug.Threshold=DEBUG
    log4j.appender.debug.layout=org.apache.log4j.PatternLayout 
    log4j.appender.debug.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #warn log
    log4j.logger.warn=warn
    log4j.appender.warn=org.apache.log4j.DailyRollingFileAppender 
    log4j.appender.warn.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.warn.File=./src/com/hp/log/warn.log
    log4j.appender.warn.Append=true
    log4j.appender.warn.Threshold=WARN
    log4j.appender.warn.layout=org.apache.log4j.PatternLayout 
    log4j.appender.warn.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    #error
    log4j.logger.error=error
    log4j.appender.error = org.apache.log4j.DailyRollingFileAppender
    log4j.appender.error.DatePattern='_'yyyy-MM-dd'.log'
    log4j.appender.error.File = ./src/com/hp/log/error.log 
    log4j.appender.error.Append = true
    log4j.appender.error.Threshold = ERROR 
    log4j.appender.error.layout = org.apache.log4j.PatternLayout
    log4j.appender.error.layout.ConversionPattern = %d{yyyy-MM-dd HH:mm:ss a} [Thread: %t][ Class:%c >> Method: %l ]%n%p:%m%n
    
  3. 设置日志实现为log4j

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
  4. 输出结果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7OwRBFtz-1629453620831)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20210813050411350.png)]

  5. 简单使用

    • 在要使用log4j的类中,导入包import org.apache.log4j.Logger;

    • 获得日志对象,参数为当前类的class

      static Logger logger = Logger.getLogger(TestUserDao.class);
      
    • 日志级别

      logger.info("info:进入了log4j");
      logger.debug("debug:进入了log4j");
      logger.error("error:进入了log4j");
      

7、分页

思考:为什么要分页?

  • 减少数据的处理量

7.1、使用limit分页

select * from user limit beginIndes,pagesize

使用Mybatis实现分页

  1. 接口

    // 分页查询
    List<User> getUserByLimit(Map<String,Integer> map);
    
  2. Mapper.xml

    <!--结果集映射-->
    <resultMap id="UserMap" type="User">
        <result  column="id" property="id"/>
        <result  column="name" property="name"/>
        <result  column="pwd" property="password"/>
    </resultMap>
    
    <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
        select * from mybatis.user limit #{startIndex},#{pageSize}
    </select>
    
  3. 测试

    @Test
    public void TestGetUserByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Integer> map = new HashMap<>();
        map.put("startIndex",1);
        map.put("pageSize",2);
        List<User> userByLimit = mapper.getUserByLimit(map);
        for (User user : userByLimit) {
            System.out.println(user);
        }
    
        sqlSession.close();
    }
    

8、使用注解开发

  1. 在接口上加注解

    @Select("select * from user")
    List<User> getUser();
    
  2. 在核心配置文件绑定接口

    <!--绑定接口-->
    <mappers>
        <mapper class="com.sjq.mapper.UserMapper"/>
    </mappers>
    
  3. 测试

    @Test
    public void TestGetUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> user = mapper.getUser();
        for (User user1 : user) {
            System.out.println(user1);
        }
        sqlSession.close();
    }
    
  • 可以在工具类中设置自动提交事务

    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
    }
    
  • 当方法参数有多个时,每个参数都要加@Param("pid")

    // 方法存在多个参数时,必须加上@Param(”“)注解
    @Select("select * from user where id = #{pid}")
    User getUserById(@Param("pid") int id);
    

关于@Param("pid")注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议加上
  • 我们在SQL中引用的就是这里面的设定值

9、Lombok

使用步骤:

  1. 在IDEA中安装Lombok插件!

  2. 在项目中导入依赖

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>
    
  3. 在实体类上或字段上加注解

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
        private int id;
        private String name;
        private String password;
    }
    
    
    @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
    Lombok config system
    Code inspections
    Refactoring actions (lombok and delombok)
    

    注解解释:

    @Data:生成get/set/tostring/equal/hashcode方法
    @AllArgsConstructor:生成带参构造方法
    @NoArgsConstructor:生成无参构造方法
    

10、多对一处理

测试环境搭建

  1. 导入Lombok
  2. 新建实体类
  3. 新建Mapper接口
  4. 建立Mapper.xml文件
  5. 在核心配置文件中注册绑定Mapper接口或者文件
  6. 测试查询是否成功

按照查询嵌套处理

<mapper namespace="com.sjq.mapper.StudentMapper">
    <!--
    思路:
        1.查询所有的学生信息
        2.根据查询出来的学生的tid,查询老师信息
        该方式属于子查询
    -->
    <select id="getStudent" resultMap="studentTeacher">
        select * from student
    </select>
    <resultMap id="studentTeacher" type="student">
        <association property="teacher" javaType="teacher" column="tid" select="getTeacher"/>
    </resultMap>
    <select id="getTeacher" resultType="teacher">
        select * from teacher where id = #{id}
    </select>
</mapper>

按照结果嵌套处理

<!--按照结果嵌套处理-->
<select id="getStudent2" resultMap="studentTeacher2">
    select s.id sid,s.name sname,t.name tname,t.id tid
    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="id" column="tid"/>
        <result property="name" column="tname"/>
    </association>
</resultMap>

11、一对多处理

测试环境搭建

一个老师可以有多个学生,对于老师来说就是一对多。

实体类:

@Data
public class Student {
    private int id;
    private String name;
    private int tid;
}
@Data
public class Teacher {
    private int id;
    private String name;
    private List<Student> students;
}

按照结果嵌套查询

<!--按照结果嵌套处理-->
<select id="getTeacherById" resultMap="teacherStudent">
    select s.id sid,s.name sname,s.tid stid,t.name tname,t.id tid
    from student s,teacher t
    where t.id = #{tid} and t.id = s.tid
</select>
<resultMap id="teacherStudent" type="teacher">
    <result property="id" column="tid"/>
    <result property="name" column="tname"/>
    <!--复杂的属性需要单独处理,对象:association   集合:collection
            javaType:指定属性的类型
            集合中的泛型信息,我们用ofType获取
            -->
    <collection property="students" ofType="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="stid"/>
    </collection>
</resultMap>

按照查询嵌套处理

<!--按照查询嵌套处理-->
<select id="getTeacherById2" resultMap="teacherStudent2">
    select * from teacher where id = #{tid}
</select>
<resultMap id="teacherStudent2" type="teacher">
    <result property="id" column="id"/>
    <collection property="students" javaType="ArrayList" ofType="student" column="id" select="getStudent"/>
</resultMap>
<select id="getStudent" resultType="student">
    select * from student where tid = #{id}
</select>

小结

  1. 关联 - association 多对一
  2. 集合 - collection 一对多
  3. javaType & ofType
    • javaType 用来指定实体类中的类型
    • ofType 用来指定映射到List或者集合中的POJO类型,泛型中的约束类型

注意点:

  1. 保证SQL的可读性,尽量保证通俗易懂
  2. 保证一对多、多对一中,属性名和字段的问题
  3. 如果问题不好排查错误,可以使用日志,建议使用Log4j

12、动态SQL

​ 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

if
choose (when, otherwise)
trim (where, set)
foreach

搭建环境

create table blog
(
    id          varchar(30)  not null comment '博客id',
    title       varchar(200) not null comment '博客标题',
    author      varchar(30)  not null comment '博客作者',
    create_time datetime     not null comment '创建时间',
    view        int(30)      not null comment '浏览量'
);

创建一个基础工程:

  1. 导包
  2. 编写核心配置文件
  3. 编写实体类
  4. 编写实体类的接口与对应的XML文件

生成随机ID

package com.sjq.utils;

import org.junit.jupiter.api.Test;

import java.util.UUID;

@SuppressWarnings("all")  //抑制警告
public class IDUtils {
    public static String getId(){
        return UUID.randomUUID().toString().replaceAll("-","");
    }

    @Test
    public void test(){
        System.out.println(IDUtils.getId());
    }
}

IF

<select id="getBlog" parameterType="map" resultType="Blog">
    select * from blog where 1 =1
    <if test="title != null">
        and title = #{title}
    </if>
</select>

choose(when,otherwise)

<select id="getBlog" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise >
                and view = #{view}
            </otherwise>
        </choose>
    </where>
</select>

trim(where,set)

<select id="getBlog" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <if test="title != null">
            and title = #{title}
        </if>
    </where>
</select>
<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author}
        </if>
    </set>
    where id = #{id}
</update>

SQL片段

有的时候,我们会将一些SQL提取出来,进行复用

  1. 使用SQL标签抽取公共的部分
  2. 在需要使用的地方使用include标签引用即可

if test=“title != null”>
and title = #{title}


### choose(when,otherwise)

```XML
<select id="getBlog" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <choose>
            <when test="title != null">
                and title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise >
                and view = #{view}
            </otherwise>
        </choose>
    </where>
</select>

trim(where,set)

<select id="getBlog" parameterType="map" resultType="Blog">
    select * from blog
    <where>
        <if test="title != null">
            and title = #{title}
        </if>
    </where>
</select>
<update id="updateBlog" parameterType="map">
    update blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author}
        </if>
    </set>
    where id = #{id}
</update>

SQL片段

有的时候,我们会将一些SQL提取出来,进行复用

  1. 使用SQL标签抽取公共的部分
  2. 在需要使用的地方使用include标签引用即可

Foreach

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值