mabatis 中

news2024/11/19 3:24:34

手动实现MaBatis底层机制

  • 实现任务阶段一
    • 🍍完成读取配置文件, 得到数据库连接
      • 🥦分析 + 代码实现
      • 🥦完成测试
  • 实现任务阶段二
    • 🍍编写执行器, 输入SQL语句, 完成操作
      • 🥦分析 + 代码实现
      • 🥦完成测试
  • 实现任务阶段三
    • 🍍将Sqlsession封装到执行器
      • 🥦分析 + 代码实现
      • 🥦完成测试
  • 实现任务阶段四
    • 🍍开发Mapper接口和Mapper.xml
      • 🥦分析 + 代码实现
  • 实现任务阶段五
    • 🍍开发Mapper接口相映射的MapperBean
      • 🥦分析 + 代码实现
  • 实现任务阶段六
    • 🍍在ZzwConfiguration读取xxxMapper.xml, 能够创建MapperBean对象
      • 🥦分析 + 代码实现
      • 🥦完成测试
  • 实现任务阶段七
    • 🍍实现动态代理Mapper的方法
      • 🥦分析 + 代码实现
      • 🥦完成测试
      • 🥦Debug原生MyBatis-DeaultSqlSession不同方法
      • 🥦Debug执行流程

上一篇, 我们学习到了 mabatis 上

接下来我们学习, 手动实现MaBatis底层机制

在这里插入图片描述

实现任务阶段一

🍍完成读取配置文件, 得到数据库连接

🥦分析 + 代码实现

●分析示意图
在这里插入图片描述

1.创建src/main/resouces/zzw_mybatis.xml 不一定非叫 zzw_mybatis
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<database>
    <!--配置连接数据库的信息-->
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://127.0.0.1:3306/zzw_mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
    <property name="username" value="root"/>
    <property name="password" value="zzw"/>
</database>

2.创建com.zzw.zzwmybatis.sqlsession.Zzwconfiguration.java
遍历xml指定元素 参考
数据库连接的5种方式 参考

/**
 * @author 赵志伟
 * @version 1.0
 * 读取xml文件, 建立连接
 */
public class ZzwConfiguration {

    //属性-类的加载器
    private static ClassLoader loader = ClassLoader.getSystemClassLoader();

