MyBatis基础增删改查

news2025/3/3 6:03:57

文章目录

  • MyBatis
    • 1. MyBatis是什么?
    • 2. 为什么要学习MyBatis
    • 3. 第一个MyBatis环境搭建
      • 1)添加MyBatis框架支持
      • 2)配置MyBatis相关配置文件
      • 3)添加代码
    • 4. 解决类的属性名和数据表字段名不一致(resultMap)
    • 5. 增加操作
      • 1)返回受影响的行数
      • 2)返回自增的id
    • 6. 修改操作
    • 7. 删除操作
    • 8. 参数赋值的两种方式
      • SQL注入问题
      • 安全的模糊查询(like)


MyBatis

1. MyBatis是什么?

MyBatis是一款数据持久层框架,它支持自定义SQL、存储过程(很少使用)以及高级映射,MyBatis去除了几乎所有的JDBC代码以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式Java对象)为数据库中的记录。

简单来说MyBatista是简单完成程序和数据交互的工具,就是是更简单的操作和读取数据库的工具。

2. 为什么要学习MyBatis

对于Java后端程序员来说,程序无非就是有两个部分构成的

  1. 程序
  2. 数据库

后端程序员无非就是进行数据库的CRUD。

而这两个重要的组成部分要进行通讯,就要依靠数据库连接工具,典型的就是JDBC,为什么有了JDBC还要去学习MyBatis这个框架呢?JDBC大概有这么几个流程:

  1. 去Maven仓库下载JDBC的jar包并导入
  2. 创建数据库,在代码里设置用户名和密码创建DataSource获取Connection连接
  3. 编写带占位符?的SQL语句
  4. 把占位符?替换成要操作的字段名并指定类型
  5. 通过connection获取Statement对象
  6. 通过Statement执行SQL获得ResultSet结果集或影响行数
  7. 处理结果集
  8. 释放资源

对于JDBC每操作一次数据库都要进行一次又一次的重复操作,建立连接、拼装SQL、执行SQL、处理结果集、最后还得释放资源。

为了解决这一系列的麻烦操作,就可以使用MyBatis来更简单的操作数据库。

3. 第一个MyBatis环境搭建

这是一个简单的框架交互流程图

在这里插入图片描述

  • Mapper就是我们所说的数据持久层
  • Inteface就是我们在类中写的接口,接口里的方法没有具体实现的,一个接口对应一张表。表里的方法对应一些操作
  • 在xml中是接口方法的实现,SQL的编写,xml是MyBatis提供的固定写法
  • 在程序运行的时候,MyBatis会将Inteface和xml合二为一,生成SQL调用JDBC
  • 再把结果从Mapper返回给Service层

MyBatis也是一个ORM框架,ORM(Object Relational Mapping),即对象关系映射。在面向对象的编程语言中,奖关系数据库中的数据对象建立起映射关系,进而自动的完成数据与对象的互相转换:

  1. 将输入数据(即传入对象)+ SQL映射成原生SQL
  2. 将结果集映射返回对象,即为输出对象

ORM把数据库映射为对象:

  • 数据库表(table)——>类(class)
  • 记录(record,行数据)——> 对象(Object)
  • 字段(field) ——> 对象的属性(attribute)

一般的ORM框架,会将数据库模型的每张表都映射为一个Java类。也就是说,使用MyBatis可以像操作对象一样来操作数据表,可以实现对象和数据库之间的转换。

1)添加MyBatis框架支持

老项目添加MyBatis

需要添加两个框架的引用

  1. MyBatis框架
  2. MySQL驱动

在这里插入图片描述

2)配置MyBatis相关配置文件

1.配置数据连接信息

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver #mysql 8.0之前的写法
    #driver-class-name=com.mysql.cj.jdbc.Driver 这是8.0之后的写法

2.MyBatis的XML文件位置

spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/blog_system?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver #mysql 8.0之前的写法
    #driver-class-name=com.mysql.cj.jdbc.Driver 这是8.0之后的写法
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

配置文件中的xml文件位置要和创建的文件夹名对应

在这里插入图片描述

3)添加代码

UserInfo对象

注意:这里的属性名要和数据库中的字段名对应

import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class UserInfo {
    private int userId;
    private String username;
    private String password;
}

在这里插入图片描述

UserMapper.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <select id="getAll" resultType="com.example.demo.model.UserInfo">
        select * from user
    </select>
</mapper>

在这里插入图片描述

