jdbc(DriverManager+Connection+Statement+ResultSet)+SQL注入+开启预编译+数据连接池

news2024/11/16 8:49:16

1 JDBC概念

JDBC 就是使用Java连接并操作数据库的一套API

全称:( Java DataBase Connectivity ) Java 数据库连接

2 JDBC优势

可随时替换底层数据库,访问数据库的Java代码基本不变

以后编写操作数据库的代码只需要面向JDBC(接口),操作哪儿个关系型数据库就需要导入该数据库的驱动包,如需要操作MySQL数据库,就需要再项目中导入MySQL数据库的驱动包。

3 JDBC快速入门

第一步:编写Java代码
第二步:Java代码将SQL发送到MySQL服务端
第三步:MySQL服务端接收到SQL语句并执行该SQL语句
第四步:将SQL语句执行的结果返回给Java代码

3.1 编写代码步骤

  • 创建工程,导入驱动jar包
    将mysql的驱动包放在模块下的lib目录(随意命名)下,并将该jar包添加为库文件
    在这里插入图片描述

在这里插入图片描述

  • 在添加为库文件的时候,有如下三个选项

    • Global Library : 全局有效
    • Project Library : 项目有效
    • Module Library : 模块有效

      一般选择全局有效

  • 注册驱动

    Class.forName("com.mysql.jdbc.Driver");
    
  • 获取连接
    Java代码需要发送SQL给MySQL服务端,就需要先建立连接

    Connection conn = DriverManager.getConnection(url, username, password);
    
  • 定义SQL语句

    String sql =update…” ;
    
  • 获取执行SQL对象

    执行SQL语句需要SQL执行对象,而这个执行对象就是Statement对象

    Statement stmt = conn.createStatement();
    
  • 执行SQL

    stmt.executeUpdate(sql);  
    
  • 处理返回结果

  • 释放资源

3.2 完整代码

/**
 * JDBC快速入门
 */
public class JDBCDemo {

    public static void main(String[] args) throws Exception {
        //1. 注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接
        String url = "jdbc:mysql://127.0.0.1:3306/db1";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3. 定义sql
        String sql = "update account set money = 2000 where id = 1";
        //4. 获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();
        //5. 执行sql
        int count = stmt.executeUpdate(sql);//受影响的行数
        //6. 处理结果
        System.out.println(count);
        //7. 释放资源
        stmt.close();
        conn.close();
    }
}

3 DriverManager

DriverManager(驱动管理类)用于

  • 注册驱动

    但MySQL 5之后的驱动包,可以省略注册驱动的步骤

  • 获取数据库连接

    语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…

    示例:jdbc:mysql://127.0.0.1:3306/db1

    细节:

    • 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对

    • 配置 useSSL=false 参数,禁用安全连接方式,解决警告提示

4 Connection

Connection(数据库连接对象)作用:

  • 获取执行 SQL 的对象
  • 管理事务

4.1 获取执行对象

  • 普通执行SQL对象

    Statement createStatement()
    

    入门案例中就是通过该方法获取的执行对象。

  • 预编译SQL的执行SQL对象:防止SQL注入

    PreparedStatement  prepareStatement(sql)
    

    通过这种方式获取的 PreparedStatement SQL语句执行对象可以防止SQL注入。

4.2 事务管理

先回顾一下MySQL事务管理的操作:

  • 开启事务 : BEGIN; 或者 START TRANSACTION;
  • 提交事务 : COMMIT;
  • 回滚事务 : ROLLBACK;

MySQL默认是自动提交事务

接下来学习JDBC事务管理的方法。

Connection几口中定义了3个对应的方法:

  • 开启事务
    参与autoCommit 表示是否自动提交事务,true表示自动提交事务,false表示手动提交事务。而开启事务需要将该参数设为为false。
  • 提交事务
  • 回滚事务
    具体代码实现如下:
/**
 * JDBC API 详解:Connection
 */
