【JavaEE基础学习打卡06】JDBC之进阶学习PreparedStatement

news2025/2/25 5:56:11

目录

  • 前言
  • 一、PreparedStatement是什么
  • 二、重点理解预编译
  • 三、PreparedStatement基本使用
  • 四、Statement和PreparedStatement比较
    • 1.PreparedStatement效率高
    • 2.PreparedStatement无需拼接参数
    • 3.PreparedStatement防止SQL注入
  • 总结


前言

📜 本系列教程适用于JavaWeb初学者、爱好者,小白白。我们的天赋并不高,可贵在努力,坚持不放弃。坚信量最终引发质变,厚积薄发。
🚀 文中白话居多,尽量以小白视角呈现,帮助大家快速入门。
🎅 我是 蜗牛老师,之前网名是 Ongoing蜗牛,人如其名,干啥都慢,所以更新也慢。希望大家多多支持,让我动力十足!

上篇文章我们学习了 JDBC 编程基本步骤,步骤中使用 Statement 执行 SQL 语句。其实还有一个更好的方式,就是 PreparedStatement,预编译语句。与 Statement 相比有诸多优势,目前开发中一般使用 PreparedStatement。所以我们非常有必要进行学习,而且日后的持久层框架底层也是使用 PreparedStatement


一、PreparedStatement是什么

在 JDBC 编程基本步骤中,我们创建 Statement(语句)对象,向数据库发送要执行的 SQL 语句。Statement 一般用于实现不带参数的简单 SQL 语句,也就是说它执行的是静态 SQL 语句。每次执行 SQL 语句时,都会将 SQL 语句编译为数据库可以理解的格式。Statement 的工作原理是将 SQL 语句发送给数据库,然后数据库执行该语句并返回结果。

那么 PreparedStatement 是什么呢?大家应该也发现了,PreparedStatementStatement 多了单词 Prepared,理解的重点就是 Prepared,它是预编译的意思,所以平时被称为预编译的 Statement(语句)。

PreparedStatement 是一个接口,而且它是 Statement 接口的子接口。

// Statement接口
public interface Statement extends Wrapper, AutoCloseable {}

// PreparedStatement接口
public interface PreparedStatement extends Statement {}

PreparedStatement 接口用于执行动态 SQL 语句。它允许在 SQL 语句中使用占位符(? 英文格式问号),然后在执行之前将这些占位符(?)替换为实际的值。PreparedStatement 在执行之前会对 SQL 语句进行预编译,这样可以提高执行效率。工作原理是将 SQL 语句发送给数据库之前,先将其编译为可执行的格式,然后将实际的参数值传递给占位符(?)。

具体解决什么问题呢?我们来看一个需求:一个博客网站要根据某个文章编号(id)查询该文章内容进行展示,文章编号100和101分别代表不同的文章。我们来看 SQL 语句:

select * from article where id = 100;
select * from article where id = 101;

在上述需求中,我们会反复执行一条结构相似的 SQL 语句。其实在日常需求当中,经常需要执行 SQL 语句结构基本相似,但是执行时的参数值不同。这种 SQL 语句我们可以叫做动态 SQL 语句,就可以使用 PreparedStatement 接口,SQL 语句中的参数可以使用占位符(?)代替,也就是说占位符(?)的位置参数未知,可以是100,可以是101或是其他。带有占位符(?)SQL 语句如下:

select * from article where id = ?;

需要注意的是 Statement 执行 SQL 语句时是不允许带有占位符(?)参数的,而且 PreparedStatement 执行带有占位符参数的 SQL 语句时,参数必须要传入实际的值才可以。

二、重点理解预编译

大概知道 PreparedStatement 是干什么的之后,我们来重点理解一下预编译。

预编译是指在执行 SQL 语句之前,将 SQL 语句编译为一个预定义的内部格式,以便数据库能够更有效地执行。

预编译的过程包括以下几个步骤:

  • 语法分析:数据库系统会对传入的 SQL 语句进行语法分析,检查其是否符合语法规则。

  • 语义分析:数据库系统会对 SQL 语句进行语义分析,检查表和列是否存在、权限是否足够等。

  • 优化和执行计划生成:数据库系统会对 SQL 语句进行优化,生成一个最佳的执行计划,以便在执行时能够高效地获取数据。

在预编译完成后,数据库会将编译后的执行计划存储在缓存中,以便下次执行相同的预编译语句时可以直接使用执行计划,从而节省了编译的时间和资源。这也是 PreparedStatement 相较于 Statement 的一个优势所在。

