手撸Mybatis(五)——连接数据库进行insert,update和delete

news2024/11/27 18:33:46

本专栏的源码:https://gitee.com/dhi-chen-xiaoyang/yang-mybatis。

引言

在上一章中,我们成功实现了数据库的连接,以及单个字段的查询、resultType映射查询、resultMap映射查询。在本章,我们将讲解关于增加、修改和删除操作。

insert操作

首先,我们修改IUserMapper类,添加insertUser接口

package com.yang.mybatis.test;

public interface IUserMapper {
    String queryUserName(Integer id);

    Integer queryUserAge(Integer id);

    User queryUserById(Integer id);

    IdUserNameVO queryIdUserNameVOById(Integer id);

    void insertUser(User user);
}

修改UserMapper.xml,加上insertUser相关的xml块

 <insert id="insertUser" parameterType="com.yang.mybatis.test.User">
        insert into user( user_name, password, age, create_time)
        values( #{userName}, #{password}, #{age}, #{createTime})
    </insert>

我们注意到,对于每一个接口方法,其对应的xml块,类型有select,insert,update和delete这几种类型,此外,还有一个parameterType参数,因此,我们需要再次修改MybatisSqlStatement类,加上operateType和parameterType参数

public class MybatisSqlStatement implements Serializable {
    private String namespace;

    private String id;

    private String sql;

    private String resultType;

    private String resultMap;

    private String operateType;

    private String parameterType;
  
    ...省略getter 和setter
}

接着修改XmlMybatisMapperParser的parseStatement方法,在解析mapper.xml的时候,设置对应的值

 private void parseStatement(MybatisMapperXmlConfiguration mybatisMapperXmlConfiguration, List<Element> elements) {
        if (elements == null || elements.isEmpty()) {
            return;
        }
        String namespace = mybatisMapperXmlConfiguration.getMapperName();
        for (Element element : elements) {
            String id = element.attributeValue("id");
            String resultType = element.attributeValue("resultType");
            String resultMap = element.attributeValue("resultMap");
            String parameterType = element.attributeValue("parameterType");
            String sql = element.getText().trim();

            MybatisSqlStatement mybatisSqlStatement = new MybatisSqlStatement();
            mybatisSqlStatement.setNamespace(namespace);
            mybatisSqlStatement.setId(id);
            mybatisSqlStatement.setSql(sql);
            mybatisSqlStatement.setResultType(resultType);
            mybatisSqlStatement.setResultMap(resultMap);
            mybatisSqlStatement.setParameterType(parameterType);
            mybatisSqlStatement.setOperateType(element.getName().toLowerCase());

            mybatisMapperXmlConfiguration.addMybatisSqlStatement(mybatisSqlStatement);
        }
    }

定义IMybatisPreparedStatementBuilder接口,用于接收请求参数并设置参数值到preparedStatement

package com.yang.mybatis.execute;



import com.yang.mybatis.execute.request.MybatisPreparedStatementBuilderRequest;

import java.sql.PreparedStatement;
import java.sql.SQLException;

public interface IMybatisPreparedStatementBuilder {
    PreparedStatement buildPreparedStatement(MybatisPreparedStatementBuilderRequest mybatisPreparedStatementBuilderRequest) throws SQLException;
}

其中,MybatisPreparedStatementBuilderRequest的定义如下:

package com.yang.mybatis.execute.request;

import com.yang.mybatis.config.MybatisSqlStatement;

import java.io.Serializable;
import java.sql.Connection;

public class MybatisPreparedStatementBuilderRequest implements Serializable {
    private Connection connection;
    private Object[] parameters;
    private MybatisSqlStatement mybatisSqlStatement;
    private String operateType;

    public Connection getConnection() {
        return connection;
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    public Object[] getParameters() {
        return parameters;
    }

    public void setParameters(Object[] parameters) {
        this.parameters = parameters;
    }

    public MybatisSqlStatement getMybatisSqlStatement() {
        return mybatisSqlStatement;
    }

    public void setMybatisSqlStatement(MybatisSqlStatement mybatisSqlStatement) {
        this.mybatisSqlStatement = mybatisSqlStatement;
    }

    public String getOperateType() {
        return operateType;
    }

    public void setOperateType(String operateType) {
        this.operateType = operateType;
    }
}

该接口的默认实现类为:

package com.yang.mybatis.execute;

import com.yang.mybatis.config.MybatisSqlStatement;
import com.yang.mybatis.execute.request.MybatisPreparedStatementBuilderRequest;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultMybatisPreparedStatementBuilder implements IMybatisPreparedStatementBuilder {
    @Override
    public PreparedStatement buildPreparedStatement(MybatisPreparedStatementBuilderRequest mybatisPreparedStatementBuilderRequest) throws SQLException {
        Connection connection = mybatisPreparedStatementBuilderRequest.getConnection();
        Object[] parameters = mybatisPreparedStatementBuilderRequest.getParameters();

        MybatisSqlStatement mybatisSqlStatement = mybatisPreparedStatementBuilderRequest.getMybatisSqlStatement();
        String rawSql = mybatisSqlStatement.getSql();

        List<String> parameterNameList = new ArrayList<>();
        String sql = extractRawSql(rawSql, parameterNameList);
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        String parameterType = mybatisSqlStatement.getParameterType();
        if (StringUtils.isEmpty(parameterType)) {
            if (parameterNameList.size() != parameters.length) {
                throw new RuntimeException("SQL语句参数个数不匹配====");
            }
            int index = 1;
            for (Object o : parameters) {
                preparedStatement.setObject(index ++, o);
            }
            return preparedStatement;
        }

        try {
            Object parameter = parameters[0];
            Class<?> aClass = Class.forName(parameterType);
            Field[] fields = aClass.getDeclaredFields();
            Map<String, Field> filedName2FieldMap = new HashMap<>();
            for (Field field : fields) {
                filedName2FieldMap.put(field.getName(), field);
            }

            List<Object> parameterValueList = new ArrayList<>();
            for (String parameterName : parameterNameList) {
                Field field = filedName2FieldMap.get(parameterName);
                if (field == null) {
                    throw new RuntimeException("SQL参数不存在");
                }
                field.setAccessible(true);
                Object value = field.get(parameter);
                parameterValueList.add(value);
            }

            int index = 1;
            for (Object o : parameterValueList) {
                preparedStatement.setObject(index++, o);
            }
            return preparedStatement;
        } catch (ClassNotFoundException | IllegalAccessException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private String extractRawSql(String rawSql, List<String> parameterNameList) {
        StringBuilder sqlBuilder = new StringBuilder();
        int start = 0;
        int end = -1;
        while ((end = rawSql.indexOf("#", start)) != -1) {
            sqlBuilder.append(rawSql.substring(start, end - 1))
                    .append(" ? ");
            int parameterStart = end + 2;
            int parameterEnd = rawSql.indexOf("}", parameterStart);
            parameterNameList.add(rawSql.substring(parameterStart, parameterEnd));
            start = parameterEnd + 1;
        }
        sqlBuilder.append(rawSql.substring(start));

        return sqlBuilder.toString();
    }
}

然后,我们修改DefaultMybatisSqlSession类,在execute方法中我们先使用IMybatisPreparedStatementBuilder来构建PreparedStatement,然后执行相关操作,最后再通过IMybatisResultParser来对结果进行解析。

package com.yang.mybatis.session;

import com.yang.mybatis.config.MybatisConfiguration;
import com.yang.mybatis.config.MybatisEnvironment;
import com.yang.mybatis.config.MybatisMapperXmlConfiguration;
import com.yang.mybatis.config.MybatisSqlStatement;
import com.yang.mybatis.execute.DefaultMybatisPreparedStatementBuilder;
import com.yang.mybatis.execute.DefaultMybatisResultParser;
import com.yang.mybatis.execute.IMybatisPreparedStatementBuilder;
import com.yang.mybatis.execute.IMybatisResultParser;
import com.yang.mybatis.execute.request.MybatisPreparedStatementBuilderRequest;
import com.yang.mybatis.execute.request.MybatisResultParserRequest;
import com.yang.mybatis.proxy.MapperProxyFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;


public class DefaultMybatisSqlSession implements IMybatisSqlSession {
    private MapperProxyFactory mapperProxyFactory;
    private MybatisConfiguration mybatisConfiguration;

    private IMybatisResultParser iMybatisResultParser;

    private IMybatisPreparedStatementBuilder iMybatisPreparedStatementBuilder;

    public DefaultMybatisSqlSession(MapperProxyFactory mapperProxyFactory, IMybatisPreparedStatementBuilder iMybatisPreparedStatementBuilder,
                                    IMybatisResultParser iMybatisResultParser) {
        this.mapperProxyFactory = mapperProxyFactory;
        this.mybatisConfiguration = mapperProxyFactory.getMybatisConfiguration();
        this.iMybatisPreparedStatementBuilder = iMybatisPreparedStatementBuilder;
        this.iMybatisResultParser = iMybatisResultParser;
    }

    @Override
    public <T> T execute(String method, Object parameter) {
        Map<String, MybatisSqlStatement> mapperMethod2SqlStatementsMap = mapperProxyFactory.getMybatisConfiguration().getMapperMethod2SqlStatementsMap();
        MybatisSqlStatement mybatisSqlStatement = mapperMethod2SqlStatementsMap.get(method);

        MybatisEnvironment defaultMybatisEnvironment = this.mybatisConfiguration.getDefaultMybatisEnvironment();

        return new TransactionInvoke<T>() {
            @Override
            public T execute(Connection connection) throws SQLException {
                Object[] parameters = (Object[]) parameter;
                String operateType = mybatisSqlStatement.getOperateType();

                MybatisPreparedStatementBuilderRequest mybatisPreparedStatementBuilderRequest = new MybatisPreparedStatementBuilderRequest();
                mybatisPreparedStatementBuilderRequest.setConnection(connection);
                mybatisPreparedStatementBuilderRequest.setMybatisSqlStatement(mybatisSqlStatement);
                mybatisPreparedStatementBuilderRequest.setParameters(parameters);
                mybatisPreparedStatementBuilderRequest.setOperateType(operateType);
                PreparedStatement preparedStatement = iMybatisPreparedStatementBuilder.buildPreparedStatement(mybatisPreparedStatementBuilderRequest);

                ResultSet resultSet = null;
                if ("select".equals(operateType)) {
                    resultSet = preparedStatement.executeQuery();
                } else {
                    preparedStatement.execute();
                }

                String mapperName = mybatisSqlStatement.getNamespace();
                MybatisMapperXmlConfiguration mybatisMapperXmlConfiguration = mybatisConfiguration.getMybatisMapperXmlConfiguration(mapperName);

                MybatisResultParserRequest mybatisResultParserRequest = new MybatisResultParserRequest();
                mybatisResultParserRequest.setResultSet(resultSet);
                mybatisResultParserRequest.setMybatisSqlStatement(mybatisSqlStatement);
                mybatisResultParserRequest.setMybatisMapperXmlConfiguration(mybatisMapperXmlConfiguration);
                mybatisResultParserRequest.setOperateType(operateType);
                T result = iMybatisResultParser.parseResult(mybatisResultParserRequest);
                if (resultSet != null) {
                    resultSet.close();
                }
                return result;
            }
        }.invoke(defaultMybatisEnvironment.getMybatisDataSource());
    }

    @Override
    public <T> T getMapper(Class<T> type) {
        return (T) mapperProxyFactory.newInstance(type, this);
    }
}

这里还需要修改DefaultMybatisSqlSessionFactory类,将IMybatisResultParser和IMybatisPreparedStatementBuilder的构建职责迁移于此,从而避免每一个SqlSession都需要重复创建这些类。

package com.yang.mybatis.session;

import com.yang.mybatis.execute.DefaultMybatisPreparedStatementBuilder;
import com.yang.mybatis.execute.DefaultMybatisResultParser;
import com.yang.mybatis.execute.IMybatisPreparedStatementBuilder;
import com.yang.mybatis.execute.IMybatisResultParser;
import com.yang.mybatis.proxy.MapperProxyFactory;

public class DefaultMybatisSqlSessionFactory implements IMybatisSqlSessionFactory {
    private MapperProxyFactory mapperProxyFactory;
    private IMybatisPreparedStatementBuilder iMybatisPreparedStatementBuilder = new DefaultMybatisPreparedStatementBuilder();
    private IMybatisResultParser iMybatisResultParser = new DefaultMybatisResultParser();

    public DefaultMybatisSqlSessionFactory(MapperProxyFactory mapperProxyFactory) {
        this.mapperProxyFactory = mapperProxyFactory;
    }

    @Override
    public IMybatisSqlSession openSession() {
        return new DefaultMybatisSqlSession(mapperProxyFactory, iMybatisPreparedStatementBuilder, iMybatisResultParser);
    }
}

添加测试代码,进行测试:

package com.yang.mybatis.test;

import com.yang.mybatis.config.parser.XmlMybatisConfigurationParser;
import com.yang.mybatis.config.parser.XmlMybatisMapperParser;
import com.yang.mybatis.session.IMybatisSqlSession;
import com.yang.mybatis.session.IMybatisSqlSessionFactory;
import com.yang.mybatis.session.MybatisSqlSessionFactoryBuilder;

import java.time.LocalDateTime;


public class Main {
    public static void main(String[] args) {
        String configPath = "mybatis-config.xml";
        IMybatisSqlSessionFactory mybatisSqlSessionFactory = new MybatisSqlSessionFactoryBuilder()
                .setMybatisMapperParser(new XmlMybatisMapperParser())
                .setMybatisConfigurationParser(new XmlMybatisConfigurationParser())
                .setConfigPath(configPath)
                .buildSqlSessionFactory();
        IMybatisSqlSession mybatisSqlSession = mybatisSqlSessionFactory.openSession();
        IUserMapper userMapper = mybatisSqlSession.getMapper(IUserMapper.class);

        User user = new User();
        user.setUserName("test");
        user.setPassword("test");
        user.setAge(4);
        user.setCreateTime(LocalDateTime.now());
        userMapper.insertUser(user);
    }

}

运行上述方法,再次查看数据库,结果如下:
image.png

update操作

首先,我们在IUserMapper接口上,添加一个updateUserById方法

    void updateUserById(User user);

然后修改UserMapper.xml,添加上updateUserById相关的xml块

 <update id="updateUserById" parameterType="com.yang.mybatis.test.User">
        update user
        set user_name = #{userName},
            password = #{password},
            age = #{age}
        where id = #{id}
    </update>

添加测试方法,进行测试

   String configPath = "mybatis-config.xml";
        MybatisSqlSessionFactory mybatisSqlSessionFactory = new MybatisSqlSessionFactoryBuilder()
                .setMybatisMapperParser(new XmlMybatisMapperParser())
                .setMybatisConfigurationParser(new XmlMybatisConfigurationParser())
                .setConfigPath(configPath)
                .buildSqlSessionFactory();
        IMybatisSqlSession mybatisSqlSession = mybatisSqlSessionFactory.openSession();
        IUserMapper userMapper = mybatisSqlSession.getMapper(IUserMapper.class);
        User user = userMapper.queryUserById(4);
        user.setUserName("cxy1");
        user.setPassword("1234");
        user.setAge(10);
        userMapper.updateUserById(user);

运行方法后,查看数据库,结果如下:
image.png

delete操作

首先,修改IUserMapper,添加deleteUserById方法

    void deleteUserById(Integer id);

然后在UserMapper.xml中添加上对应的xml块

<delete id="deleteUserById" parameterType="int">
        delete from user
        where id = #{id}
    </delete>

添加测试方法,进行测试:

 public static void main(String[] args) {
        String configPath = "mybatis-config.xml";
        IMybatisSqlSessionFactory mybatisSqlSessionFactory = new MybatisSqlSessionFactoryBuilder()
                .setMybatisMapperParser(new XmlMybatisMapperParser())
                .setMybatisConfigurationParser(new XmlMybatisConfigurationParser())
                .setConfigPath(configPath)
                .buildSqlSessionFactory();
        IMybatisSqlSession mybatisSqlSession = mybatisSqlSessionFactory.openSession();
        IUserMapper userMapper = mybatisSqlSession.getMapper(IUserMapper.class);
        userMapper.deleteUserById(5);
    }

结果如下:
image.png
可以看出,这里因为我们使用的是parameterType是int而不是java.lang.Integer,所以会报错,但是一般情况下,像int,float,long等小写,一般我们也会使用的,而且用的频率比java.lang.Integer的频率更大,那么,我们其实可以添加一个假名,将int这些小写的方式和对应的包装类关联起来。我们修改DefaultMybatisPreparedStatementBuilder,修改内容如下:

package com.yang.mybatis.execute;

import com.yang.mybatis.config.MybatisSqlStatement;
import com.yang.mybatis.execute.request.MybatisPreparedStatementBuilderRequest;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DefaultMybatisPreparedStatementBuilder implements IMybatisPreparedStatementBuilder {
    private Map<String, String> baseAliasMap = new HashMap<>();

    {
        baseAliasMap.put("int", Integer.class.getName());
        baseAliasMap.put("float", Float.class.getName());
        baseAliasMap.put("double", Double.class.getName());
        baseAliasMap.put("long", Long.class.getName());
        baseAliasMap.put("byte", Byte.class.getName());
        baseAliasMap.put("short", Short.class.getName());
        baseAliasMap.put("string", String.class.getName());
        baseAliasMap.put("String", String.class.getName());
        baseAliasMap.put("char", Character.class.getName());
    }
    @Override
    public PreparedStatement buildPreparedStatement(MybatisPreparedStatementBuilderRequest mybatisPreparedStatementBuilderRequest) throws SQLException {
        Connection connection = mybatisPreparedStatementBuilderRequest.getConnection();
        Object[] parameters = mybatisPreparedStatementBuilderRequest.getParameters();

        MybatisSqlStatement mybatisSqlStatement = mybatisPreparedStatementBuilderRequest.getMybatisSqlStatement();
        String rawSql = mybatisSqlStatement.getSql();

        List<String> parameterNameList = new ArrayList<>();
        String sql = extractRawSql(rawSql, parameterNameList);
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        String parameterType = mybatisSqlStatement.getParameterType();
        if (StringUtils.isEmpty(parameterType)) {
            if (parameterNameList.size() != parameters.length) {
                throw new RuntimeException("SQL语句参数个数不匹配====");
            }
            int index = 1;
            for (Object o : parameters) {
                preparedStatement.setObject(index ++, o);
            }
            return preparedStatement;
        }

        try {
            Object parameter = parameters[0];
            if (baseAliasMap.containsKey(parameterType)) {
                if (parameters.length != 1) {
                    throw new RuntimeException("SQL语句有误, 只能有一个parameterType参数");
                }
                preparedStatement.setObject(1, parameter);
                return preparedStatement;
            }
            Class<?> aClass = Class.forName(parameterType);
            Field[] fields = aClass.getDeclaredFields();
            Map<String, Field> filedName2FieldMap = new HashMap<>();
            for (Field field : fields) {
                filedName2FieldMap.put(field.getName(), field);
            }

            List<Object> parameterValueList = new ArrayList<>();
            for (String parameterName : parameterNameList) {
                Field field = filedName2FieldMap.get(parameterName);
                if (field == null) {
                    throw new RuntimeException("SQL参数不存在");
                }
                field.setAccessible(true);
                Object value = field.get(parameter);
                parameterValueList.add(value);
            }

            int index = 1;
            for (Object o : parameterValueList) {
                preparedStatement.setObject(index++, o);
            }
            return preparedStatement;
        } catch (ClassNotFoundException | IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private String extractRawSql(String rawSql, List<String> parameterNameList) {
        StringBuilder sqlBuilder = new StringBuilder();
        int start = 0;
        int end = -1;
        while ((end = rawSql.indexOf("#", start)) != -1) {
            sqlBuilder.append(rawSql.substring(start, end - 1))
                    .append(" ? ");
            int parameterStart = end + 2;
            int parameterEnd = rawSql.indexOf("}", parameterStart);
            parameterNameList.add(rawSql.substring(parameterStart, parameterEnd));
            start = parameterEnd + 1;
        }
        sqlBuilder.append(rawSql.substring(start));

        return sqlBuilder.toString();
    }
}

再次运行测试方法,这次没有报错了,然后我们查看数据库,结果如下,说明删除成功了。
image.png

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

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

相关文章

【MATLAB源码-第204期】基于matlab的语音降噪算法对比仿真,谱减法、维纳滤波法、自适应滤波法;参数可调。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 语音降噪技术的目的是改善语音信号的质量&#xff0c;通过减少或消除背景噪声&#xff0c;使得语音更清晰&#xff0c;便于听者理解或进一步的语音处理任务&#xff0c;如语音识别和语音通讯。在许多实际应用中&#xff0c;如…

MySQL45讲(一)(40)

回顾binlog_formatstatement STATEMENT 记录SQL语句。日志文件小&#xff0c;节约IO&#xff0c;但是对一些系统函数不能准确复制或不能复制&#xff0c;如now()、uuid()等 在RR隔离级别下&#xff0c;binlog_formatstatement 如果执行insert select from 这条语句是对于一张…

动态规划算法:简单多状态问题

例题一 解法&#xff08;动态规划&#xff09;&#xff1a; 算法思路&#xff1a; 1. 状态表⽰&#xff1a; 对于简单的线性 dp &#xff0c;我们可以⽤「经验 题⽬要求」来定义状态表⽰&#xff1a; i. 以某个位置为结尾&#xff0c;巴拉巴拉&#xff1b; ii. 以某个位置为起…

通过高效的升级计划控制云成本

快速迁移到云以及使用和成本的复杂性使得公司迫切希望减少浪费并控制其支出。更糟糕的是&#xff0c;动荡的经济让决策者紧张不安&#xff0c;他们考虑削减成本措施并优先考虑锁定收入。 如果没有正式的 FinOps 或成本优化策略&#xff0c;公司很容易看到云费用如滚雪球般失控…

一键解密,网络安全神器现已问世!

一、简介 当前版本V1.1这款工具是一款功能强大的网络安全综合工具&#xff0c;旨在为安全从业者、红蓝对抗人员和网络安全爱好者提供全面的网络安全解决方案。它集成了多种实用功能&#xff0c;包括解密、分析、扫描、溯源等&#xff0c;为用户提供了便捷的操作界面和丰富的功…

UDP多播

1 、多播的概念 多播&#xff0c;也被称为组播&#xff0c;是一种网络通信模式&#xff0c;其中数据的传输和接收仅在同一组内进行。多播具有以下特点&#xff1a; 多播地址标识一组接口&#xff1a;多播使用特定的多播地址&#xff0c;该地址标识一组接收数据的接口。发送到多…

现场面试题

这里写目录标题 1.sql1.1 只保留学生的最新成绩1.2 统计通话号码数1.3 更新地址 2.基础题2.1 请求序列第N位的值: 0, 1, 1, 2, ,3, 5, 8, 13, 21, 34.....第N位的值2.2 请写一段java代码&#xff0c;输出存在重复字母的单词 1.sql 1.1 只保留学生的最新成绩 表student中记录学…

每日一题(PTAL2):列车调度--贪心+二分

选择去维护一个最小区间 代码1&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int n;cin>>n;int num;vector <int> v;int res0;for(int i0;i<n;i){cin>>num;int locv.size();int left0;int rightv.size()-1;while(left<…

C++变量的作用域与存储类型

一 变量的作用域和存储类型 1 变量的作用域(Scope) 指在源程序中定义变量的位置及其能被读写访问的范围分为局部变量(Local Variable)和全局变量(Global Variable) 1&#xff09;局部变量(Local Variable) 在语句块内定义的变量 形参也是局部变量 特点&#xff1a; 生存期是…

AIGC-3D数字人技术:高效助推各行业数字化水平升级

从“互联网”到“人工智能”&#xff0c;数字员工作为一种全新的交互形式&#xff0c;对企业有着重要的作用&#xff0c;企业、品牌通过数字人的AI语音交互、AI播报等核心功能&#xff0c;可以有效推动企业提升数字水平。 作为3D、AI虚拟数字人技术服务商及方案提供商&#xff…

为什么都喜欢用串口通讯?那为什么还用RS485,SPI和I2C?

1、为什么都喜欢用串口通讯&#xff1f; 之前在做单片机产品的时候&#xff0c;用的最多的就是串口通讯&#xff0c;凡是单片机的外设&#xff0c;优先选用带串口功能的&#xff0c;比如蓝牙模块&#xff0c;WIFI模块&#xff0c;4G模块&#xff0c;电表和显示屏等等。 为什么都…

科研学习|可视化——ggplot2版本的网络可视化

ggplot2是R语言中一个非常流行的数据可视化包&#xff0c;它也可以用于网络可视化。以下是三个基于ggplot2并专门用于网络可视化的R包&#xff1a; ggnet2: 这个包的使用方法与传统的plot函数相似&#xff0c;易于使用。更多信息可在其官方页面查看&#xff1a;ggnet2 geomnet…

KUKA机器人故障报警信息处理(一)

1、KSS00276 机器人参数不等于机器人类型 ①登录专家模式 ②示教器操作&#xff1a;【菜单】—【显示】—【变量】—【单个】 ③名称输入&#xff1a;$ROBTRAFO[] 新值&#xff1a;TRAFONAME[] ④点击【设定值】。 2、电池报警&#xff1a; ①“充电电池警告-发现老化的蓄电池…

【管理咨询宝藏93】大型制造集团数字化转型设计方案

【管理咨询宝藏93】大型制造集团数字化转型设计方案 【格式】PDF版本 【关键词】国际咨询公司、制造型企业转型、数字化转型 【核心观点】 - 235页大型制造型集团数字化转型方案设计&#xff01;细节非常详尽&#xff0c;图表丰富&#xff01; - 系统架构必须采用成熟、具有国…

Mybatis进阶4-权限管理

权限管理 1.权限 //相当于 职责 2.用户 //相当于 职员&#xff08;职员就职于一个职位&#xff09; 3.角色 //相当于 职位&#xff08;有多个职责&#xff09; 权限管理基础表&#xff1a;权限表&#xff0c;用户表&#xff0c;角色表 问题1&#xff1a;…

雷蛇笔记本数据丢失怎么恢复?提供详细指南

在数字化时代&#xff0c;笔记本电脑已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;尽管技术不断进步&#xff0c;数据丢失的风险仍然存在。雷蛇&#xff08;Razer&#xff09;作为一家知名的电脑硬件制造商&#xff0c;其笔记本电脑也难免会遇到这样的问题。当…

Nextjs+Antd5.0打造面向AI的文档可视化引擎(最新更新)

hello&#xff0c;大家好&#xff0c;我是徐小夕。之前和大家分享了很多可视化&#xff0c;零代码和前端工程化的最佳实践&#xff0c;今天继续分享一下我开发的文档引擎 Nocode/WEP 的最新更新。 issue收集&#xff1a; https://github.com/MrXujiang/Nocode-Wep/issues 演示地…

基于51单片机ESP8266wifi控制机器人—送餐、快递

基于51单片机wifi控制机器人 &#xff08;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; ​功能介绍 具体功能&#xff1a; 1.L298N驱动电机&#xff0c;机器人行走&#xff1b; 2.装备红外线感应检测到周围环境&#xff0c;进行行程判断&#xf…

STM32——基础篇

技术笔记&#xff01; 一、初识STM32 1.1 ARM内核系列 A 系列&#xff1a;Application缩写。高性能应用&#xff0c;比如&#xff1a;手机、电脑、电视等。 R 系列&#xff1a;Real-time缩写。实时性强&#xff0c;汽车电子、军工、无线基带等。 M 系列&#xff1a;Microcont…

抖音小店——服务体验,决定店铺生死的关键

哈喽~我是电商月月 新手做抖音小店&#xff0c;是不是觉得“选品”是整个抖店运营过程中最重要的操作 选品在前期确实非常重要&#xff0c;新店铺没有销量&#xff0c;没有评分本身就不好出单&#xff0c;你又不是厂家可以把价格压到最低做促销转化&#xff0c;想出单就只能把…