控制器代码

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {

    @Autowired
    private UserService userService;

    @RequestMapping("/getAll")
    public List<UserInfo> getAll() {
        return userService.getAll();
    }
}

Service代码

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
    public List<UserInfo> getAll() {
        return userMapper.getAll();
    }
}

定义接口代码

@Mapper
public interface UserMapper {
    // 方法定义
    List<UserInfo> getAll();
}

通过浏览器访问

在这里插入图片描述

4. 解决类的属性名和数据表字段名不一致(resultMap)

实体类

@Getter
@Setter
public class UserInfo {
    private int id;
    private String name;
    private String password;
}

数据表

+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| userId   | int(11)     | NO   | PRI | NULL    | auto_increment |
| username | varchar(64) | YES  | UNI | NULL    |                |
| password | varchar(32) | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+

MyBatis配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <resultMap id="UserBean" type="com.example.demo.model.UserInfo">
        <!-- 映射主键的(表中主键和程序实体类中的主键) -->
        <id column="userId" property="id"></id>
        <!-- 普通列的映射 -->
        <result column="username" property="name"></result>
        <result column="password" property="password"></result>
    </resultMap>
    <select id="getAll" resultMap="UserBean">
        select * from user
    </select>
</mapper>

在这里插入图片描述

通过resultMap来解决类的属性名和数据表中字段名不一致的情况

  • id标签表示主键
  • result标签表示普通字段

MyBatis查询返回类型的设置

  1. resultType(返回结果类型)
  2. resultMap(返回映射)

resultTypeVSresultMap

  • 共同点:它们的功能是一样的,都是用来进行指定结果类型
  • 不同点:
    • resultType用法简单,但是如果实体类中的属性名和表中的字段名不一致那么结果将查询不出来
    • resultMap用法相对麻烦(resultMap接口多个列),但它可以实现属性名和数据表字段名不对应的映射,也能查询出结果

5. 增加操作

1)返回受影响的行数

Controller(控制器)代码:

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {

    @Autowired
    private UserService userService;

    public Integer addUser(UserInfo userInfo) {
        // 校验参数
        if (userInfo == null || userInfo.getName() == null || "".equals(userInfo.getName())
        || userInfo.getPassword() == null || "".equals(userInfo.getPassword())) {
            return 0;
        }

        return userService.addUser(userInfo);
    }
}

Service(服务层代码):

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;

    public int addUser(UserInfo userInfo) {
        // 服务(方法编排)
        return userMapper.addUser(userInfo);
    }
}

Mapper 接口代码:

@Mapper
public interface UserMapper {
    int addUser(UserInfo userInfo);
}

编写MyBatis的xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <!-- 添加方法 -->
    <insert id="addUser">
        insert into user(username,password) values(#{name},#{password})
    </insert>
</mapper>

通过postman测试

在这里插入图片描述

2)返回自增的id

Controller(控制器)代码:

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {
    @Autowired
    private UserService userService;

    @RequestMapping("/add2")
    public Integer addUser2(UserInfo userInfo) {
        // 校验参数
        if (userInfo == null || userInfo.getName() == null || "".equals(userInfo.getName())
                || userInfo.getPassword() == null || "".equals(userInfo.getPassword())) {
            return 0;
        }
        // 调用数据库执行添加操作,执行完添加之后会将自增id设置到userinfo的id属性
        userService.addUser2(userInfo);
        return userInfo.getId();
    }
}

Service(服务层代码):

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;

    public int addUser2(UserInfo userInfo) {
        // 服务(方法编排)
        return userMapper.addUser2(userInfo);
    }
}

Mapper接口:

@Mapper
public interface UserMapper {
    int addUser2(UserInfo userInfo);
}

编写MyBatis的xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">


    <!-- 添加方法(返回自增id) -->
    <insert id="addUser2" useGeneratedKeys="true" keyProperty="id" keyColumn="userId">
        insert into user(username, password) values(#{name},#{password})
    </insert>
</mapper>
  • useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据
    库内部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递
    增字段),默认值:false
  • keyColumn:设置⽣成键值在表中的列名,在某些数据库(像 PostgreSQL)中,当主键列
    不是表中的第⼀列的时候,是必须设置的。如果⽣成列不⽌⼀个,可以⽤逗号分隔多个属性
    名称
  • keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值
    或 insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)。如果⽣成列不⽌
    ⼀个,可以⽤逗号分隔多个属性名称

Postman测试结果

在这里插入图片描述

6. 修改操作

