Mini MyBatis-Plus(下)

news2024/11/27 21:04:52
作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO

联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
 

最核心的内容前两篇已经讲完了,这一篇只有代码:

先看demo目录下的三个文件:

DemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

}

User.java

package com.example.demo;

import com.example.demo.mybatisplus.annotations.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @author mx
 */
@Data
@TableName("t_user")
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private Date birthday;
}

UserMapper.java

package com.example.demo;

import com.example.demo.mybatisplus.AbstractBaseMapper;

/**
 * @author mx
 */
public class UserMapper extends AbstractBaseMapper<User> {
}

mybatisplus下AbstractBaseMapper.java

package com.example.demo.mybatisplus;

import com.example.demo.mybatisplus.annotations.TableName;
import com.example.demo.mybatisplus.core.JdbcTemplate;
import com.example.demo.mybatisplus.query.QueryWrapper;
import com.example.demo.mybatisplus.query.SqlParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Mapper基类
 *
 * @author mx
 */
public abstract class AbstractBaseMapper<T> {

    private static Logger logger = LoggerFactory.getLogger(AbstractBaseMapper.class);

    private JdbcTemplate<T> jdbcTemplate = new JdbcTemplate<T>();

    private Class<T> beanClass;

    private final String TABLE_NAME;

    private static final String DEFAULT_LOGICAL_TYPE = " and ";

    public AbstractBaseMapper() {
        // DO对象的Class
        beanClass = (Class<T>) ((ParameterizedType) this.getClass()
                .getGenericSuperclass())
                .getActualTypeArguments()[0];
        // DO对应的表名 TODO 非空判断及默认处理
        TABLE_NAME = beanClass.getAnnotation(TableName.class).value();
    }

    public T select(QueryWrapper<T> queryWrapper) {
        List<T> list = this.list(queryWrapper);
        if (!list.isEmpty()) {
            return list.get(0);
        }

        return null;
    }

    public List<T> list(QueryWrapper<T> queryWrapper) {
        StringBuilder sqlBuilder = new StringBuilder("SELECT * FROM ").append(TABLE_NAME).append(" WHERE ");

        List<Object> paramList = new ArrayList<>();
        Map<String, SqlParam> conditionMap = queryWrapper.build();
        conditionMap.forEach((operator, param) -> {
            sqlBuilder.append(param.getColumnName()).append(operator).append("?").append(DEFAULT_LOGICAL_TYPE);
            paramList.add(param.getValue());
        });

        // 删除最后一个 and
        String sql = sqlBuilder.replace(sqlBuilder.length() - DEFAULT_LOGICAL_TYPE.length(), sqlBuilder.length(), ";").toString();

        try {
            logger.info("sql: {}", sql);
            logger.info("params: {}", paramList);
            return jdbcTemplate.queryForList(sql, paramList, beanClass);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("query failed", e);
        }

        return Collections.emptyList();
    }