public class JDBCDemo3_Connection {

    public static void main(String[] args) throws Exception {
        //1. 注册驱动
        //Class.forName("com.mysql.jdbc.Driver");
        //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
        String url = "jdbc:mysql:///db1?useSSL=false";
        String username = "root";
        String password = "1234";
        Connection conn = DriverManager.getConnection(url, username, password);
        //3. 定义sql
        String sql1 = "update account set money = 3000 where id = 1";
        String sql2 = "update account set money = 3000 where id = 2";
        //4. 获取执行sql的对象 Statement
        Statement stmt = conn.createStatement();

        try {
            // ============开启事务==========
            conn.setAutoCommit(false);
            //5. 执行sql
            int count1 = stmt.executeUpdate(sql1);//受影响的行数
            //6. 处理结果
            System.out.println(count1);
            int i = 3/0;
            //5. 执行sql
            int count2 = stmt.executeUpdate(sql2);//受影响的行数
            //6. 处理结果
            System.out.println(count2);

            // ============提交事务==========
            //程序运行到此处,说明没有出现任何问题,则需求提交事务
            conn.commit();
        } catch (Exception e) {
            // ============回滚事务==========
            //程序在出现异常时会执行到这个地方,此时就需要回滚事务
            conn.rollback();
            e.printStackTrace();
        }

        //7. 释放资源
        stmt.close();
        conn.close();
    }
}

5 Statement

Statement对象的作用就是用来执行SQL语句。而针对不同类型的SQL语句使用的方法也不一样。

/**
  * 执行DML语句
  * @throws Exception
  */
@Test
public void testDML() throws  Exception {
    //1. 注册驱动
    //Class.forName("com.mysql.jdbc.Driver");
    //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
    String url = "jdbc:mysql:///db1?useSSL=false";
    String username = "root";
    String password = "1234";
    Connection conn = DriverManager.getConnection(url, username, password);
    //3. 定义sql
    String sql = "update account set money = 3000 where id = 1";
    //4. 获取执行sql的对象 Statement
    Statement stmt = conn.createStatement();
    //5. 执行sql
    int count = stmt.executeUpdate(sql);//执行完DML语句,受影响的行数
    //6. 处理结果
    //System.out.println(count);
    if(count > 0){
        System.out.println("修改成功~");
    }else{
        System.out.println("修改失败~");
    }
    //7. 释放资源
    stmt.close();
    conn.close();
}

6 ResultSet

6.1 概述

ResultSet(结果集对象)是用来封装SQL查询语句的结果。

而执行了DQL语句后就会返回该对象,对应执行DQL语句的方法如下:

ResultSet  executeQuery(sql):执行DQL 语句,返回 ResultSet 对象

那么我们就需要从 ResultSet 对象中获取我们想要的数据。ResultSet 对象提供了操作查询结果数据的方法,如下:

boolean next()

  • 将光标从当前位置向前移动一行
  • 判断当前行是否为有效行

6.2 代码实现

/**
  * 执行DQL
  * @throws Exception
  */
@Test
public void testResultSet() throws  Exception {
    //1. 注册驱动
    //Class.forName("com.mysql.jdbc.Driver");
    //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
    String url = "jdbc:mysql:///db1?useSSL=false";
    String username = "root";
    String password = "1234";
    Connection conn = DriverManager.getConnection(url, username, password);
    //3. 定义sql
    String sql = "select * from account";
    //4. 获取statement对象
    Statement stmt = conn.createStatement();
    //5. 执行sql
    ResultSet rs = stmt.executeQuery(sql);
    //6. 处理结果, 遍历rs中的所有数据
    // 6.1 光标向下移动一行,并且判断当前行是否有数据
    while (rs.next()){
        //6.2 获取数据  getXxx()
        int id = rs.getInt("id");
        String name = rs.getString("name");
        double money = rs.getDouble("money");

        System.out.println(id);
        System.out.println(name);
        System.out.println(money);

        System.out.println("--------------");
    }

    //7. 释放资源
    rs.close();
    stmt.close();
    conn.close();
}