Controller(控制器代码)

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {

    @Autowired
    private UserService userService;
    /**
     * 修改密码操作
     * @param id
     * @param password
     * @return
     */
    @RequestMapping(value = "/update")
    public Integer updateUserInfo(Integer id, String password) {
        if(id == null || id < 0 || password == null || "".equals(password)) {
            return 0;
        }

        return userService.updateUserInfo(id,password);
    }
}

Service服务层代码:

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;

    public int updateUserInfo(Integer id, String password) {
        return userMapper.updateUserInfo(id,password);
    }
}

Mapper接口方法定义

@Mapper
public interface UserMapper {
    int updateUserInfo(Integer id, String password);
}

MyBatis配置文件实现接口

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">

    <!-- 更新操作 -->
    <update id="updateUserInfo">
        update user set password=#{password} where userId=#{id}
    </update>
</mapper>

7. 删除操作

Controller控制器代码:

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {

    @Autowired
    private UserService userService;

    @RequestMapping("/delete")
    public Integer deleteUser(Integer id) {
        if (id == null || id < 0) {
            return 0;
        }
        return userService.deleteUser(id);
    }
}

Service服务层代码

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;
    public int deleteUser(int id) {
        return userMapper.deleteUser(id);
    }
}

Mapper接口方法定义

@Mapper
public interface UserMapper {
    int deleteUser(int id);
}

MyBatisj配置文件接口实现

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
    <!-- 删除操作 -->
    <delete id="deleteUser">
        delete from user where userId=#{id}
    </delete>
</mapper>

8. 参数赋值的两种方式

  • #{}:预编译处理
  • ${}:字符直接替换

预编译处理是指:MyBatis在处理#{}时,会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值。直接替换:是MyBatis在处理${}时,就是直接把${}替换成变量的值了。

${}使用场景:

假设我们要对用户以id进行降序排序,变量order传递过来的是asc或者desc

@Mapper
public interface UserMapper {
    // 方法定义
    List<UserInfo> sortAllUser(String order);
}
<!-- ${}使用场景 -->
    <select id="sortAllUser" resultMap="UserBean">
        select * from user order by userId ${order}
    </select>

假设传递过来的是desc,如果使用${}的话,${order}就会被直接替换成 desc,正常排序返回结果。而如果使用#{}的话就会被替换成‘desc’,此时'desc'就是一个字符串了,那么执行SQL就会发生报错。

-- 使用${}
select * from user order by userId desc;
-- 使用#{}
select * from user order by userId 'desc';

${}是存存在SQL注入的问题的

SQL注入问题

假设要做一个简单的登录

Controller控制器代码

@Controller
@RequestMapping("/mybatis")
@ResponseBody
public class UserController2 {

    @Autowired
    private UserService userService;

    /**
     * 登录
     * @param username
     * @param password
     * @param request
     * @return
     */
    @RequestMapping("/login")
    public Object logIn(String username, String password, HttpServletRequest request) {
        Map<String,Object> result = new HashMap<>();
        result.put("status",200);// 响应状态码
        String message = null;
        int state = -1; // 登录状态码
        if (username != null && !"".equals(username) && password != null && !"".equals(password)) {
            UserInfo userInfo = userService.logIn(username,password);
            if (userInfo != null) {
                message = "登录成功";
                state = 1;
                // 把用户信息存储到session
                HttpSession session = request.getSession(true);
                session.setAttribute("userInfo",userInfo);
            } else {
                message = "用户名或密码错误";
            }
        } else {
            message = "用户名或密码错误";
        }
        result.put("message",message);
        result.put("state",state);

        return result;
    }
}

UserService服务层代码

@Service
public class UserService {
    @Resource
    private UserMapper userMapper;

    public UserInfo logIn(String username, String password) {
        return userMapper.logIn(username,password);
    }
}

Mapper接口映射

@Mapper
public interface UserMapper {
    // 方法定义
    List<UserInfo> getAll();
    UserInfo logIn(String username, String password);
}

实现接口的xml配置文件

 <!-- 登录用户查询 -->
    <select id="logIn" resultMap="UserBean">
        select * from user where username='${username}' and password='${password}'
    </select>

如果使用${}方式直接替换参数,就会有SQL注入的风险

Postman模拟请求

http://127.0.0.1:8080/mybatis/login?username=admin&password=' or userId='1''

在这里插入图片描述

无论输入任何密码都能登录成功,最后执行的SQL如下。也就是说通过SQL注入不需要知道密码就能登录,甚至执行删表操作。