    //读取xml文件信息, 并处理
    //Connection 是java.sql包下的
    public Connection build(String resource) {

        Connection connection = null;//java.sql

        //1.得到解析器, 解析配置文件 dom4j
        SAXReader reader = new SAXReader();
        //2.加载配置文件zzw_mybatis.xml, 获取到对应的InputStream
        InputStream inputStream = loader.getResourceAsStream(resource);
        try {
            //3.得到xml文件的文档
            Document document = reader.read(inputStream);
            //4.获取rootElement / zzw_mybatis.xml的根元素, 即<database/>
            Element rootElement = document.getRootElement();
            System.out.println("root="+ rootElement.getName());//root=database
            //5.解析rootElement, 返回Connection => 单独写一个方法
            connection = evalDataSource(rootElement);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return connection;
    }

    //方法会解析zzw_config.xml信息, 并返回connection
    //eval: 评估/解析
    private Connection evalDataSource(Element node) {
        if (!"database".equals(node.getName())) {
            throw new RuntimeException("root 节点应该是<database/>");
        }
        //连接DB的必要参数
        String driverClassName = null;
        String url = null;
        String username = null;
        String password = null;

        //遍历node下的子节点, 获取属性值
        List<Element> properties = node.elements("property");
        for (Element property : properties) {

            String name = property.attributeValue("name");
            String value = property.attributeValue("value");

            //判断是否得name和value
            if (name == null || value == null) {
                throw new RuntimeException("property 节点没有设置name或者value属性");
            }

            switch (name) {
                case "driverClassName":
                    driverClassName = value;
                    break;
                case "url":
                    url = value;
                    break;
                case "username":
                    username = value;
                    break;
                case "password":
                    password = value;
                    break;
                default:
                    throw new RuntimeException("属性名没有匹配到");
            }
        }
        Connection connection = null;
        try {
            Class.forName(driverClassName);
            connection = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return connection; //返回Connection
    }
}

🥦完成测试

com.zzw.test.ZzwMyBatisTest.java

在这里插入图片描述

public class ZzwMyBatisTest {
    @Test
    public void build() {
        ZzwConfiguration zzwConfiguration = new ZzwConfiguration();
        Connection connection = zzwConfiguration.build("zzw_mybatis.xml");
        System.out.println("connection--" + connection);
    }
}

实现任务阶段二

🍍编写执行器, 输入SQL语句, 完成操作

🥦分析 + 代码实现

●分析示意图
说明: 我们把对数据库的操作, 会封装到一套Executor机制中, 程序具有更好的扩展性, 结构更加清晰

下图在原生mybatis的项目中可以看到
在这里插入图片描述在这里插入图片描述

●代码实现
1.新建com.zzw.entity.Monster.java

/**
 * @author 赵志伟
 * @version 1.0
 * Monster和 monster表有映射关系
 *
 * 解读
 * @Getter 就会给所有属性 生成对应的getter方法
 * @Setter 就会给所有属性 生成对应的setter方法
 * @ToString 生成 toString...
 * @NoArgsConstructor 生成无参构造器
 * @AllArgsConstructor 生成全参构造器
 * @Data 注解 
 * 如何选择主要还是看自己的需求
 */
//@Getter
//@Setter
//@ToString
//@NoArgsConstructor
//@AllArgsConstructor
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Monster {
    private Integer id;
    private Integer age;
    private Date birthday;//java.util
    private String email;
    private Integer gender;
    private String name;
    private Double salary;
}

在这里插入图片描述

@Data注解包含了其他注解
在这里插入图片描述

2.新建com.zzw.zzwmybatis.sqlsession.Executor接口

public interface Executor {
    //泛型方法
    public <T> T query(String sql, Object parameter);
}

3.新建com.zzw.zzwmybatis.sqlsession.ZzwExecutor.java

自定义泛型方法, 参考

public class ZzwExecutor implements Executor {

    //属性
    private ZzwConfiguration zzwConfiguration =
            new ZzwConfiguration();

    /**
     * 根据 sql 查询结果
     * @param statement
     * @param parameter
     * @return
     * @param <T>
     */
    @Override
    public <T> T query(String sql, Object parameter) {
        //得到连接Connection
        Connection connection = getConnection();
        //查询返回的结果集
        ResultSet resultSet = null;
        PreparedStatement preparedStatement = null;

        try {
            preparedStatement = connection.prepareStatement(sql);
            //设置参数, 如果参数多, 可以使用数组处理
            preparedStatement.setString(1, parameter.toString());
            resultSet = preparedStatement.executeQuery();
            //把resultSet数据封装到对象-monster
            //说明: 这里做了简化处理
            //认为放回的结果就是一个monster记录
            //完善的写法是一套反射机制
            Monster monster = new Monster();

            //遍历结果集, 把数据封装到monster对象
            while (resultSet.next()) {
                monster.setId(resultSet.getInt("id"));
                monster.setAge(resultSet.getInt("age"));
                monster.setBirthday(resultSet.getDate("birthday"));
                monster.setEmail(resultSet.getString("email"));
                monster.setGender(resultSet.getInt("gender"));
                monster.setName(resultSet.getString("name"));
                monster.setSalary(resultSet.getDouble("salary"));
            }
            return (T) monster;
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    //编写方法, 通过ZzwConfiguration对象, 返回连接
    private Connection getConnection() {
        Connection connection = zzwConfiguration.build("zzw_mybatis.xml");
        return connection;
    }
}

🥦完成测试

public class ZzwMyBatisTest {
    @Test
    public void query() {
        ZzwExecutor executor = new ZzwExecutor();
        Monster monster
                = executor.query("SELECT * FROM `monster` WHERE id = ?", 1);
        System.out.println("monster--" + monster);
    }
}

实现任务阶段三

🍍将Sqlsession封装到执行器

🥦分析 + 代码实现

●分析示意图. 先观察原生MyBatisSqlSession接口和默认实现. 在原生mybatis项目中
在这里插入图片描述在这里插入图片描述

●功能实现

●代码实现
1.创建com.zzw.zzwmybatis.sqlsession.ZzwSqlSession.java

/**
 * @author 赵志伟
 * @version 1.0
 * ZzwSqlSession: 搭建Configuration (连接) 和 Executor 之间的桥梁
 * 这里有操作DB的具体方法
 */
public class ZzwSqlSession {
    //属性
    //执行器
    private Executor executor = new ZzwExecutor();
    //配置
    private ZzwConfiguration zzwConfiguration =
            new ZzwConfiguration();

    //编写方法selectOne, 返回一条记录-对象[做了简化]
    //说明: 在原生的mybatis中, statement不是sql, 而是要执行的接口方法
    //这里我们是做了简化
    public <T> T selectOne(String statement, Object parameter) {
        return executor.query(statement, parameter);
    }

    //selectList - update - delete - insert
}

🥦完成测试

public class ZzwMyBatisTest {
    @Test
    public void selectOne() {
        ZzwSqlSession zzwSqlSession = new ZzwSqlSession();
        Monster monster =
                zzwSqlSession.selectOne("select * from `monster` where id = ?", 1);
        System.out.println("monster--" + monster);
    }
}

实现任务阶段四

🍍开发Mapper接口和Mapper.xml

🥦分析 + 代码实现

●分析示意图
在这里插入图片描述在这里插入图片描述

●代码实现
1.创建com.zzw.mapper.MonsterMapper接口

/**
 * @author 赵志伟
 * @version 1.0
 * MonsterMapper: 声明对db的crud方法
 */
public interface MonsterMapper {
    //查询方法
    public Monster getMonsterById(Integer id);
}

2.src/main/resources(类路径)下新建 MonsterMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<mapper namespace="com.zzw.mapper.MonsterMapper">
    <!--实现配置接口方法getMonsterById-->
    <select id="getMonsterById" resultType="com.zzw.entity.Monster">
        select * from monster where id = ?
    </select>
</mapper>

实现任务阶段五

🍍开发Mapper接口相映射的MapperBean

🥦分析 + 代码实现

●分析示意图
在这里插入图片描述

●代码实现
1.创建com.zzw.zzwmybatis.config.Function.java

/**
 * @author 赵志伟
 * @version 1.0
 * Function: 记录对应的Mapper的方法信息
 */
@Setter
@Getter
@ToString
public class Function {
    //属性
    private String sqlType;//sql类型. 比如select, insert, update, delete
    private String funcName;//方法名
    private String sql;//执行sql语句
    private Object resultType;//返回类型
    private String parameter;//参数类型
}

2.创建com.zzw.zzwmybatis.config.MapperBean.java

/**
 * @author 赵志伟
 * @version 1.0
 * MapperBean: 将Mapper信息, 进行封装
 */
@Setter
@Getter
@ToString
public class MapperBean {
    private String interfaceName;//接口的全路径-接口名
    
    //接口下的所有方法-集合
    private List<Function> functions;
}

实现任务阶段六

🍍在ZzwConfiguration读取xxxMapper.xml, 能够创建MapperBean对象

🥦分析 + 代码实现

●分析示意图

●代码实现
1.修改com.zzw.zzwmybatis.sqlsession.Zzwconfiguration.java, 增加方法

//读取xxxMapper.xml, 能够创建MapperBean对象
//path 就是xml的路径+文件名, 是从类的加载路径计算的
//如果: xxxMapper.xml 文件是放在resources目录下, 直接传入xml文件名即可
public MapperBean readMapper(String path) {

    MapperBean mapperBean = new MapperBean();

    //1.得到解析器 -> dom4j
    SAXReader reader = new SAXReader();
    //2.获取到xml文件对应的InputStream
    InputStream inputStream = loader.getResourceAsStream(path);
    try {
        //3.得到xml文件的文档
        Document document = reader.read(inputStream);
        //4.获取xml文档的根元素 <mapper/>
        Element rootElement = document.getRootElement();
        System.out.println("root="+ rootElement);

        //获取到namespace
        String namespace = rootElement.attributeValue("namespace").trim();
        //设置mapperBean的属性interfaceName
        mapperBean.setInterfaceName(namespace);

        //得到rootElement的迭代器-可以遍历它的子节点/子元素-生成Function
        Iterator<Element> rootIterator = rootElement.elementIterator();

        //保存接口下所有的方法信息
        List<Function> functions = new ArrayList<>();
        //遍历它的子节点/子元素-生成Function
        while (rootIterator.hasNext()) {
            //取出一个子元素-dom4j.Element
            Element element = rootIterator.next();
            /*
            <select id="getMonsterById" resultType="com.zzw.entity.Monster">
                select * from monster where id = ?
            </select>
             */
            Function function = new Function();
            String sqlType = element.getName().trim();
            String funcName = element.attributeValue("id").trim();
            String sql = element.getTextTrim();//等价于: getText().trim()
            //resultType是返回类型的全路径-即全类名
            String resultType = element.attributeValue("resultType").trim();
            //开始封装
            function.setSqlType(sqlType);
            function.setFuncName(funcName);
            function.setSql(sql);
            //这里多说一句 function-private Object resultType; 是resultType实例
            //所以我们使用反射生成一个对象, setResultType
            Object instance = Class.forName(resultType).newInstance();
            function.setResultType(instance);

            //将封装好的function对象放人到 list
            functions.add(function);
        }
        //while循环结束后, 将function的list设置
        mapperBean.setFunctions(functions);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    return mapperBean;
}

🥦完成测试

public class ZzwMyBatisTest {
    @Test
    public void readMapper() {
        ZzwConfiguration zzwConfiguration = new ZzwConfiguration();
        MapperBean mapperBean = zzwConfiguration.readMapper("MonsterMapper.xml");
        System.out.println("mapperBean--" + mapperBean);
        System.out.println("ok~~");
    }
}

实现任务阶段七

🍍实现动态代理Mapper的方法

🥦分析 + 代码实现

●分析示意图
无

前面我们有2个地方学习过动态代理, 切面编程的底层支撑是动态代理
动态代理: AOP切面编程
动态代理: 手动实现spring底层机制

●代码实现
1.新增com.zzw.zzwmybatis.sqlsession.ZzwMapperProxy.java
转String类型

/**
 * @author 赵志伟
 * @version 1.0
 * ZzwMapperProxy: 动态代理生成Mapper对象, 调用ZzwExecutor方法
 */
@SuppressWarnings({"all"})
public class ZzwMapperProxy implements InvocationHandler {
    //属性
    private ZzwSqlSession zzwSqlSession;
    private String mapperFile;
    private ZzwConfiguration zzwConfiguration;

    //构造器
    public ZzwMapperProxy(ZzwSqlSession zzwSqlSession,
                          ZzwConfiguration zzwConfiguration,
                          Class clazz) {
        this.zzwSqlSession = zzwSqlSession;
        this.zzwConfiguration = zzwConfiguration;
        this.mapperFile = clazz.getSimpleName() + ".xml";
    }

    //前面讲解spring时, 讲过动态代理知识
    //提示: 当执行Mapper接口的代理对象方法时, 会执行到invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        MapperBean mapperBean =
                zzwConfiguration.readMapper(this.mapperFile);

        //判断是否是xml文件对应的接口
        if (!method.getDeclaringClass().getName().equals(mapperBean.getInterfaceName())) {
            return null;
        }

        //取出mapperBean的functions
        List<Function> functions = mapperBean.getFunctions();
        //判断当前mapperBean解析对应MapperXML后, 有方法
        if (functions != null && functions.size() != 0) {

            for (Function function : functions) {
                //当前要执行的方法和function.getFuncName()一样
                //说明我们可以从当前遍历的function对象中, 取出相应的信息sql, 并执行方法
                if (method.getName().equals(function.getFuncName())) {{
                    //如果我们当前的function 要执行的sqlType是select
                    //我们就去执行selectOne
                    /**
                     * 说明:
                     * 1. 如果要执行的方法是select, 就对应执行selectOne
                     * 2. 因为我们在ZzwSqlSession就写了一个 selectOne
                     * 3. 实际上ZzwSqlSession对应不同的方法(多个方法)
                     * , 根据不同的匹配情况调用不同方法, 并且还需要进行参数解析处理, 还有比较复杂的字符串处理, 拼接sql, 处理返回类型等等工作
                     * 4. 因为我们主要是想讲解mybatis 生成mapper动态代理对象, 调用方法的机制, 所以我们做了简化
                     */
                    if ("select".equals(function.getSqlType())) {
                        return zzwSqlSession.selectOne(function.getSql(), String.valueOf(args[0]));
                    }
                }}
            }
        }
        return null;
    }
}

2.修改com.zzw.zzwmybatis.sqlsession.ZzwSqlSession, 增加方法

/**
 * 1. 返回mapper的动态代理对象
 * 2. 这里的clazz 到时传入的是 MonsterMapper.class
 * 3. 放回的就是MonsterMapper接口代理对象
 * 4. 当执行接口方法时(通过代理对象调用), 根据动态代理机制, 会执行到ZzwMapperProxy-invoke
 * @param clazz
 * @return
 * @param <T>
 */
public <T> T getMapper(Class<T> clazz) {
    //返回动态代理对象
    return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new ZzwMapperProxy(this, zzwConfiguration, clazz));
}

🥦完成测试

1.测试com.zzw.test.ZzwMyBatisTest

public class ZzwMyBatisTest {
    @Test
    public void getMapper() {
        ZzwSqlSession zzwSqlSession = new ZzwSqlSession();
        MonsterMapper mapper = zzwSqlSession.getMapper(MonsterMapper.class);
        System.out.println("mapper运行类型=" + mapper.getClass());//mapper是一个代理对象
        Monster monster = mapper.getMonsterById(1);
        System.out.println("monster--" + monster);
    }
}

2.新建com.zzw.zzwmybatis.sqlsession.ZzwSessionFactory

/**
 * @author 赵志伟
 * @version 1.0
 * ZzwSessionFactory: 会话工厂-返回会话ZzwSqlSession
 */
public class ZzwSessionFactory {

    public static ZzwSqlSession openSession() {
        return new ZzwSqlSession();
    }
}

3.测试com.zzw.test.ZzwMyBatisTest

public class ZzwMyBatisTest {
    @Test
    public void openSession() {
        ZzwSqlSession zzwSqlSession = ZzwSessionFactory.openSession();
        MonsterMapper mapper = zzwSqlSession.getMapper(MonsterMapper.class);
        Monster monster = mapper.getMonsterById(1);
        System.out.println("monster--" + monster);
    }
}

🥦Debug原生MyBatis-DeaultSqlSession不同方法

找到mybatis项目, 在DefaultSqlSessionselectOne方法打上断点, 测试select方法

同时证明:原生的mybatis中,selectOne方法的statement参数不是sql, 而是要执行的接口方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Step Into, 追到BaseExecutordoQuery方法

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into, doQuery里面就是原生的Jdbc代码了

在这里插入图片描述

DefaultSqlSessioninsert方法打上断点, 测试insert方法
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

继续 Step Into, doUpdate方法里面就是原生的Jdbc代码了

在这里插入图片描述

DefaultSqlSessiondelete方法打上断点, 测试delete方法
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

DefaultSqlSessionupdate方法打上断点, 测试update方法
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

🥦Debug执行流程

回到自己写的zzw-mybatis项目, 开始debug
在这里插入图片描述

Step Into

在这里插入图片描述

Step Into

在这里插入图片描述

Step Out

在这里插入图片描述

估值

在这里插入图片描述

Step Into

在这里插入图片描述

Step Out

在这里插入图片描述

估值, mapper是个代理对象

在这里插入图片描述

ZzwMapperProxyinvoke方法下个断点, 直接放行

在这里插入图片描述

mapperBean估值

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Step Into

在这里插入图片描述

继续 Step Into

在这里插入图片描述

查看传进来的参数

在这里插入图片描述

拿到Jdbc的结果集

在这里插入图片描述

Step Out

在这里插入图片描述

monster进行估值

在这里插入图片描述

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

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

相关文章

基于PHP的餐厅管理系统APP设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术 3 1.1 MVC 3 1.2 ThinkPHP 3 1.3 MySQL数据库 3 1.4 uni-app 4 1.5 本章小结 4 2 系统分析 5 2.1 功能需求 5 2.2 用例分析 7 2.3 非功能需求 8 2.4 本章小结 8 3 系统设计 9 3.1 系统总体设计 9 3.2 系统详细设计 10 3.3 本章小…

数字图像处理—python

pycahem终端也可以下载库&#xff0c;我只会用终端下载,用的镜像网站 pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple pip install scikit-image -i https://pypi.tuna.tsinghua.edu.cn/simple. pip install matplotlib -i https://pypi.tuna.tsinghua.edu.c…

超标量与多发射和超长指令字设计

前言 大家好我是jiantaoyab&#xff0c;这是我所总结作为学习的笔记第11篇,在这里分享给大家,这篇文章讲超标量与多发射和超长指令字设计&#xff0c;前面文章提到的书籍的pdf大家没有的话可以私信找我要&#xff01; 《计算机组成与设计&#xff1a;硬件 / 软件接口》中4.10…

什么是PLC设备数据采集?

在当今工业4.0和智能制造的大背景下&#xff0c;数据的价值日益凸显。特别是对于PLC&#xff08;可编程逻辑控制器&#xff09;这类核心工业设备&#xff0c;数据采集显得尤为重要。那么&#xff0c;究竟什么是PLC设备数据采集&#xff1f;它又有何价值呢&#xff1f;今天&…

Python打印Linux系统中最常用的linux命令之示例

一、Linux中的~/.bash_history文件说明&#xff1a; 该文件保存了linux系统中运行过的命令的历史。使用该文件来获取命令的列表&#xff0c;并统计命令的执行次数。统计时&#xff0c;只统计命令的名称&#xff0c;以不同参数调用相同的命令也视为同一命令。 二、示例代码&am…

一篇搞定mysql数据库基础

目录 一、MySQL具体的特点 1.关系型数据库&#xff08;RDBMS&#xff09;&#xff1a; 2.MySQL是一个“客户端-服务器”结构的程序 Q1:服务器能不能知道客户端什么时候发请求&#xff1f;&#xff1f; Q2:服务器是只给一个客户端提供服务吗&#xff1f;&#xff1f; 二、M…

靶场:sql-less-18——sqlmap爆库的操作

本文操作环境&#xff1a;KaLi-Linux 靶场链接&#xff1a;Less-18 Header Injection- Error Based- string 1、打开靶场&#xff0c;挂好代理&#xff0c;使用bp抓包 2、复制抓包的数据内容&#xff0c;在kali-Linux中新建文档复制保存 3、打开命令窗口&#xff1a;确定注入点…

【更新】数字金融与企业ESG表现:效应、机制与“漂绿”检验数据集(2011-2022年)

参照温亚东&#xff08;2024&#xff09;的做法&#xff0c;本团队对来自统计与决策《数字金融与企业ESG表现&#xff1a;效应、机制与"漂绿"检验》一文中的基准回归部分进行复刻 一、数据介绍 数据名称&#xff1a;数字金融与企业ESG表现 参考期刊&#xff1a;《统…

Linux--编译链接的过程

一.gcc,g,gdb安装 命令行写gcc,g,gdb根据提示安装: sudo apt install gcc/g/gdb 二.gcc分布编译链接 编译链接的过程&#xff1a;(面试过程一个大的问题&#xff09; (1)预编译: gcc -E main.c -o main.i 用gcc预编译main.c输出main.i(2)编译: gcc -S main.i -o main.s(3)汇编…

Java学习笔记(10)

学生管理系统项目 package exercise;import java.util.ArrayList; import java.util.Scanner;public class StudentProgramme {public static void main(String[] args) {ArrayList<Student> studentArrayList new ArrayList<>();Student newStudent new Student…

Linux——文件标识符

目录 一、文件基础 二、常见的C语言文件接口 三、系统文件接口 四、理解语言与系统文件操作的关系 五、如何理解一切皆文件 六、文件标识符再理解 一、文件基础 一个空文件&#xff0c;也会占用磁盘空间&#xff0c;这是因为文件不仅仅有存放在里面的内容&#xff0c;还…

医学图像分析算法的原理

医学图像分析算法的实现原理涉及数据准备、特征提取、模型选择与训练、模型评估与优化以及部署与应用等多个步骤和技术。通过这些步骤&#xff0c;可以利用机器学习和深度学习技术来帮助医生更准确、更高效地进行医学图像诊断和分析。北京木奇移动技术有限公司&#xff0c;专业…

LeetCode 1315.祖父节点值为偶数的节点和

给你一棵二叉树&#xff0c;请你返回满足以下条件的所有节点的值之和&#xff1a; 该节点的祖父节点的值为偶数。&#xff08;一个节点的祖父节点是指该节点的父节点的父节点。&#xff09; 如果不存在祖父节点值为偶数的节点&#xff0c;那么返回 0 。 示例&#xff1a; 输入…

面试官:MySQL的七种日志

哪七种日志日志&#xff1f; 错误日志&#xff08;error log&#xff09; error log主要记录MySQL在启动、关闭或者运行过程中的错误信息&#xff0c;在MySQL的配置文件my.cnf中&#xff0c; 可以通过log-error/var/log/mysqld.log 执行mysql错误日志的位置。 慢查询日志&a…

重读 Java 设计模式: 解析单例模式,保证唯一实例的创建与应用

本周工作太忙了&#xff0c;变成了加班狗&#xff0c;下班回来也没时间写&#xff0c;只能利用周末时间写了&#x1f62d;。 好了&#xff0c;言归正传&#xff0c;本次我们先来介绍下设计模式中创建型模式-单例模式。 一、引言 单例模式是设计模式中最简单但又最常用的一种模…

【图论】 【割点】 【双连通分类】LCP 54. 夺回据点

本文涉及知识点 图论 割点 双连通分类 割点原理及封装好的割点类 LeetCode LCP 54. 夺回据点 魔物了占领若干据点&#xff0c;这些据点被若干条道路相连接&#xff0c;roads[i] [x, y] 表示编号 x、y 的两个据点通过一条道路连接。 现在勇者要将按照以下原则将这些据点逐一…

Docker容器Docker桌面配置镜像加速

打开Docker Desktop应用程序&#xff0c;点击设置 具体配置如下&#xff1a; {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"features": {"buil…

基于java的足球联赛管理系统(程序+数据库+文档)

** &#x1f345;点赞收藏关注 → 私信领取本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345;** 一、研究背景…

【数据库】软件测试之MySQL数据库练习题目

有表如下&#xff1a; Student 学生表 SC 成绩表 Course 课程表 Teacher 老师表 每个学生可以学习多门课程&#xff0c;每一个课程都有得分&#xff0c;每一门课程都有老师来教&#xff0c;一个老师可以教多个学生 1、查询姓‘朱’的学生名单 select * from Student whe…

「CISP题库精讲」CISP题库习题解析精讲20道

前言 本篇主要对CISP教材第九章《计算环境安全》的一些习题进行讲解&#xff0c;包括20道题&#xff0c;这里只是部分习题&#xff0c;针对第九章可能会多写几章的内容&#xff0c;如果我发布的这些习题里面没有你想找的那道题&#xff0c;你也可以直接私信我&#xff0c;我加…