7 SQL注入

SQL注入是通过操作输入来修改事先定义好的SQL语句,用以达到执行代码对服务器进行攻击的方法。

代码模拟

select * from tb_user where username = 'sjdljfld' and password = ''or '1' = '1'

从上面语句可以看出条件 username = 'sjdljfld' and password = '' 不管是否满足,而 or 后面的 '1' = '1' 是始终满足的,最终条件是成立的,就可以正常的进行登陆了。

7.1 PreparedStatement简介

PreparedStatement作用: 预编译SQL语句并执行:预防SQL注入问题。

  • 获取 PreparedStatement 对象

    // SQL语句中的参数值,使用?占位符替代
    String sql = "select * from user where username = ? and password = ?";
    // 通过Connection对象获取,并传入对应的sql语句
    PreparedStatement pstmt = conn.prepareStatement(sql);
    
  • 设置参数值

  • 执行SQL语句

    executeUpdate(); 执行DDL语句和DML语句

    executeQuery(); 执行DQL语句

    注意:

    • 调用这两个方法时不需要传递SQL语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了。

7.2 使用PreparedStatement改进sql注入

 @Test
public void testPreparedStatement() throws  Exception {
    //2. 获取连接:如果连接的是本机mysql并且端口是默认的 3306 可以简化书写
    String url = "jdbc:mysql:///db1?useSSL=false";
    String username = "root";
    String password = "1234";
    Connection conn = DriverManager.getConnection(url, username, password);

    // 接收用户输入 用户名和密码
    String name = "zhangsan";
    String pwd = "' or '1' = '1";

    // 定义sql
    String sql = "select * from tb_user where username = ? and password = ?";
    // 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    // 设置?的值
    pstmt.setString(1,name);
    pstmt.setString(2,pwd);
    // 执行sql
    ResultSet rs = pstmt.executeQuery();
    // 判断登录是否成功
    if(rs.next()){
        System.out.println("登录成功~");
    }else{
        System.out.println("登录失败~");
    }
    //7. 释放资源
    rs.close();
    pstmt.close();
    conn.close();
}

执行上面语句就可以发现不会出现SQL注入漏洞问题了。那么PreparedStatement又是如何解决的呢?它是将特殊字符进行了转义,转义的SQL如下:

select * from tb_user where username = 'sjdljfld' and password = '\'or \'1\' = \'1'

8 开启预编译

数据库检查SQL和编译SQL花费的时间比执行SQL的时间还要长。如果我们只是重新设置参数,那么检查SQL语句和编译SQL语句将不需要重复执行。这样就提高了性能。
  • 开启预编译功能

    在代码中编写url时需要加上以下参数。而我们之前根本就没有开启预编译功能,只是解决了SQL注入漏洞。

    useServerPrepStmts=true
    
  • 配置MySQL执行日志(重启mysql服务后生效)

    在mysql配置文件(my.ini)中添加如下配置

    log-output=FILE
    general-log=1
    general_log_file="D:\mysql.log"
    slow-query-log=1
    slow_query_log_file="D:\mysql_slow.log"
    long_query_time=2
    

9 数据库连接池

9.1 简介

  • 数据库连接池是个容器,负责分配、管理数据库连接(Connection)

  • 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;

  • 释放超过最大空闲时间的数据库连接来避免数据库连接遗漏

  • 好处

    • 资源重用
    • 提升系统响应速度
    • 避免数据库连接遗漏

之前我们代码中使用连接是没有使用都创建一个Connection对象,使用完毕就会将其销毁。这样重复创建销毁的过程性能很低。
而使用数据库连接池能达到Connection对象的复用.