mysql> select * from user where username='admin' and password='' or userId='1';

如果把${}替换成#{}就不会有SQL注入的问题

<select id="logIn" resultMap="UserBean">
        select * from user where username=#{username} and password=#{password}
    </select>

如果用#{}是 会将SQL中的#{}替换为?号,使用PreparedStatement的set方法来赋值。把整体看做是一个字符串。

使用刚才的SQL注入执行的SQL将会是如下

mysql> select * from user where username="admin" and password="' or userId='1";

所以,${}一定要慎用,如果非要使用就要将前端的参数进行安全过滤

安全的模糊查询(like)

ike 使⽤ #{} 报错

这是一个错误示例

<!-- 过滤查询 -->
    <select id="getLike" resultMap="UserBean">
        select username from user where username like '#{keyName}%';
    </select>

相当于执行的SQL是

select username from user where username like '"张"%';

这个是不能直接使⽤ ${},可以考虑使⽤ mysql 的内置函数 concat() 来处理,实现代码如下 :

<!-- 过滤查询 -->
    <select id="getLike" resultMap="UserBean">
        select username from user where username like concat(#{keyName},'%')
    </select>

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

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

相关文章

类和对象深入讲解(1)

目录 1.类和对象的初步认识 1.1面向过程和面向对象的区别 1.2类的引入 1.3内的定义 1.4类的访问限定符及封装 1.4.1访问限定符 1.4.2 封装 1.5类的作用域 1.6类对象模型 1.6.1如何计算类对象大小 1.类和对象的初步认识 1.1面向过程和面向对象的区别 C语言是面向过程的…

大模型混战,阿里百度华为谁将成就AI时代的“新地基”?

从算力基础到用户生态&#xff0c;群雄逐鹿大模型 自2022年stable diffusion模型的进步推动AIGC的快速发展后&#xff0c;年底&#xff0c;ChatGPT以“破圈者”的姿态&#xff0c;快速“吸粉”亿万&#xff0c;在全球范围内掀起了一股AI浪潮&#xff0c;也促使了众多海外巨头竞…

Golang每日一练(leetDay0030)

目录 88. 合并两个有序数组 Merge Sorted Array &#x1f31f; 89. 格雷编码 Gray Code &#x1f31f;&#x1f31f; 90. 子集 II Subsets II &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/…

为什么要创建FAQ?这篇文章告诉你

什么是FAQ 通过上述的引入大家应该也了解到了&#xff0c;FAQ是为了“解决问题”而存在的。FAQ是英文Frequently Asked Questions的缩写&#xff0c;中文意思就是“经常问到的问题”&#xff0c;或者更通俗地叫做“常见问题解答”。FAQ是当前网络上提供在线帮助的主要手段&…

小程序开发收费价目表

小程序作为一种新兴应用形式&#xff0c;正在逐渐成为企业和个人推广、运营的重要手段。然而&#xff0c;小程序开发的价格因项目规模和复杂程度差异较大&#xff0c;令不少人望而却步。本文将从小程序开发的相关因素入手&#xff0c;探讨小程序开发的价格范围和算法。 一、小…

【JLink仿真器】盗版检测、连接故障、检测不到芯片问题

【JLink仿真器】盗版检测、连接故障、检测不到芯片问题一、问题描述二、解决方法1、降低驱动&#xff08;解决非法问题以及连接故障&#xff09;2、SWD引脚被锁&#xff08;解决检测不到芯片&#xff09;三、说明一、问题描述 盗版检测&#xff1a;the connected probe appear…

【Linux】Mysql之索引的基本操作

一、为什么要使用索引 索引就是根据表中的一列或若干列按照一定顺序建立的列值与记录行之间的对应关系表&#xff0c;实质上是一张描述索引列的列值与原表中记录行之间一 一对应关系的有序表。 索引是 MySQL 中十分重要的数据库对象&#xff0c;是数据库性能调优技术的基础&…

GraphCL方法介绍(Graph Contrastive Learning with Augmentations)

论文链接&#xff1a;https://arxiv.org/pdf/2010.13902.pdf 附录链接&#xff1a;https://yyou1996.github.io/files/neurips2020_graphcl_supplement.pdf 代码链接&#xff1a;https://github.com/Shen-Lab/GraphCL 1 图的数据增强 我们专注于图级扩充。给定 M 个图的数…

【分布式】熔断、降级傻傻分不清楚-熔断和降级的真实关系

文章目录前言降级熔断什么是服务熔断熔断和降级的关系降级方式1、熔断降级&#xff08;不可用&#xff09;2、超时降级3、限流降级总结前言 刚开始我以为熔断和降级是一体的&#xff0c;以为他们必须配合使用&#xff1b; 只不过名字不一样而已&#xff0c;但是当我经过思考过…

[架构之路-164]-《软考-系统分析师》-3-操作系统基本原理-文件系统(文件的逻辑组织、文件的物理组织、硬盘空间管理、分布式文件系统)

目录 3 . 4 文件系统 3.4.1文件的组织结构 1 . 逻辑结构 2 . 物理结构 3 . 树形文件结构 3.4.2 硬盘存储空间管理 1 . 空闲文件目录 2 . 空闲块链 3 . 位示图法 4 . 成组链接法 3.4.3分布式文件系统 1. D F S 的特点 2. DFS 的组成 3. DFS 的架构 3 . 4 文件系统…

腾讯云服务器TencentOS系统安装宝塔Linux面板命令

腾讯云服务器TencentOS Server操作系统安装宝塔Linux面板命令选择CentOS安装脚本即可&#xff0c;TencentOS用户态环境与CentOS保持兼容&#xff0c;在CentOS上开发的应用程序可直接在TencentOS Server上运行。腾讯云百科分享腾讯云服务器TencentOS操作系统安装宝塔Linux面板命…

客户端ack模块的实现

文章目录背景第一版设计第二版设计第三、四版设计写在最后背景 所谓客户端ack模块是在我们推送服务中一个技术需求&#xff0c;本文主要介绍其迭代过程。 首先简单介绍下推送服务的架构&#xff0c;如下图。用户请求ws服务&#xff0c;建立ws长连接&#xff0c;并通过login和…

类和对象(C++11)

目录 一、类的定义 1.定义与声明放一起 2.定义与声明分开 二、类的访问限定符及封装 1.类的访问限定符 2.类的封装 三、类的实例化 四、类对象 1.类对象的存储方式 2.计算类对象的大小 面试题 1.结构体怎么对齐&#xff1f; 为什么要进行内存对齐&#xff1f; 2.如…

Python数据结构与算法-树

一、树的概念详情见 https://blog.csdn.net/little_limin/article/details/129845592 Python数据结构与算法-堆排序&#xff08;NB组&#xff09;—— 一、树的基础知识二、树的实例&#xff1a;模拟文件系统1、树的存储树结构也是链式存储的&#xff0c;与链表的结构相似&…

java通过URLClassLoader类加载器加载外部jar

相信在实际工作中&#xff0c;大家可能会遇到这种需求&#xff0c;这个jar是外部的&#xff0c;并没有添加到项目依赖中&#xff0c;只能通过类加载器加载并调用相关方法。 这种jar加载&#xff0c;其实也简单&#xff0c;我们通过普通的URLClassLoader就可以加载。代码如下所示…

netfilter filter表

iptables是linux下常用的一个防火墙软件&#xff0c;可以实现对网络访问的各种限制。iptables相当于防火墙的客户端&#xff0c;与用户进行交换&#xff0c;其后台依赖于内核的netfilter模块。iptables的各种配置&#xff0c;最终都是netfilter模块来实现的。 iptables分为4个…

Python-DQN代码阅读(12)

目录 1.代码 1.1代码解读 1.2 代码分解 1.2.1 latest_checkpoint tf.train.latest_checkpoint(checkpoint_dir) 1.2.2 saver.restore(sess, latest_checkpoint) 1.2.3 sess.run(tf.global_variables_initializer()) 1.2.4 deep_q_learning() 1.3 输出结果 1.4 问题 1…

v-for比v-if优先级更高?

前言 v-if和v-for哪个优先级更高呢&#xff1f;这是面试官常常问到的一个问题&#xff0c;如果是在三年前&#xff0c;我会毫不犹豫的回答当然是v-for哩&#xff0c;但在3202的今天&#xff0c;如果还这么答&#xff0c;显然是低估了前端技术的日新月异啰。下面我们就来结合编…

第十四届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组 E 题

颜色平衡树问题描述格式输入格式输出样例输入样例输出评测用例规模与约定解析参考程序问题描述 格式输入 输入的第一行包含一个整数 n &#xff0c;表示树的结点数。 接下来 n 行&#xff0c;每行包含两个整数 Ci , Fi&#xff0c;用一个空格分隔&#xff0c;表示第 i 个结点 …