[MyBatis系列⑤]多表查询 | 一篇万字长文带你上手三种多表查询方式及其对象封装过程

news2024/9/28 7:17:45

目录

1、简介

2、业务场景及环境准备

2.1、环境

2.2、ER图

2.3、SQL

3、一对一

3.1、POJO

3.2、OrderMapper.xml

3.3、resultMap

3.4、执行结果

4、一对多

4.1、POJO

4.2、UserMapper.xml

4.3、resultMap

4.4、执行结果

5、多对多

5.1、POJO

5.2、UserMapper.xml

5.3、执行结果

6、注意事项


🍃作者简介:准大三本科网络工程专业在读,持续学习Java,努力输出优质文章

⭐MyBatis系列①:增删改查

⭐MyBatis系列②:两种Dao开发方式

⭐MyBatis系列③:动态SQL

⭐MyBatis系列④:核心配置文件详解

1、简介

MyBatis 是一个优秀的持久层框架,它提供了强大的支持来执行数据库操作,包括多表查询。多表查询是指从多个数据库表中检索数据的过程,这在实际的应用中非常常见。MyBatis 提供了多种方法来执行多表查询,以下是一些常见的技术和方法:

  1. 使用嵌套查询: 这是最基本的多表查询方法,通过在 SQL 语句中嵌套子查询来联合多个表的数据。例如,你可以在 SELECT 语句中使用子查询来从一个表中获取数据,然后再将其用于主查询中。这种方法在某些简单情况下是有效的,但对于复杂的多表查询可能会变得冗长和难以维护。
  2. 使用多个 SQL 语句: 在 MyBatis 中,你可以编写多个独立的 SQL 语句,每个语句都从一个表中检索数据,然后在 Java 代码中将这些数据组合起来。这通常需要在 Java 代码中手动执行每个查询并进行数据处理,但对于一些复杂的多表查询情况可能更加灵活。
  3. 使用关联查询: MyBatis 支持使用关联查询来执行多表查询,特别是在映射文件中配置了表之间的关联关系。通过在 Mapper XML 文件中配置 associationcollection 来表示表之间的关联关系,MyBatis 可以自动根据关系从多个表中检索数据并构造结果对象。
  4. 使用自定义映射查询: 有时候,多表查询的结果可能不适合于一个实体类,这时你可以使用自定义映射查询来将结果映射到一个 Map 或者其他自定义的数据结构中,以适应查询的需要。

无论使用哪种方法,多表查询都需要仔细考虑性能和结果的数据结构。在执行多表查询时,需要注意数据库表之间的关联关系、连接方式(内连接、左连接等)以及查询结果的组织方式,以便在查询结果中获取所需的数据。 MyBatis 的强大灵活性使得你可以根据实际情况选择合适的方法来执行多表查询。

2、业务场景及环境准备

模拟的业务场景为订单与用户的关系,可以是一对一、一对多。

比如,一个用户有多个订单,一个订单只有一个用户。

还有就是用户与角色的关系,多个用户拥有多个角色,一个角色可以被多个用户拥有,一个用户可以拥有多个角色。

2.1、环境

下面准备四张表:

ordersQuery

userQuery

roleQuery

user_role

2.2、ER图

2.3、SQL