9.2 实现

  • 标准接口:DataSource

    Connection getConnection()
    

    以后就不需要通过 DriverManager 对象获取 Connection 对象,而是通过连接池(DataSource)获取 Connection 对象。

  • 常见的数据库连接池

    • DBCP
    • C3P0
    • Druid

    我们现在使用更多的是Druid(阿里巴巴开源),它的性能比其他两个会好一些。

9.3 Driud使用

  • 导入jar包 druid-1.1.12.jar
  • 定义配置文件
  • 加载配置文件
  • 获取数据库连接池对象
  • 获取连接

现在通过代码实现,首先需要先将druid的jar包放到项目下的lib下并添加为库文件。编写配置文件如下:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db1?useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000

使用druid的代码如下:

/**
 * Druid数据库连接池演示
 */
public class DruidDemo {

    public static void main(String[] args) throws Exception {
        //1.导入jar包
        //2.定义配置文件
        //3. 加载配置文件
        Properties prop = new Properties();
        prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
        //4. 获取连接池对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //5. 获取数据库连接 Connection
        Connection connection = dataSource.getConnection();
        System.out.println(connection); //获取到了连接后就可以继续做其他操作了

        //System.out.println(System.getProperty("user.dir"));
    }
}

10 案例实现

完成商品品牌数据的增删改查操作

  • 查询:查询所有数据
  • 添加:添加品牌
  • 修改:根据id修改
  • 删除:根据id删除

9.1 环境准备

  • 数据库表 tb_brand

    -- 删除tb_brand表
    drop table if exists tb_brand;
    -- 创建tb_brand表
    create table tb_brand (
        -- id 主键
        id int primary key auto_increment,
        -- 品牌名称
        brand_name varchar(20),
        -- 企业名称
        company_name varchar(20),
        -- 排序字段
        ordered int,
        -- 描述信息
        description varchar(100),
        -- 状态:0:禁用  1:启用
        status int
    );
    -- 添加数据
    insert into tb_brand (brand_name, company_name, ordered, description, status)
    values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
           ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
           ('小米', '小米科技有限公司', 50, 'are you ok', 1);
    
  • 在pojo包下实体类 Brand

    /**
     * 品牌
     * alt + 鼠标左键:整列编辑
     * 在实体类中,基本数据类型建议使用其对应的包装类型
     */
    public class Brand {
        // id 主键
        private Integer id;
        // 品牌名称
        private String brandName;
        // 企业名称
        private String companyName;
        // 排序字段
        private Integer ordered;
        // 描述信息
        private String description;
        // 状态:0:禁用  1:启用
        private Integer status;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getBrandName() {
            return brandName;
        }
    
        public void setBrandName(String brandName) {
            this.brandName = brandName;
        }
    
        public String getCompanyName() {
            return companyName;
        }
    
        public void setCompanyName(String companyName) {
            this.companyName = companyName;
        }
    
        public Integer getOrdered() {
            return ordered;
        }
    
        public void setOrdered(Integer ordered) {
            this.ordered = ordered;
        }
    
        public String getDescription() {
            return description;
        }
    
        public void setDescription(String description) {
            this.description = description;
        }
    
        public Integer getStatus() {
            return status;
        }
    
        public void setStatus(Integer status) {
            this.status = status;
        }
    
        @Override
        public String toString() {
            return "Brand{" +
                    "id=" + id +
                    ", brandName='" + brandName + '\'' +
                    ", companyName='" + companyName + '\'' +
                    ", ordered=" + ordered +
                    ", description='" + description + '\'' +
                    ", status=" + status +
                    '}';
        }
    }
    
5.2.2 查询所有
 /**
   * 查询所有
   * 1. SQL:select * from tb_brand;
   * 2. 参数:不需要
   * 3. 结果:List<Brand>
   */