当多次执行相同的预编译语句时,由于已经完成了编译和优化的步骤,预编译的语句可以更快速地执行,因为只需传递参数值并执行执行计划,而不需要再进行语法分析、语义分析和执行计划生成等步骤。

需要注意的是,预编译功能主要适用于需要多次执行相同的 SQL 语句的场景,因为预编译的语句在编译时会占用一定的资源。如果只需要执行一次或是每次 SQL 语句都不同,那么使用 Statement 可能会更合适。

三、PreparedStatement基本使用

在对 PreparedStatement 有了基本了解后,我们进行简单使用。在 JDBC 编程基本步骤中查询了 teacher 表的全部数据,在这里将再次使用 teacher 表,这次我们往表中添加数据。

test-jdbc 项目中新建类 TestPreparedStatement,仍然生成 main() 方法。方法中重新编写 JDBC 代码,顺带巩固。

在这里插入图片描述
JDBC 编程的第一步就是加载驱动,第二步是连接 Connection 连接。大家还记得代码如何编写吗?

/**
 * 敲入main,根据提示自动生成主函数main()方法
 * @param args
 */
public static void main(String[] args) {

    try {
        // ①动态加载指定路径下的MySQL JDBC驱动,将其注册到DriverManager中。
        Class.forName("com.mysql.cj.jdbc.Driver");
        // ②建立到给定数据库URL的连接。
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");
   
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
}

之前第三步是创建一个 Statement 对象,用于向数据库发送 SQL 语句。现在我们改用 PreparedStatement。和 Statement 一样我们需要先拿到 PreparedStatement 对象,使用 Connection 中的 prepareStatement(String) 方法获得。我们来看 API:

/**
 * 创建一个PreparedStatement对象,用于向数据库发送参数化的SQL语句。
 * 可以预编译带有或不带有IN参数的SQL语句,并将其存储在PreparedStatement对象中。然后可以使用该对象多次有效地执行该语句。 
 */
PreparedStatement prepareStatement(String sql) throws SQLException;

接下来我们来编写第三步:使用 Connection 来创建 PreparedStatement 对象。

/**
 * 敲入main,根据提示自动生成主函数main()方法
 * @param args
 *
 */
public static void main(String[] args) {

    try {
        // ①动态加载指定路径下的MySQL JDBC驱动,将其注册到DriverManager中。
        Class.forName("com.mysql.cj.jdbc.Driver");
        // ②建立到给定数据库URL的连接。
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");
        // ③使用Connection来创建PreparedStatement对象,将把语句发送到数据库进行预编译。
        PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name, sex, age) value (?, ?, ?)");

    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
}

上述③代码处,使用 ConnectionprepareStatement(String sql) 方法来创建 PreparedStatement 对象,该方法需要传入一个 SQL 语句字符串,可以包含占位符。上述 SQL 语句向 teacher 表中插入一条数据,由于表中 id 为自增,所以插入时不需要给 id 指定值。对于 namesexage 三个字段的值使用占位符(?)进行占位。

PreparedStatement 也提供了 execute()executeUpdate()executeQuery()executeLargeUpdate()(1.8版本新增)方法去执行 SQL 语句。这里我们使用 executeUpdate() 方法去执行 insert 语句。由于执行的 SQL 语句带有占位符参数,因此在执行语句前必须为这些参数传入参数值,PreparedStatement 提供了一系列的 setXxx(int index, Xxx value) 方法来传入参数值。

在这里插入图片描述
我们来看具体代码实现:

/**
 * 敲入main,根据提示自动生成主函数main()方法
 * @param args
 *
 */
public static void main(String[] args) {

    try {
        // ①动态加载指定路径下的MySQL JDBC驱动,将其注册到DriverManager中。
        Class.forName("com.mysql.cj.jdbc.Driver");
        // ②建立到给定数据库URL的连接。
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");
        // ③使用Connection来创建PreparedStatement对象,将把语句发送到数据库进行预编译。
        PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name, sex, age) value (?, ?, ?)");
        // ④设置参数并执行SQL语句
        preparedStatement.setString(1, "赵六");
        preparedStatement.setString(2, "女");
        preparedStatement.setInt(3, 20);
        // 执行SQL语句
        preparedStatement.executeUpdate();

    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
}

SQL 语句中的第一个占位符(?),是表中 name 字段的值,为字符串,所以这里使用 setString() 方法,方法中需要两个参数,一个是占位符(?)的位置,从1开始,第二个参数是具体的值。其他占位符(?)操作一样,需要注意的是占位符(?)的位置及该位置传入的参数类型。如果编程时不清楚预编译 SQL 语句中各参数的类型,我们可以使用 setObject() 方法传入参数,然后由 PreparedStatement 负责类型转换。

最后一步就是关闭资源,使用到哪些资源就关闭哪些资源,注意当前代码中我们没有使用 StatementResultSet

/**
 * 敲入main,根据提示自动生成主函数main()方法
 * @param args
 *
 */
public static void main(String[] args) {

    try {
        // ①动态加载指定路径下的MySQL JDBC驱动,将其注册到DriverManager中。
        Class.forName("com.mysql.cj.jdbc.Driver");
        // ②建立到给定数据库URL的连接。
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");
        // ③使用Connection来创建PreparedStatement对象,将把语句发送到数据库进行预编译。
        PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name, sex, age) value (?, ?, ?)");
        // ④设置参数并执行SQL语句
        preparedStatement.setString(1, "赵六");
        preparedStatement.setString(2, "女");
        preparedStatement.setInt(3, 20);
		// 执行SQL语句
        preparedStatement.executeUpdate();

        // ⑤ 关闭资源
        preparedStatement.close();
        connection.close();

    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
}

我们运行程序,控制台无报错,通过客户端查看表中记录,是否有刚刚插入的赵六数据。

在这里插入图片描述

四、Statement和PreparedStatement比较

StatementPreparedStatement 的相同之处在于它们都是用于执行 SQL 语句的接口。它们都可以执行查询和更新操作,并且都可以接收参数。不同之处在于 PreparedStatement 可以预编译 SQL 语句并使用占位符(?),这样可以提高执行效率,并且可以防止 SQL 注入攻击。

1.PreparedStatement效率高

我们进行简单测试,向 teacher 表分别插入1000条记录进行对比。

import java.sql.*;

/**
 * PreparedStatementVsStatement PreparedStatement和Statement比较
 *
 * @author Ongoing蜗牛
 * @since 2023/8/24 14:25
 */
public class PreparedStatementVsStatement {

    /**
     * 使用Statement执行SQL语句
     *
     * @param connection 数据库连接对象
     */
    public void insertByStatement(Connection connection){
        // 以毫秒为单位返回当前时间,记录开始时间
        long start = System.currentTimeMillis();
        try {
            // 创建Statement对象
            Statement statement = connection.createStatement();
            // 使用for循环执行插入1000条记录
            for (int i = 0; i < 1000; i++) {
                statement.executeUpdate("insert into teacher (name, sex, age) value ('张某" + i + "', '男', 20)");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("使用Statement执行耗时:" + (end - start));

    }

    /**
     * 使用PreparedStatement执行SQL语句
     *
     * @param connection 数据库连接对象
     */
    public void insertByPreparedStatement(Connection connection){
        // 以毫秒为单位返回当前时间,记录开始时间
        long start = System.currentTimeMillis();
        try {
            // 创建Statement对象
            PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name, sex, age) value (?, ?, ?)");
            // 使用for循环设置参数值并执行
            for (int i = 0; i < 1000; i++) {
                preparedStatement.setString(1, "李某" + i);
                preparedStatement.setString(2, "女");
                preparedStatement.setInt(3, 23);

                preparedStatement.executeUpdate();
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("使用PreparedStatement执行耗时:" + (end - start));

    }

    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {

        PreparedStatementVsStatement psvs = new PreparedStatementVsStatement();

        try {
            // 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 建立数据库连接。
            Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");

            // 调用 使用Statement执行SQL语句 方法
            psvs.insertByStatement(connection);
            // 调用 使用PreparedStatement执行SQL语句 方法
            psvs.insertByPreparedStatement(connection);

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }
}

执行结果如下:

使用Statement执行耗时:751
使用PreparedStatement执行耗时:637

通过上述测试代码可知,同样是插入1000条记录,使用 Statement 需要传入1000条 SQL 语句,而使用 PreparedStatement 其实只需要传入一条预编译的 SQL 语句,然后对其进行1000次设置参数。从执行多用时间也可以看出 PreparedStatement 的执行效率要高于 Statement

2.PreparedStatement无需拼接参数

其实 PreparedStatement 还有一个优势是在使用参数时,不需要拼接,减少 SQL 语句的复杂的。我们看下面的伪代码:

// 教师信息
String name = "张三";
String sex = "男";
int age = 20;

// 使用Statement执行,需要拼接参数
statement.executeUpdate("insert into teacher (name, sex, age) value ('"+name+"','"+sex+"',"+age+")");

// 使用PreparedStatement执行,不需要拼接参数
PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name, sex, age) value (?, ?, ?)");
preparedStatement.setString(1, name);
preparedStatement.setString(2, sex);
preparedStatement.setInt(3, age);
preparedStatement.executeUpdate();

3.PreparedStatement防止SQL注入

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

经典的例子就是登录操作,一般正常用户会输入用户和密码进行登录操作,系统根据用户输入到数据库表中进行匹配,如果找到相应的记录则登录成功,否则登录失败。那么我们要通过 SQL 语句的执行去进行匹配操作。这里还是使用 teacher 表简单模拟,要求输入的姓名在表中存在就登录成功。正常用户输入姓名,系统执行 SQL 匹配。非正常用户会输入特殊字符串匹配。代码如下:

import java.sql.*;

/**
 * TestSqlInjection SQL注入
 *
 * @author Ongoing蜗牛
 * @since 2023/8/24 15:22
 */
public class TestSqlInjection {

    /**
     * 使用姓名登录,Statement执行SQL语句
     * @param name 姓名
     */
    public void loginByStatement(String name){
        // 打印输入的姓名
        System.out.println("登录姓名:" + name);
        // 登录标识
        boolean flag = false;
        try {
            // 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 建立数据库连接。
            Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");
            // 创建Statement对象
            Statement statement = connection.createStatement();
            // 执行SQL语句并返回结果
            ResultSet resultSet = statement.executeQuery("select * from teacher where name = '"+ name +"'");
            // 打印执行的SQL语句
            System.out.println("select * from teacher where name = '"+ name +"'");
            // 处理结果
            while (resultSet.next()){
                // 返回至少一条记录就登录成功
                flag = true;
                break;
            }

            // 关闭资源
            resultSet.close();
            statement.close();
            connection.close();

            // 打印输出结果
            if (flag){
                System.out.println("登录成功!");
            }else{
                System.out.println("登录失败!");
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 主函数测试
     * @param args
     */
    public static void main(String[] args) {
        TestSqlInjection testSqlInjection = new TestSqlInjection();
        //String loginName = "张三"; //数据库中可以匹配,登录成功
        //String loginName = "某某"; //数据库中匹配不到,登录失败
        String loginName = "' or true or '"; //数据库中匹配不到,但是登录成功
        testSqlInjection.loginByStatement(loginName);
    }
}

执行结果如下:

登录姓名:' or true or '
select * from teacher where name = '' or true or ''
登录成功!

这回大家明白什么是 SQL 注入了吧。那么使用 PreparedStatement 进行同样的登录操作,也会遭遇 SQL 注入登录成功吗?

/**
 * 使用姓名登录,PreparedStatement执行SQL语句
 * @param name 姓名
 */
public void loginByPreparedStatement(String name){
    // 打印输入的姓名
    System.out.println("登录姓名:" + name);
    // 登录标识
    boolean flag = false;
    try {
        // 注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        // 建立数据库连接。
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test_jdbc?serverTimezone=Asia/Shanghai", "root", "root");
        // 创建PreparedStatement对象,预编译SQL语句
        PreparedStatement preparedStatement = connection.prepareStatement("select * from teacher where name = ?");
        // 设置参数
        preparedStatement.setString(1, name);
        // 执行SQL语句
        ResultSet resultSet = preparedStatement.executeQuery();
        // 打印执行的SQL语句
        System.out.println(preparedStatement.toString());
        // 处理结果
        while (resultSet.next()){
            // 返回至少一条记录就登录成功
            flag = true;
            break;
        }

        // 关闭资源
        resultSet.close();
        preparedStatement.close();
        connection.close();

        // 打印输出结果
        if (flag){
            System.out.println("登录成功!");
        }else{
            System.out.println("登录失败!");
        }

    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
}

/**
 * 主函数测试
 * @param args
 */
public static void main(String[] args) {
    TestSqlInjection testSqlInjection = new TestSqlInjection();
    //String loginName = "张三"; //数据库中可以匹配,登录成功
    //String loginName = "某某"; //数据库中匹配不到,登录失败
    String loginName = "' or true or '"; //数据库中匹配不到,但是登录成功
    //testSqlInjection.loginByStatement(loginName);
    testSqlInjection.loginByPreparedStatement(loginName);
}

我们查看执行结果,为登录失败,也就是说 PreparedStatement 可以防止 SQL 注入。究其原因很简单,PreparedStatement' or true or ' 作为一个参数值传给 name,数据库中当然没有该姓名了。

登录姓名:' or true or '
com.mysql.cj.jdbc.ClientPreparedStatement: select * from teacher where name = '' or true or ''
登录失败!

总结

PreparedStatement 接口用于执行动态SQL语句。 它允许在 SQL 语句中使用占位符,然后在执行之前将这些占位符替换为实际的值。

预编译是指在执行 SQL 语句之前,将 SQL 语句编译为一个预定义的内部格式,以便数据库能够更有效地执行。

PreparedStatement 关键步骤:

// 使用Connection来创建PreparedStatement对象,将把语句发送到数据库进行预编译。
PreparedStatement preparedStatement = connection.prepareStatement("insert into teacher (name, sex, age) value (?, ?, ?)");
// 设置参数并执行SQL语句
preparedStatement.setString(1, "赵六");
preparedStatement.setString(2, "女");
preparedStatement.setInt(3, 20);
// 执行SQL语句        
preparedStatement.executeUpdate();

PreparedStatement 优势:

  • 预编译 SQL 语句,效率高。
  • 无需拼接参数,更简单。
  • 防止 SQL 注入,更安全。

日后 JDBC 编程使用 PreparedStatement 执行 SQL 语句。

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

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

相关文章

Kali Linux中的SQL注入攻击如何进行

Kali Linux中的SQL注入攻击如何进行&#xff1f; 什么是SQL注入攻击&#xff1f; SQL注入是一种常见的Web应用程序漏洞&#xff0c;攻击者可以通过恶意构造的SQL查询字符串&#xff0c;绕过应用程序的验证和过滤&#xff0c;进而访问或操纵数据库中的数据。这可能导致泄露敏感…

Linux 命令大全(看这一篇就足够)

目录 第一章&#xff1a;Linux目录结构 第一节&#xff1a;基本介绍 第二节&#xff1a;Linux具体目录结构 第二章&#xff1a;Linux常用命令 第一节&#xff1a;目录处理命令 2.1.1 命令格式 2.1.2 列出目录的内容&#xff1a;ls 命令 2.1.3 创建目录&#xff1a;mkdi…

Wlan——锐捷智分网络解决方案及其配置

目录 智分解决方案 一代智分解决方案 二代智分解决方案 三代智分解决方案 智分解决方案 技术原理 隧道建立 智分方案的配置 配置基础信息 配置微AP的无线信号 调整微AP的射频参数 宿舍场景特点&#xff1a;房间小&#xff0c;单个房间用户少&#xff0c;房间密集&am…

第 5 章 栈(1)(介绍,应用场景,入门)

5.1栈的一个实际需求 请输入一个表达式 计算式:[722-51-53-3] 点击计算【如下图】 请问: 计算机底层是如何运算得到结果的&#xff1f; 注意不是简单的把算式列出运算,因为我们看这个算式 7 * 2 * 2 - 5, 但是计算机怎么理解这个算式的(对计算机而言&#xff0c;它接收到的就…

用名字来杀,杀不死的进程

杀死进程 这是进程的名字 docker-prox pkill -f "docker-prox"查看是否杀死 netstat -tlnp | grep :7006

echarts 的dataZoom滑块两端文字被遮挡

问题&#xff1a; 期望&#xff1a; 解决方案&#xff1a; 1&#xff1a;调整宽度&#xff08;4版本的没有width属性&#xff09; 2. 参考&#xff1a;echarts图标设置dataZoom拖拽时间轴时自动调整两侧文字的位置_datazoom 位置_乌栖曲的博客-CSDN博客 设置文字的定位 cons…

RT-Thread内核学习

内核框架 内核是操作系统最基础也是最重要的部分&#xff0c;内核处于硬件层之上&#xff0c;内核部分包括内核库、实时内核实现。 内核库是为了保证内核能够独立运行的一套小型的类似C库的函数实现子集。这部分根据编译器不同自带C库的情况也会不同。 当使用GNU GCC编译器时&…

2023年高教社杯 国赛数学建模思路 - 复盘:光照强度计算的优化模型

文章目录 0 赛题思路1 问题要求2 假设约定3 符号约定4 建立模型5 模型求解6 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 问题要求 现在已知一个教室长为15米&#xff0c;宽为12米&…

基于旗鱼算法优化的BP神经网络(预测应用) - 附代码

基于旗鱼算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码 文章目录 基于旗鱼算法优化的BP神经网络&#xff08;预测应用&#xff09; - 附代码1.数据介绍2.旗鱼优化BP神经网络2.1 BP神经网络参数设置2.2 旗鱼算法应用 4.测试结果&#xff1a;5.Matlab代码 摘要…

pandas 将单元格是列表的DataFrame拆成多列

方法&#xff1a; pd.DataFrame(df[col].values.tolist()) 将单元格元素是列表的列拆成多列 如果要与原来的其他列合并 pd.concat([pd.DataFrame(df[col].values.tolist()), df[其他列]], axis1) 示例&#xff1a; points数组如下&#xff1a; 生成DataFrame如下 处理结…

S7-300 PLC 模拟量采集(从硬件组态到软件FC编写)

S7-300PLC属于退市产品,很多老的生产线仍然沿用,所以这篇博客我们一步步介绍如何从硬件组态到软件FC的编写,首先我们组态模拟量模块。 1、硬件组态 组态好硬件后,我们开始设计软件FC,模拟量采集往往都会有很多回路,下面我们介绍如何在STEP7中创建模拟量采集FC,S_ITR,有关…

mysql sql_mode数据验证检查

sql_mode 功能 sql_mode 会影响MySQL支持的sql语法以及执行的数据验证检查。通过设置sql_mode ,可以完成不同严格程度的数据校验&#xff0c;有效地保障数据准确性 sql_mode 严格模式 VS 宽松模式 宽松模式 比如&#xff0c;插入的数据不满足 表的数据类型&#xff0c;也可能…

国际象棋上放马--夏令营

题目 tips&#xff1a; 1、分类讨论&#xff0c;从最小的数1开始试&#xff0c;再逐一增大&#xff0c;这种会是有规律的 其次&#xff0c;既然要分类讨论就要比大小 2、输入m,n的同时&#xff0c;在m,n同为0时程序停止怎么写 while(scanf("")!EOF&&(m||…

微信小程序开发教学系列(1)- 开发入门

第一章&#xff1a;微信小程序简介与入门 1.1 简介 微信小程序是一种基于微信平台的应用程序&#xff0c;可以在微信内直接使用&#xff0c;无需下载和安装。它具有小巧、高效、便捷的特点&#xff0c;可以满足用户在微信中获取信息、使用服务的需求。 微信小程序采用前端技…

Docker常见配置实验

1、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。 1、拉取mysql5.6与owncloud的镜像 docker pull mysql:5.6 docker pull mysql:5.6 2、生成容器实例&#xff0c;构建个人网盘 docker run -d --name mydb1 --env MYSQL_ROOT_PASSWORD123456 mysql:5.6 docker …

mysql 开启远程连接(windows)

mysql版本&#xff1a;MySQL Server 5.7 1、开放防火墙端口 2、 配置 MySQL 服务的用户权限 打开 cmd 输入以下命令登录 mysql&#xff0c;接着输入密码&#xff0c;回车 mysql -u root -p 接着输入命令 use mysql; 查看mysql 数据库当前 root 用户的相关信息 select host,user…

打开软件报错mfc100u.dll缺失是什么意思?简单式修复mfc100u.dll问题

首先&#xff0c;我们需要了解什么是MFC100U.dll文件以及它的作用。MFC100U.dll是一个Microsoft Foundation Class (MFC)库文件&#xff0c;它是Visual C应用程序开发的一部分。MFC库提供了许多通用的功能&#xff0c;如窗口管理、消息处理等&#xff0c;可以帮助开发者更快速地…

C++信息学奥赛1137:加密的病历单

#include<bits/stdc.h> using namespace std; int main() {string arr;// 输入一行字符串getline(cin, arr);string btt;for(int iarr.length()-1;i>0;i--){char aarr[i]3; // 对当前字符进行加密&#xff0c;向后移动三位if(arr[i]>88 and arr[i]<90) { // 如果…

无代码之舞:当非开发者也成为创作者

无代码/低代码开发的崛起 定义与背景 无代码/低代码开发是指通过图形界面、拖放等简单操作&#xff0c;而不需要编写代码来创建应用程序的方法。这种方法的出现&#xff0c;使得非专业开发者也能轻松地创建和部署应用程序。在过去的几十年里&#xff0c;软件开发一直是一个复杂…

SpringBoot案例-基础登录功能

根据页面原型&#xff0c;明确需求 页面原型 需求 账号密码输入正确方可进入 阅读接口文档 接口文档连接如下&#xff1a; https://hkm-web.oss-cn-beijing.aliyuncs.com/%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3 思路分析 后端接收到前端传递的用户名及密码之后&#xf…