CREATE TABLE `rolequery` (
  `id` bigint(20) NOT NULL,
  `roleName` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `rolequery`(`id`,`roleName`) VALUES (1,'CEO'),(2,'CFO'),(3,'COO');

CREATE TABLE `userquery` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `password` varchar(50) DEFAULT NULL,
  `birthday` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `userquery`(`id`,`username`,`password`,`birthday`)
VALUES (1,'lucy','123','2019-02-15'),
       (2,'tom','123','2002-10-26');

CREATE TABLE `user_role` (
  `user_id` bigint(20) NOT NULL,
  `role_id` bigint(20) NOT NULL,
  PRIMARY KEY (`user_id`,`role_id`),
  CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `userquery` (`id`),
  CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `rolequery` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/* 插入数据到表 'user_role' */
INSERT INTO `user_role`(`user_id`,`role_id`) VALUES (1,1),(1,2),(2,2),(2,3);

CREATE TABLE `ordersquery` (
  `id` INT(11) NOT NULL,
  `ordertime` VARCHAR(255),
	`total` DOUBLE,
	`userID` BIGINT(20) NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `orders_user_ibfk` FOREIGN KEY (`userID`) REFERENCES `userquery` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `ordersquery` (`id`,`ordertime`,`total`,`userID`)
VALUES (1,'1693059342876','3000',1),
       (2,'1693059342876','4000',1),
       (3,'1693059342876','5000',2);

3、一对一

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

对应的SQL语句:

select ordersquery.*, userquery.username,userquery.`password`,userquery.birthday from ordersquery, userquery where ordersquery.userID = userquery.id;

3.1、POJO

User

package com.xzl.domain;


/**
 * @author 逐梦苍穹
 * @date 2023/8/26 16:48
 */
public class User {
    private int id;
    private String username;
    private String password;
    private String birthday;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday=" + birthday +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}

Order

package com.xzl.domain;

import java.util.Date;

/**
 * @author 逐梦苍穹
 * @date 2023/8/26 16:48
 */
public class Order {
    private int id;
    private Date ordertime;
    private double total;
    //这个地方数据库里面的表单是"userID",但是这里应该封装整个User对象
    private User user;

    @Override
    public String toString() {
        return "Order{" +
                "id=" + id +
                ", ordertime=" + ordertime +
                ", total=" + total +
                ", user=" + user +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public Date getOrdertime() {
        return ordertime;
    }

    public void setOrdertime(Date ordertime) {
        this.ordertime = ordertime;
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

3.2、OrderMapper.xml

OrderMapper.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.xzl.dao.OrderMapper">
    <resultMap id="OrderMapper" type="com.xzl.domain.Order">
        <!--column通过SQL语句查询出来的字段,property对应的实体属性-->
        <id column="id" property="id"/>
        <result column="ordertime" property="ordertime"/>
        <result column="total" property="total"/>
        <result column="userId" property="user.id"/>
        <result column="username" property="user.username"/>
        <result column="password" property="user.password"/>
        <result column="birthday" property="user.birthday"/>
    </resultMap>

    <resultMap id="OrderMapperAssociation" type="com.xzl.domain.Order">
        <!--column通过SQL语句查询出来的字段,property对应的实体属性-->
        <id column="id" property="id"/>
        <result column="ordertime" property="ordertime"/>
        <result column="total" property="total"/>
        <!--
            property: 当前实体(order)中的属性名称(private User user)
            javaType: 当前实体(order)中的属性的类型(User)
        -->
        <association property="user" javaType="com.xzl.domain.User">
            <id column="userId" property="id"/>
            <result column="username" property="username"/>
            <result column="password" property="password"/>
            <result column="birthday" property="birthday"/>
        </association>
    </resultMap>

    <select id="findAll" resultMap="OrderMapperAssociation">
        SELECT ordersquery.id,
               ordersquery.ordertime,
               ordersquery.total,
               userquery.id AS userId,
               userquery.username,
               userquery.password,
               userquery.birthday
        FROM ordersquery,
             userquery
        WHERE ordersquery.userID = userquery.id;
    </select>
</mapper>

3.3、resultMap

OrderMapper.xml中的resultMap有两种写法:

这个部分其实就是手动指定字段与实体属性的映射关系

(column: 数据表的字段名称

property:实体的属性名称)

写法①:

写法②:

3.4、执行结果

4、一对多

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

4.1、POJO

相比之前一对一的POJO,变化在于User类多了一个List<Order> orderList。

(两个POJO代码里面的toString正常写就可以,这里只是为了方便测试):

User

package com.xzl.domain;

import java.util.List;

/**
 * @author 逐梦苍穹
 * @date 2023/8/26 16:48
 */
public class User {
    private int id;
    private String username;
    private String password;
    private String birthday;
    private List<Order> orderList;

    @Override
    public String toString() {
        return orderList == null ? "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday=" + birthday +
                '}' : "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday='" + birthday + '\'' +
                ", orderList=" + orderList +
                '}';
    }

    public List<Order> getOrderList() {
        return orderList;
    }

    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}

Order

package com.xzl.domain;

import java.util.Date;

/**
 * @author 逐梦苍穹
 * @date 2023/8/26 16:48
 */
public class Order {
    private int id;
    private Date ordertime;
    private double total;
    //这个地方数据库里面的表单是"userID",但是这里应该封装整个User对象
    private User user;

    @Override
    public String toString() {
        return user == null ? "Order{" +
                "id=" + id +
                ", ordertime=" + ordertime +
                ", total=" + total +
                '}' : "Order{" +
                "id=" + id +
                ", ordertime=" + ordertime +
                ", total=" + total +
                ", user=" + user +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public Date getOrdertime() {
        return ordertime;
    }

    public void setOrdertime(Date ordertime) {
        this.ordertime = ordertime;
    }

    public double getTotal() {
        return total;
    }

    public void setTotal(double total) {
        this.total = total;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }
}

4.2、UserMapper.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.xzl.dao.UserMapper">
    <resultMap id="UserMapper" type="com.xzl.domain.User">
        <!--column通过SQL语句查询出来的字段,property对应的实体属性-->
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
        <!--配置集合信息
            property:集合名称
            ofType:当前集合中的数据类型
        -->
        <collection property="orderList" ofType="com.xzl.domain.Order">
            <id column="orderID" property="id"/>
            <result column="ordertime" property="ordertime"/>
            <result column="total" property="total"/>
        </collection>
    </resultMap>

    <select id="findAll" resultMap="UserMapper">
        SELECT userquery.*,
               ordersquery.id AS orderID,
               ordersquery.ordertime,
               ordersquery.total
        FROM userquery
                 LEFT JOIN ordersquery ON userquery.id = ordersquery.userID;
    </select>
</mapper>

4.3、resultMap

UserMapper.xml的resultMap相比于OrderMapper.xml的写法略有不同,区别在于这里需要封装的是对象集合,而不是单个对象:

4.4、执行结果

5、多对多

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色

5.1、POJO

相比之前一对一的POJO,变化在于User类多了一个List<Role> roleList。

User(toString正常写就可以,这里只是为了方便测试):

package com.xzl.domain;

import java.util.List;

/**
 * @author 逐梦苍穹
 * @date 2023/8/26 16:48
 */
public class User {
    private int id;
    private String username;
    private String password;
    private String birthday;
    private List<Order> orderList;
    private List<Role> roleList;

    @Override
    public String toString() {
        if (orderList==null && roleList==null){
            return "User{" +
                    "id=" + id +
                    ", username='" + username + '\'' +
                    ", password='" + password + '\'' +
                    ", birthday='" + birthday + '\'' +
                    '}';
        }else {
            if (orderList==null){
                return "User{" +
                        "id=" + id +
                        ", username='" + username + '\'' +
                        ", password='" + password + '\'' +
                        ", birthday='" + birthday + '\'' +
                        ", roleList=" + roleList +
                        '}';
            }else {
                        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", birthday='" + birthday + '\'' +
                ", orderList=" + orderList +
                '}';
            }
        }
    }

    public List<Role> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<Role> roleList) {
        this.roleList = roleList;
    }

    public List<Order> getOrderList() {
        return orderList;
    }

    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }

    public int getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }
}

Role

package com.xzl.domain;

import java.util.Date;

/**
 * @author 逐梦苍穹
 * @date 2023/8/26 16:48
 */
public class Role {
    private int id;
    private String rolename;

    @Override
    public String toString() {
        return "Role{" +
                "id=" + id +
                ", rolename='" + rolename + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

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

    public String getRolename() {
        return rolename;
    }

    public void setRolename(String rolename) {
        this.rolename = rolename;
    }
}

5.2、UserMapper.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.xzl.dao.UserMapper">
    <resultMap id="userRoleMap" type="com.xzl.domain.User">
        <!--column通过SQL语句查询出来的字段,property对应的实体属性-->
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="birthday" property="birthday"/>
        <!--配置集合信息
            property:集合名称
            ofType:当前集合中的数据类型
        -->
        <collection property="roleList" ofType="com.xzl.domain.Role">
            <id column="roleID" property="id"/>
            <result column="rolename" property="rolename"/>
        </collection>
    </resultMap>

    <select id="findAllUserAndRole" resultMap="userRoleMap">
        SELECT userquery.id,
               userquery.username,
               userquery.`password`,
               userquery.birthday,
               rolequery.id AS roleID,
               rolequery.rolename
        FROM userquery
                 LEFT JOIN user_role ON userquery.id = user_role.user_id
                 INNER JOIN rolequery ON user_role.role_id = rolequery.id;
    </select>
</mapper>

5.3、执行结果

6、注意事项

MyBatis多表配置方式:

一对一配置:使用<resultMap>做配置

一对多配置:使用<resultMap>+<collection>做配置

多对多配置:使用<resultMap>+<collection>做配置

这里涉及到的操作都需要有一个配置好的日期类型转换器,不然Date无法正确转换。具体请看我这篇文章:MyBatis核心配置文件详解

转换器代码如下:

package com.xzl.handle;

import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

/**
 * @author 逐梦苍穹
 * @date 2023/8/24 23:30
 * setNonNullParameter为java程序设置数据到数据库的回调方法
 * getNullableResult为查询时 mysql的字符串类型转换成 java的Type类型的方法
 * i 是一个整数,表示要设置的参数在 SQL 语句中的位置。
 * s 表示数据库列名
 */
public class DateTypeHandle extends BaseTypeHandler<Date> {
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException {
        // 在预处理语句中设置非空参数
        // 将 Date 类型的数据转换为 long 类型的时间戳,并以字符串形式设置到 PreparedStatement 中
//        preparedStatement.setString(i, date.getTime() + "");
        preparedStatement.setLong(i,date.getTime());
    }

    @Override
    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException {
        // 从结果集中获取可空结果(根据列名)
        // 将结果集中的 long 类型的时间戳转换为 Date 类型并返回
        return new Date(resultSet.getLong(s));
    }

    @Override
    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException {
        // 从结果集中获取可空结果(根据列索引)
        // 将结果集中的 long 类型的时间戳转换为 Date 类型并返回
        return new Date(resultSet.getLong(i));
    }

    @Override
    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        // 从存储过程的调用结果中获取可空结果
        // 直接获取存储过程的 Date 类型数据并返回
        return callableStatement.getDate(i);
    }
}

🍁如果觉得文章写的不错,欢迎点赞收藏加关注!

🍁您的一键三连,就是我创作的最大动力!😊

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

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

相关文章

2048小游戏成品源码

2048小游戏&#xff0c;可以自选背景颜色&#xff0c;方框颜色&#xff0c;音乐播放。 还可以展示当前玩家的排名&#xff0c;动态排名&#xff0c;及历史玩家的排名。 前期需求&#xff1a; 使用pygame加载目录音乐。MP3文件&#xff1a; def music_play():import pygame …

基于Java+SpringBoot+Vue前后端分离工厂车间管理系统设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

Android实现跟随滑块移动显示的seekBar

概述 详细讲述跟随滑块移动显示的seekBar效果的自定义实现过程 详细 前言 在Android开发过程中&#xff0c;我们有时会使用到自定义Seekbar,如在滑动滑块时&#xff0c;文字随滑块移动之类的效果&#xff0c;今天就来讲讲跟随滑块移动显示的seekBar的实现吧。 今天涉及内容…

IO进程线程、开启进程frok函数,exec函数族

进程是一个独立的可调度的任务 进程是一个抽象实体。当系统在执行某个程序时&#xff0c;分配和释放的各种资源 进程是一个程序的一次执行的过程 主要的进程标识&#xff1a; 进程号(Process Identity Number&#xff0c;PID) 父进程号(Parent Process ID&#xff0c;PPID) …

DML语句的用法(MySQL)

文章目录 前言一、DML介绍二、DML语句操作1、给指定字段添加数据2、给全部字段添加数据3、批量添加数据4、修改数据5、删除数据 总结 前言 本文主要介绍SQL语句中DML语句的用法。 在实验开始之前我们先创建一下所要使用表&#xff0c;如下图所示&#xff1a; 一、DML介绍 DM…

战略在集体学习过程中涌现

战略学习派&#xff1a;战略是涌现的学习过程&#xff0c;中国人的话&#xff0c;要交学习费&#xff01;【安志强趣讲269期】 趣讲大白话&#xff1a;出来混总要交学费 **************************** 中国人有这个意识 新进一个领域&#xff0c;要交学费&#xff0c;有学习过程…

【Flutter】Flutter 使用 infinite_scroll_pagination 实现无限滚动分页

【Flutter】Flutter 使用 infinite_scroll_pagination 实现无限滚动分页 文章目录 一、前言二、安装和基本使用1. 添加依赖2. 基础配置和初始化 三、实际业务中的用法1. 与 API 集成2. 错误处理 四、完整示例1. 创建一个无限滚动列表2. 使用在你的应用中3. 完整代码示例 五、总…

【Qt学习】08:文件读写操作

OVERVIEW 文件读写操作一、文件操作1.QFile2.QFileInfo 二、二进制文件读写三、文本文件读写 文件读写操作 文件操作是应用程序必不可少的部分&#xff0c;Qt 作为一个通用开发库提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象&#xff0c;这些设备具有…

Web自动化测试之图文验证码的解决方案

对于web应用程序来讲&#xff0c;处于安全性考虑&#xff0c;在登录的时候&#xff0c;都会设置验证码&#xff0c; 验证码的类型种类繁多&#xff0c;有图片中辨别数字字母的&#xff0c;有点击图片中指定的文字的&#xff0c;也有算术计算结果的&#xff0c;再复杂一点就是滑…

电子封条监控系统 yolov5

电子封条监控系统利用yoloov5python 深度学习训练模型技术&#xff0c;电子封条监控系统实现对画面内外的出入人员、人数变化及非煤矿山生产作业状态等情况的实时监测和分析&#xff0c;及时发现异常动态&#xff0c;减少了人为介入的过程。介绍Yolo算法之前&#xff0c;首先先…

Android开发之性能测试工具Profiler

前言 性能优化问题&#xff0c;在我们开发时都会遇到&#xff0c;但是在小厂和对自己要求不严格的情况下&#xff0c;我都很少去做性能优化&#xff1b; 在性能优化上&#xff0c;基本大家都是通过自己的开发经验和性能分析工具来发现问题&#xff0c;今天给大家分享一下小编最…

性能优化之分库分表

1、什么是分库分表 1.1、分表 将同一个库中的一张表&#xff08;比如SPU表&#xff09;按某种方式&#xff08;垂直拆分、水平拆分&#xff09;拆分成SPU1、SPU2、SPU3、SPU4…等若干张表&#xff0c;如下图所示&#xff1a; 1.2、分库 在表数据不变的情况下&#xff0c;对…

【GeoDa实用技巧100例】025:geoda空间回归分析案例教程

严重声明:本文来自专栏《GeoDa空间计量案例教程100例》,为CSDN博客专家刘一哥GIS原创,原文及专栏地址为:https://blog.csdn.net/lucky51222/category_12373659.html,谢绝转载或爬取!!! 文章目录 一、空间自回归模型二、Geoda空间回归分析普通最小二乘法回归(OLS)空间…

设计模式--建造者模式(Builder Pattern)

一、什么是建造者模式 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;它关注如何按照一定的步骤和规则创建复杂对象。建造者模式的主要目的是将一个复杂对象的构建过程与其表示分离&#xff0c;从而使同样的构建过程可以创建不同的表示。…

基于配置类方式管理 Bean

目录 一、完全注解开发理解 二、配置类和扫描注解 三、Bean定义组件 四、Bean注解细节 五、import 扩展 一、完全注解开发理解 Spring 完全注解配置&#xff08;Fully Annotation-based Configuration&#xff09;是指通过 Java配置类 代码来配置 Spring 应用程序&#…

Folyd 多源最短路

目录 简介 实现 代码 关于Floyd的题目 简介 首先我们要知道a到b的最短路是什么 a到b的最短路是从a点到b点的最小距离&#xff08;花费&#xff09; 那多源最短路呢就是能求任意a和b&#xff0c;之间的最短路 那么Folyd是多源最短路&#xff0c;也就是求任意a和b&#x…

春秋云镜 CVE-2019-13275

春秋云镜 CVE-2019-13275 WordPress Plugin wp-statics SQLI 靶标介绍 WordPress VeronaLabs wp-statistics插件12.6.7之前版本中的v1/hit端点存在SQL注入漏洞。 启动场景 漏洞利用 exp time curl -X POST http://host/wp-json/wpstatistics/v1/hit --data "wp_stati…

SpringBoot权限认证

SpringBoot的安全 常用框架&#xff1a;Shrio,SpringSecurity 两个功能&#xff1a; Authentication 认证Authorization 授权 权限&#xff1a; 功能权限访问权限菜单权限 原来用拦截器、过滤器来做&#xff0c;代码较多。现在用框架。 SpringSecurity 只要引入就可以使…

mybatis:动态sql【2】+转义符+缓存

目录 一、动态sql 1.set、if 2.foreach 二、转义符 三、缓存cache 1. 一级缓存 2. 二级缓存 一、动态sql 1.set、if 在update语句中使用set标签&#xff0c;动态更新set后的sql语句&#xff0c;&#xff0c;if作为判断条件。 <update id"updateStuent" pa…

【C++】容器适配器stack、queue以及deque容器

&#x1f3d6;️作者&#xff1a;malloc不出对象 ⛺专栏&#xff1a;C的学习之路 &#x1f466;个人简介&#xff1a;一名双非本科院校大二在读的科班编程菜鸟&#xff0c;努力编程只为赶上各位大佬的步伐&#x1f648;&#x1f648; 目录 前言一、什么是容器适配器1.1 stack的…