@Test
public void testSelectAll() throws Exception {
    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = "select * from tb_brand;";
    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //4. 设置参数
    //5. 执行SQL
    ResultSet rs = pstmt.executeQuery();
    //6. 处理结果 List<Brand> 封装Brand对象,装载List集合
    Brand brand = null;
    List<Brand> brands = new ArrayList<>();
    while (rs.next()){
        //获取数据
        int id = rs.getInt("id");
        String brandName = rs.getString("brand_name");
        String companyName = rs.getString("company_name");
        int ordered = rs.getInt("ordered");
        String description = rs.getString("description");
        int status = rs.getInt("status");
        //封装Brand对象
        brand = new Brand();
        brand.setId(id);
        brand.setBrandName(brandName);
        brand.setCompanyName(companyName);
        brand.setOrdered(ordered);
        brand.setDescription(description);
        brand.setStatus(status);

        //装载集合
        brands.add(brand);
    }
    System.out.println(brands);
    //7. 释放资源
    rs.close();
    pstmt.close();
    conn.close();
}
5.2.3 添加数据
/**
  * 添加
  * 1. SQL:insert into tb_brand(brand_name, company_name, ordered, description, status) values(?,?,?,?,?);
  * 2. 参数:需要,除了id之外的所有参数信息
  * 3. 结果:boolean
  */
@Test
public void testAdd() throws Exception {
    // 接收页面提交的参数
    String brandName = "香飘飘";
    String companyName = "香飘飘";
    int ordered = 1;
    String description = "绕地球一圈";
    int status = 1;

    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = "insert into tb_brand(brand_name, company_name, ordered, description, status) values(?,?,?,?,?);";
    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //4. 设置参数
    pstmt.setString(1,brandName);
    pstmt.setString(2,companyName);
    pstmt.setInt(3,ordered);
    pstmt.setString(4,description);
    pstmt.setInt(5,status);

    //5. 执行SQL
    int count = pstmt.executeUpdate(); // 影响的行数
    //6. 处理结果
    System.out.println(count > 0);

    //7. 释放资源
    pstmt.close();
    conn.close();
}
5.2.4 修改数据
/**
  * 修改
  * 1. SQL:

     update tb_brand
         set brand_name  = ?,
         company_name= ?,
         ordered     = ?,
         description = ?,
         status      = ?
     where id = ?

   * 2. 参数:需要,所有数据
   * 3. 结果:boolean
   */

@Test
public void testUpdate() throws Exception {
    // 接收页面提交的参数
    String brandName = "香飘飘";
    String companyName = "香飘飘";
    int ordered = 1000;
    String description = "绕地球三圈";
    int status = 1;
    int id = 4;

    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = " update tb_brand\n" +
        "         set brand_name  = ?,\n" +
        "         company_name= ?,\n" +
        "         ordered     = ?,\n" +
        "         description = ?,\n" +
        "         status      = ?\n" +
        "     where id = ?";

    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);

    //4. 设置参数
    pstmt.setString(1,brandName);
    pstmt.setString(2,companyName);
    pstmt.setInt(3,ordered);
    pstmt.setString(4,description);
    pstmt.setInt(5,status);
    pstmt.setInt(6,id);

    //5. 执行SQL
    int count = pstmt.executeUpdate(); // 影响的行数
    //6. 处理结果
    System.out.println(count > 0);

    //7. 释放资源
    pstmt.close();
    conn.close();
}
5.2.5 删除数据
/**
  * 删除
  * 1. SQL:
            delete from tb_brand where id = ?
  * 2. 参数:需要,id
  * 3. 结果:boolean
  */
@Test
public void testDeleteById() throws Exception {
    // 接收页面提交的参数
    int id = 4;
    //1. 获取Connection
    //3. 加载配置文件
    Properties prop = new Properties();
    prop.load(new FileInputStream("jdbc-demo/src/druid.properties"));
    //4. 获取连接池对象
    DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
    //5. 获取数据库连接 Connection
    Connection conn = dataSource.getConnection();
    //2. 定义SQL
    String sql = " delete from tb_brand where id = ?";
    //3. 获取pstmt对象
    PreparedStatement pstmt = conn.prepareStatement(sql);
    //4. 设置参数
    pstmt.setInt(1,id);
    //5. 执行SQL
    int count = pstmt.executeUpdate(); // 影响的行数
    //6. 处理结果
    System.out.println(count > 0);

    //7. 释放资源
    pstmt.close();
    conn.close();
}

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

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