    public int insert(T bean) {
        // 得到DO对象的所有字段
        Field[] declaredFields = beanClass.getDeclaredFields();

        // 拼接sql语句,表名来自DO的TableName注解value
        StringBuilder sqlBuilder = new StringBuilder()
                .append("INSERT INTO ")
                .append(TABLE_NAME)
                .append(" VALUES(");
        for (int i = 0; i < declaredFields.length; i++) {
            sqlBuilder.append("?");
            if (i < declaredFields.length - 1) {
                sqlBuilder.append(",");
            }
        }
        sqlBuilder.append(")");

        // 收集sql参数
        ArrayList<Object> paramList = new ArrayList<>();
        try {
            for (Field declaredField : declaredFields) {
                declaredField.setAccessible(true);
                Object o = declaredField.get(bean);
                paramList.add(o);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        int affectedRows = 0;
        try {
            logger.info("sql: {}", sqlBuilder.toString());
            logger.info("params: {}", paramList);
            affectedRows = jdbcTemplate.update(sqlBuilder.toString(), paramList);
            logger.info("insert success, affectedRows: {}", affectedRows);
            return affectedRows;
        } catch (SQLException e) {
            e.printStackTrace();
            logger.error("insert failed", e);
        }

        return 0;
    }

    public int updateSelective(T bean, QueryWrapper<T> queryWrapper) {
        // 得到DO对象的所有字段
        Field[] declaredFields = beanClass.getDeclaredFields();

        // 拼接sql语句,表名来自DO的TableName注解value
        StringBuilder sqlSetBuilder = new StringBuilder()
                .append("UPDATE ")
                .append(TABLE_NAME)
                .append(" SET ");

        List<Object> paramList = new ArrayList<>();

        // 先拼接要SET的字段占位符 SET name=?, age=?
        try {
            for (int i = 0; i < declaredFields.length; i++) {
                Field declaredField = declaredFields[i];
                declaredField.setAccessible(true);
                Object fieldValue = declaredField.get(bean);
                if (fieldValue != null) {
                    sqlSetBuilder.append(declaredField.getName()).append(" = ").append("?").append(", ");
                    paramList.add(fieldValue);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        // 删除最后一个 ,
        sqlSetBuilder = sqlSetBuilder.delete(sqlSetBuilder.length() - 2, sqlSetBuilder.length());

        // 再拼接WHERE条件占位符
        StringBuilder sqlWhereBuilder = new StringBuilder(" WHERE ");
        Map<String, SqlParam> conditionMap = queryWrapper.build();
        for (Map.Entry<String, SqlParam> stringSqlParamEntry : conditionMap.entrySet()) {
            String operator = stringSqlParamEntry.getKey();
            SqlParam param = stringSqlParamEntry.getValue();
            sqlWhereBuilder.append(param.getColumnName()).append(operator).append("?").append(DEFAULT_LOGICAL_TYPE);
            paramList.add(param.getValue());
        }
        // 删除最后一个 and
        sqlWhereBuilder = sqlWhereBuilder.replace(sqlWhereBuilder.length() - DEFAULT_LOGICAL_TYPE.length(), sqlWhereBuilder.length(), ";");

        String sql = sqlSetBuilder.append(sqlWhereBuilder).toString();

        int affectedRows = 0;
        try {
            logger.info("sql: {}", sqlSetBuilder.toString());
            logger.info("params: {}", paramList);
            affectedRows = jdbcTemplate.update(sql, paramList);
            logger.info("update success, affectedRows: {}", affectedRows);
            return affectedRows;
        } catch (SQLException e) {
            e.printStackTrace();
            logger.error("update failed", e);
        }

        return 0;
    }

}

annotations下的TableName.java

package com.example.demo.mybatisplus.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author mx
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableName {

    String value();

}

core下的

JdbcTemplate.java

package com.example.demo.mybatisplus.core;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * JdbcTemplate,简化jdbc操作
 *
 * @author mx
 */
public class JdbcTemplate<T> {

    public List<T> queryForList(String sql, List<Object> params, RowMapper<T> rowMapper) throws SQLException {
        return query(sql, params, rowMapper);
    }

    public T queryForObject(String sql, List<Object> params, RowMapper<T> rowMapper) throws SQLException {
        List<T> result = query(sql, params, rowMapper);
        return result.isEmpty() ? null : result.get(0);
    }

    public List<T> queryForList(String sql, List<Object> params, Class<T> clazz) throws Exception {
        return query(sql, params, clazz);
    }

    public T queryForObject(String sql, List<Object> params, Class<T> clazz) throws Exception {
        List<T> result = query(sql, params, clazz);
        return result.isEmpty() ? null : result.get(0);
    }

    public int update(String sql, List<Object> params) throws SQLException {
        // 1.获取Connection
        Connection conn = getConnection();

        // 2.传入sql模板、sql参数,得到PreparedStatement
        PreparedStatement ps = getPreparedStatement(sql, params, conn);

        // 3.执行更新(增删改)
        int affectedRows = ps.executeUpdate();

        // 4.释放资源
        closeConnection(conn, ps, null);

        return affectedRows;
    }

    // ************************* private methods **************************

    private List<T> query(String sql, List<Object> params, RowMapper<T> rowMapper) throws SQLException {
        // 外部传入rowMapper(手写规则)
        return baseQuery(sql, params, rowMapper);
    }

    private List<T> query(String sql, List<Object> params, Class<T> clazz) throws Exception {
        // 自己创建rowMapper(反射)后传入
        BeanHandler<T> beanHandler = new BeanHandler<>(clazz);
        return baseQuery(sql, params, beanHandler);
    }

    /**
     * 基础查询方法,必须传入Bean的映射规则
     *
     * @param sql
     * @param params
     * @param rowMapper
     * @return
     * @throws SQLException
     */
    private List<T> baseQuery(String sql, List<Object> params, RowMapper<T> rowMapper) throws SQLException {
        // TODO 参数非空校验

        // 1.获取Connection
        Connection conn = getConnection();

        // 2.传入sql模板、sql参数,得到PreparedStatement
        PreparedStatement ps = getPreparedStatement(sql, params, conn);

        // 3.执行查询
        ResultSet rs = ps.executeQuery();

        // 4.处理结果
        List<T> result = new ArrayList<>();
        while (rs.next()) {
            T obj = rowMapper.mapRow(rs);
            result.add(obj);
        }

        // 5.释放资源
        closeConnection(conn, ps, rs);
        return result;
    }

    /**
     * 内部类,实现了RowMapper接口,底层使用反射
     *
     * @param <R>
     */
    private static class BeanHandler<R> implements RowMapper<R> {
        // clazz表示最终封装的bean类型
        private Class<R> clazz;

        public BeanHandler(Class<R> clazz) {
            this.clazz = clazz;
        }

        @Override
        public R mapRow(ResultSet rs) {
            try {
                if (rs.next()) {
                    // 1.获取表数据
                    ResultSetMetaData metaData = rs.getMetaData();

                    // 2.反射创建bean
                    R bean = clazz.newInstance();

                    // 3.利用反射,把表数据设置到bean中
                    for (int i = 0; i < metaData.getColumnCount(); i++) {
                        String name = metaData.getColumnName(i + 1);
                        Object value = rs.getObject(name);
                        Field field = clazz.getDeclaredField(name);
                        field.setAccessible(true);
                        field.set(bean, value);
                    }

                    // 4.返回bean
                    return bean;
                } else {
                    return null;
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    private PreparedStatement getPreparedStatement(String sql, List<Object> params, Connection conn) throws SQLException {
        // 1.传入sql模板,得到PreparedStatement
        PreparedStatement ps = conn.prepareStatement(sql);

        // 2.为sql模板设置参数
        for (int i = 0; i < params.size(); i++) {
            ps.setObject(i + 1, params.get(i));
        }

        return ps;
    }

    private Connection getConnection() throws SQLException {
        // TODO 可以抽取配置到properties文件
        String url = "jdbc:mysql://localhost:3306/demo";
        String user = "root";
        String password = "123456";
        return DriverManager.getConnection(url, user, password);
    }

    private void closeConnection(Connection conn, PreparedStatement preparedStatement, ResultSet rs) throws SQLException {
        if (rs != null) {
            rs.close();
        }

        if (preparedStatement != null) {
            preparedStatement.close();
        }

        if (conn != null) {
            conn.close();
        }
    }

}

 RowMapper.java

package com.example.demo.mybatisplus.core;

import java.sql.ResultSet;

/**
 * 结果集映射器
 *
 * @author mx
 */
@FunctionalInterface
public interface RowMapper<T> {
    /**
     * 将结果集转为指定的Bean
     *
     * @param resultSet
     * @return
     */
    T mapRow(ResultSet resultSet);
}

query下的

QueryWrapper.java

package com.example.demo.mybatisplus.query;

import com.example.demo.mybatisplus.utils.ConditionFunction;
import com.example.demo.mybatisplus.utils.Reflections;

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

/**
 * 模拟MyBatis-Plus的LambdaQueryWrapper(思路完全不同,仅仅是形似)
 *
 * @author mx
 */
public class QueryWrapper<T> {
    // conditionMap,收集查询条件
    // {
    //    " LIKE ": {
    //        "name": "bravo1988"
    //    },
    //    " = ": {
    //        "age": 18
    //    }
    // }
    private final Map<String, SqlParam> conditionMap = new HashMap<>();

    // 操作符类型,比如 name like 'bravo' 中的 LIKE
    private static final String OPERATOR_EQ = " = ";
    private static final String OPERATOR_GT = " > ";
    private static final String OPERATOR_LT = " < ";
    private static final String OPERATOR_LIKE = " LIKE ";

    public QueryWrapper<T> eq(ConditionFunction<T, ?> fn, Object value) {
        String columnName = Reflections.fnToColumnName(fn);
        conditionMap.put(OPERATOR_EQ, new SqlParam(columnName, value));
        return this;
    }

    public QueryWrapper<T> gt(ConditionFunction<T, ?> fn, Object value) {
        String columnName = Reflections.fnToColumnName(fn);
        conditionMap.put(OPERATOR_GT, new SqlParam(columnName, value));
        return this;
    }

    public QueryWrapper<T> lt(ConditionFunction<T, ?> fn, Object value) {
        String columnName = Reflections.fnToColumnName(fn);
        conditionMap.put(OPERATOR_LT, new SqlParam(columnName, value));
        return this;
    }

    public QueryWrapper<T> like(ConditionFunction<T, ?> fn, Object value) {
        String columnName = Reflections.fnToColumnName(fn);
        conditionMap.put(OPERATOR_LIKE, new SqlParam(columnName, "%" + value + "%"));
        return this;
    }

    public Map<String, SqlParam> build() {
        return conditionMap;
    }
}

 SqlParam.java

package com.example.demo.mybatisplus.query;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author mx
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SqlParam {
    private String columnName;
    private Object value;
}

utils下的

 ConditionFunction.java

package com.example.demo.mybatisplus.utils;

import java.io.Serializable;
import java.util.function.Function;

/**
 * 扩展java.util.function包下的Function接口:支持Serializable
 * 搭配Reflections工具类一起使用,用于获取Lambda表达式的方法名
 *
 * @author mx
 */
@FunctionalInterface
public interface ConditionFunction<T, R> extends Function<T, R>, Serializable {
}

Reflections.java

package com.example.demo.mybatisplus.utils;

import java.beans.Introspector;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.regex.Pattern;

/**
 * 获取Lambda入参的方法名
 *
 * @author mx
 */
public class Reflections {
    private static final Pattern GET_PATTERN = Pattern.compile("^get[A-Z].*");
    private static final Pattern IS_PATTERN = Pattern.compile("^is[A-Z].*");

    /**
     * 注意: 非标准变量(非小驼峰)调用这个方法可能会有问题
     *
     * @param fn
     * @param <T>
     * @return
     */
    public static <T> String fnToColumnName(ConditionFunction<T, ?> fn) {
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(Boolean.TRUE);
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
            String getter = serializedLambda.getImplMethodName();
            // 对于非标准变量生成的Get方法这里可以直接抛出异常,或者打印异常日志
            if (GET_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(3);
            } else if (IS_PATTERN.matcher(getter).matches()) {
                getter = getter.substring(2);
            }
            return Introspector.decapitalize(getter);
        } catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }
}

其实第一篇的内容是最难的,不只是从0到1,而是从0到90,后面两篇其实只是90到100,在这基础稍微扩展了一下而已。

AbstractBaseMapper代码还有冗余,有兴趣的同学可以自行完善。但还是那句话,如果你的目的是为了锻炼封装能力,可以精益求精,但我们的AbstractBaseMapper注定不能用于生产,即使要优化,点到为止即可。

学习必须往深处挖,挖的越深,基础越扎实!

阶段1、深入多线程

阶段2、深入多线程设计模式

阶段3、深入juc源码解析

阶段4、深入jdk其余源码解析

阶段5、深入jvm源码解析

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

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

相关文章

通过学习这些技巧,让你的Python代码更加简洁和高效

文章目录 前言列表性能陷阱陷阱一陷阱二 快速合并字典通过有序字典去重最后Python技术资源分享1、Python所有方向的学习路线2、学习软件3、入门学习视频4、实战案例5、清华编程大佬出品《漫画看学Python》6、Python副业兼职与全职路线 前言 今天看到一些关于容器的使用技巧&am…

隧道代理HTTP工作原理:一场奇妙的网络魔法表演

嘿&#xff0c;小伙伴们&#xff01;今天我们要一起探索一个有趣的话题——隧道代理HTTP的工作原理。这不是普通的表演&#xff0c;而是一场奇妙的网络魔法表演&#xff01; 首先&#xff0c;让我们想象一下&#xff0c;网络世界就像一个大舞台&#xff0c;而我们每个人都是这…

邮政快递查询,邮政快递单号查询,按物流更新量来筛选单号

如何快速、准确地查询多个快递单号的物流信息&#xff1f;如何提高工作效率&#xff0c;减少一个个等待的焦虑&#xff1f;别担心&#xff0c;【快递批量查询高手】为你排忧解难&#xff0c;不仅可以帮你省下大量的时间&#xff0c;还能提高工作效率&#xff0c;让你更好地享受…

喜讯丨智安网络实力上榜《嘶吼2023中国网络安全产业势能榜》

近日&#xff0c;嘶吼安全产业研究院正式发布《嘶吼2023中国网络安全产业势能榜》。智安网络凭借在网络安全行业领先的产品实力、专业的安全服务水平及多年累积的行业经验&#xff0c;从300余家厂商中脱颖而出&#xff0c;成为《中国网络安全产业势能榜》互联网行业势能厂商。 …

计算机网络复习4

网络层——点到点 文章目录 网络层——点到点功能路由算法IPV4NAT 网络地址转换子网划分与子网掩码、CIDR地址解析协议ARP&#xff1a;根据IP地址找到MAC地址动态主机配置协议DHCP网际控制报文协议ICMPIPV6内部网关协议&#xff08;IGP&#xff09;外部网关协议(EGP) 功能 异构…

【银行测试】核心系统/信贷系统+各个测试点总结(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、银行核心系统和…

数据结构-八大排序详解(动图+实现详解+总结)

1 前言 本章主要讲解&#xff1a; 八大排序的基本知识及其实现 注&#xff1a;这里的八大排序指直接插入&#xff0c;希尔&#xff0c;选择&#xff0c;堆排&#xff0c;冒泡&#xff0c;快排&#xff0c;归并&#xff0c;基数 八大排序汇总图&#xff1a; 2 排序概念及应用 …

MindOpt 云上建模求解平台:多求解器协同优化

前言 数学规划是一种数学优化方法&#xff0c;主要是寻找变量的取值在特定的约束情况下&#xff0c;使我们的决策目标得到一个最大或者最小值的决策。 使用数学规划的方法我们需要确定问题的目标、约束、变量的取值范围&#xff0c;然后进行数学建模&#xff0c;将数学公式转化…

前端使用高德api的AMap.Autocomplete无效,使用AMap.Autocomplete报错

今天需要一个坐标拾取器&#xff0c;需要一个输入框输入模糊地址能筛选的功能 查看官方文档&#xff0c;有一个api可以直接满足我们的需求 AMap.Autocomplete 上代码 AMapLoader.load({"key": "你的key", // 申请好的Web端开发者Key&#xff0c;首次调…

[AI编程]AI辅助编程助手-亚马逊AI 编程助手 Amazon CodeWhisperer

亚马逊AI 编程助手 Amazon CodeWhisperer 是一种基于人工智能技术的编程辅助工具&#xff0c;旨在帮助开发人员更高效地编写代码。它可以提供实时的代码建议、自动补全和错误检查&#xff0c;帮助优化代码质量和提高编程效率。 Amazon CodeWhisperer 使用了自然语言处理和机器…

Lunix的奇妙冒险————权限篇

文章目录 一.什么是权限二.用户权限和类别。1.用户2.角色3.更换文件角色 三.文件的类别和对应权限1.文件的类别。2.文件属性权限1.权限说明。2.默认生成文件权限来源3.更改权限 3.文件的执行与删除 四.不同用户共同在一个目录下的权限。1.普通用户家目录2.在同一目录下文件的权…

述职报告一般怎么写?

在日常生活中&#xff0c;我们经常需要撰写各种报告。对于报告的撰写&#xff0c;我们需要清晰地解释涉及的专业术语。现在&#xff0c;我为大家整理了一些精选的晋升述职报告范文&#xff0c;供大家参考和借鉴。希望这些范文能对大家有所帮助。 晋升述职报告范文精选1 一、个…

力扣题目学习笔记(OC + Swift)19. 删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 此题目为链表题&#xff0c;拿出我们的杀手锏&#xff0c;链表解题经典三把斧&#xff1a; 哑巴节点栈快慢指针 关于内存问题&#xff1a;由于Swift及…

Fiddler 抓包工具的安装与使用

今天分享Fiddler 抓包工具的安装与使用&#xff0c;基于HTTP应用层协议的抓包工具。 一、下载安装 1、下载地址&#xff1a; The Ultimate Web Debugging Tool - Download Fiddler Everywhere | Telerik 选择相应类型&#xff1a; 2、下载完成 3、安装 傻瓜式安装&#xf…

【开源学习】ThingsBoard -- 基本配置与使用

【开源学习】ThingsBoard -- 基本配置与使用 租户及客户管理租户及租户账号管理租户管理租户创建租户修改租户删除 租户账号管理租户账号创建租户账号修改租户账号删除 客户及客户账号管理客户管理客户创建客户修改客户删除 客户用户管理客户用户创建客户用户修改客户用户删除 …

蔓灵花组织wmRAT攻击武器对比分析

概述 蔓灵花&#xff0c;又名"Bitter"、"APT-C-08"、"T-APT-17"以及"苦象"&#xff0c;常对南亚周边及孟加拉湾海域的相关国家发起网络攻击&#xff0c;主要针对巴基斯坦和中国两国。其攻击目标主要包括政府部门、核工业、能源、国防…

【数据分享】2023年我国省市县三级的生活服务设施数量(23类设施/Excel/Shp格式)

人才市场、售票处、旅行社等生活服务设施的配置情况是一个城市公共基础设施完善程度的重要体现&#xff0c;一个城市生活服务设施种类越丰富&#xff0c;数量越多&#xff0c;通常能表示这个城市的公共服务水平越高&#xff01; 本次我们为大家带来的是我国各省份、各地级市、…

Hive05_DML 操作

1 DML 数据操作 1.1 数据导入 1.1.1 向表中装载数据&#xff08;Load&#xff09; 1&#xff09;语法 hive> load data [local] inpath 数据的 path [overwrite] into table student [partition (partcol1val1,…)];&#xff08;1&#xff09;load data:表示加载数据 &…

Matplotlib、Pandas可视化工具

一、Matplotlib 1.简介&#xff1a; 数据可视化可以看到变量的分布和变量之间的关系&#xff0c;还可以检查建模过程中的假设。Python 提供了若干种用于绘图的扩展包&#xff0c;包括:Matplotlib、 Pandas、 ggplot 和 Seaborn等。Matplotlib 是最基础的扩展包&#xff0c;它…

CUDA驱动深度学习发展 - 技术全解与实战

全面介绍CUDA与pytorch cuda实战 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员&#xff0c;阿里云认证的资深架构师&#xff0c;项目管理专业人士&…