相关文章

裸辞18K外包,面试阿里、字节全都一面挂,哭死.....

测试员可以先在外包积累经验&#xff0c;以后去大厂就很容易&#xff0c;基本不会被卡&#xff0c;事实果真如此吗&#xff1f;但是在我身上却是给了我很大一巴掌... 所谓今年今天履历只是不卡简历而已&#xff0c;如果面试答得稀烂&#xff0c;人家根本不会要你。况且要不是大…

[软件工具]ARW文件批量转图片jpg工具使用教程

当你有一批后缀为.ARW格式图像文件怎么转jpg呢&#xff0c;我们可以使用这个工具进行转换首先我们打开软件 然后我们直接导入文件夹&#xff0c;点击开始转换等待转换完成即可。详细视频教程参看&#xff1a; ARW文件批量转图片jpg png bmp工具使用教程_哔哩哔哩_bilibili这个…

自动化测试基础篇:Selenium 框架设计(POM)

【导语】Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作一样。本文介绍selenium的框架设计。 自动化测试框架 1.什么是自动化测试框架 简单来说&#xff0c;自动化测试框架就是由一些标准&#xff0c;协议&…

Vue-2.1scoped样式冲突

默认情况&#xff1a;写在组件中的样式会全局生效->因此很容易造成多个组件之间的样式冲突问题 1.全局样式&#xff1a;默认组件中的样式会作用到全局 2.局部样式&#xff1a;可以给组件加上scoped属性&#xff0c;可以让样式只作用于当前组件 <style scoped> <…

长沙建筑模板生产厂家有哪些?

在湖南长沙地区&#xff0c;建筑施工企业寻找一家可信赖的建筑模板供应商是非常重要的。在长沙地区&#xff0c;有多家建筑模板生产厂家&#xff0c;其中值得一提的是能强优品木业&#xff0c;他们是长沙地区建筑模板生产的领先供应商之一。 能强优品木业位于广西贵港市&#x…

Leetcode: 63. 不同路径 II(动态规划)

1. 题目解析 LeetCode链接 根据题目可以得出&#xff0c;当处于 [i][j] 位置时只能从 [i][j - 1], 和 [i - 1][j] 到达&#xff0c;所以我们只需要将到达上述两点的路径相加就可以得到到达该点的路径和 2. 解题思路 通过分析题目我们可以使用动态规划来解决这道题 首先我们…

【计算机网络笔记】什么是计算机网络?

前言计算机网络的定义交换网络什么是Internet从组成细节角度看从服务角度看 最后感谢 &#x1f496; 本篇文章总字数&#xff1a;1342字 预计阅读时间&#xff1a;5~10min 建议收藏之后慢慢阅读 前言 计算机网络通信技术计算机技术。 计算机网络是通信技术与计算机技术紧密结…

求后缀表达式的值

后缀表达式的值 【题目描述】 从键盘读入一个后缀表达式&#xff08;字符串&#xff09;&#xff0c;只含有0-9组成的运算数及加&#xff08;&#xff09;、减&#xff08;—&#xff09;、乘&#xff08;*&#xff09;、除&#xff08;/&#xff09;四种运算符。每个运算数之间…

面试题____Java小白找工作必须领悟的修仙秘籍(二)

当我们走出校园&#xff0c;步入社会&#xff0c;必须得找工作&#xff0c;那么作为it小白你必须拥有过硬的基础应用知识&#xff0c;才能慢慢的适应工作的节奏&#xff0c;以下内容则都是基础中的基础&#xff0c;需要全部进行掌握&#xff0c;因为这里可能有你面试时需要回答…

故障注入常用方法有哪些 其重要性是什么

故障注入是一种有效的测试方法&#xff0c;可用于评估系统对异常情况的响应。通过这种测试方法&#xff0c;可以发现系统中的潜在问题&#xff0c;并采取适当措施来改进系统的质量和性能。本文将介绍故障注入常用方法及重要性! 一、故障注入常用方法 1、随机故障注入&#xff1…

交易履约之结算平台实践 | 京东云技术团队

导读 京东科技业务在快速发展的同时&#xff0c;产生了众多线上化资金结算的需求。传统的线下资金结算模式有着人力成本高、耗时长、多方沟通协调成本高、结算准确率低等固有缺点&#xff0c;且无法满足“风法财审”对于资金流程的管控要求&#xff0c;在此背景下金道结算平台…

springboot就业信息管理系统springboot32

大家好✌&#xff01;我是CZ淡陌。一名专注以理论为基础实战为主的技术博主&#xff0c;将再这里为大家分享优质的实战项目&#xff0c;本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#xff0c;希望你能有所收获&#xff0c;少走一些弯路…

[UUCTF 2022 新生赛]ezpop - 反序列化(字符串逃逸)【***】

[UUCTF 2022 新生赛]ezpop 一、解题过程二、其他WP三、总结反思 一、解题过程 题目代码&#xff1a; <?php //flag in flag.php error_reporting(0); class UUCTF{public $name,$key,$basedata,$ob;function __construct($str){$this->name$str;}function __wakeup(){i…

成集云 | 嗨便利集成金蝶云星辰 | 解决方案

方案介绍 嗨便利是一款便捷即时到家服务平台。它集合了即时零售、即时配送、前置仓、数字化中台、会员体系以及自研SAAS系统等众多前沿科技&#xff0c;利用大数据驱动的预测算法&#xff0c;通过多渠道订单整合&#xff0c;智能调度配送系统&#xff0c;致力于为消费者提供“…

互联网干洗店洗鞋店预约收衣下单软件

拽牛科技洗护软件系统可以实现用户在线下单&#xff0c;商家依托平台来接单&#xff0c;将用户的订单运送到校外来清洗处理&#xff0c;这样可以有效的避免学校的高房租成本。 软件有四种下单模式&#xff0c;网点自取模式&#xff5c;上门取送模式&#xff5c;快递柜模式&…

实验室管理系统LIMS

在数字化浪潮中&#xff0c;越来越多的企业开始有数字化转型的意识。对于实验室而言&#xff0c;数字化转型是指运用新一代数字技术&#xff0c;促进实验室业务、生产、研发、管理、服务、供应链等方面的转型与升级&#xff0c;实现实验室业务“人、机、料、法、环”的多维度发…

【使用 TensorFlow 2】02/3 使用 Lambda 层创建自定义激活函数

一、说明 TensorFlow 2发布已经接近2年时间&#xff0c;不仅继承了Keras快速上手和易于使用的特性&#xff0c;同时还扩展了原有Keras所不支持的分布式训练的特性。3大设计原则&#xff1a;简化概念&#xff0c;海纳百川&#xff0c;构建生态.这是本系列的第三部分&#xff0c;…

【pycharm】控制台报错:终端无法加载文件\venv\Scripts\activate.ps1

目录 一、在pycharm控制台输入 二、在windows的power shell &#xff08;以管理员方式打开&#xff09; 三、 在pycharm控制台输入 四、重新打开pycharm即可 前言&#xff1a;安装pycharm2022-03版本出现的终端打开报错 一、在pycharm控制台输入 get-executionpolicy …

单目标分割标签图叠加代码

本代码只适合两个图片合并&#xff0c;如果出现三个图片合并&#xff0c;就将第三个图删除&#xff0c;先合并一次&#xff0c;然后再将图片加入&#xff0c;再合并一次 1. 问题背景 有的时候标签有多个&#xff0c;需要将两张或者是多张图象叠加在一起&#xff0c;成为以下情…