【示例】Mybatis-标签学习+Mybatis工作流程

news2025/2/28 13:03:49

前言

本文主要学习Mybatis相关标签的使用及Mybatis的工作流程。

文中用到的示例,代码存储位置:

GitHubhttps://github.com/Web-Learn-GSF/Java_Learn_Examples
父工程Java_Framework_Mybatis

基础

示例 | 初始Mybatis

数据库初始化

-- 建表
CREATE TABLE `user`(
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

-- 插入语句
INSERT INTO `user`(`id`, `name`, `pwd`) VALUES
(1, "狂神", "123456"),
(2, "张三", "1234567"),
(3, "李四", "1234568")

项目目录及内容

image-20240410224334133

UserDaoDao接口,提供获取数据库数据的接口方法
UserMapper.xmlDao接口对应的配置文件,每个接口方法都有对应的具体SQL语句
User数据库对象
MybatisUtils每次连接数据库之前,都需要通过sqlSessionFactory来获取sqlSession对象,从而进行后续的数据库连接、sql执行、关闭操作
可以理解为:获取Dao接口的代理类对象,已经对接口方法进行增强,能运行相应的SQL语句及返回查询结果
mybatis-config.xmlmybatis的配置文件,用于定义数据库的配置连接、Mapper的注册(将Dao接口与对应的xml文件相关联)
UserTest测试文件

常见问题汇总

  • Dao层Mapper.xml配置文件没有在mybatis-config.xml中注册

  • maven导出资源问题:资源不放在resources文件夹下,正常情况下没法输出到target文件夹中。通过配置资源导出的目录解决该问题。

    通过设置:src/main/resources和src/main/java目录下的所有.xml文件和.properties文件,都会被识别为资源,从而在构建的时候输出到target目录

<!-- 在项目的pom.xml文件中加入此配置 -->

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
        </resource>
    </resources>
</build>

示例 | 上述示例完善

调整后的目录结构

image-20240410230204659

log存放日志的文件夹
db.properties将数据库连接配置放在该配置文件中,提供一个key-value的访问结构,在mybatis-config.xml中导入后,可以通过变量标识符${}替换相应的连接对象
log4j.propertiesMaven导入日志依赖、mybatis-config.xml中开启日志,log4j.properties配置文件配置日志细节(名字是默认的,放在resources目录下就能访问到;不同的日志实现,配置文件的默认名字也不一样)

相关改动细节

  • 通过db.properties配置数据库连接,不再需要转义符了

  • mybatis-config.xml

    • 配置多套数据库环境
    • 映射Mapper的三种方式
  • UserDao.xml:resultMap标签解决数据库字段与poji实体字段不一致的情况

示例 | 基于注解开发上述示例

项目目录结构

image-20240411085750807

UserMapper.xml文件去掉了,转而在UserMapper.java中加入注解,实现SQL语句。

**注意:**即使没了UserMapper.xml配置文件,也要在mybatis-config.xml配置文件中注册mapper

进阶

示例 | resultMap多对一处理

项目目录结构

image-20240411090712167

Pojo中,增加了学生和老师的实体对象。


案例背景及概念理解:关联、集合

在学校里,一个老师对应多个学生。

  • 对于学生而言:是多对一的关系,多个学生关联一个老师
  • 对于老师而言:是一对多的关系,一个老师集合多个学生

现在要求:查询所有的学生,及其关联的老师信息

数据库创建:

-- 新建老师表
CREATE TABLE `teacher` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

-- 插入老师数据
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');

-- 新建学生表
CREATE TABLE `student` (
  `id` INT(10) NOT NULL,
  `name` VARCHAR(30) DEFAULT NULL,
  `tid` INT(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `fktid` (`tid`),
  CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

-- 插入学生数据
INSERT INTO `student` (`id`, `name`, `tid`) VALUES 
('1', '小明', '1'),
('2', '小红', '1'),
('3', '小张', '1'),
('4', '小李', '1'),
('5', '小王', '1')

复杂查询的两种查询思路:

  • 子查询 | 按照查询嵌套处理:先查询学生,为每一个查询到的学生,查询其对应的老师。
-- 对应的SQL写法
select id, name, tid, (select name from teacher as t where t.id = s.tid) as t_name from student s;
<select id="getTeacher"  resultType="GSF.Example.Pojo.Teacher">
    select * from learn_mybatis.teacher where id=#{id}
</select>

<!--根据查询嵌套处理-->
<select id="getStudent" resultMap="getStudent">
    select id, name, tid from learn_mybatis.student;
</select>

<resultMap id="getStudent" type="GSF.Example.Pojo.Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="teacher" column="tid" javaType="GSF.Example.Pojo.Teacher" select="getTeacher"/>
</resultMap>
  • 连接查询 | 按照结果嵌套处理:先查询所有的学生、老师,然后封装查询结果
select  s.id s_id ,s.name s_name, t.id t_id, t.name t_name 
from learn_mybatis.student s, learn_mybatis.teacher t
where s.tid=t.id
<select id="getStudent2" resultMap="getStudent2">
    select  s.id s_id ,s.name s_name, t.id t_id, t.name t_name 
    from learn_mybatis.student s, learn_mybatis.teacher t
    where s.tid=t.id
</select>

<resultMap id="getStudent2" type="GSF.Example.Pojo.Student">
    <result property="id" column="s_id"/>
    <result property="name" column="s_name"/>
    <association property="teacher" javaType="GSF.Example.Pojo.Teacher">
        <result property="id" column="t_id"/>
        <result property="name" column="t_name"/>
    </association>
</resultMap>

测试结果:

Student(id=1, name=小明, teacher=Teacher(id=1, name=秦老师))
Student(id=2, name=小红, teacher=Teacher(id=1, name=秦老师))
Student(id=3, name=小张, teacher=Teacher(id=1, name=秦老师))
Student(id=4, name=小李, teacher=Teacher(id=1, name=秦老师))
Student(id=5, name=小王, teacher=Teacher(id=1, name=秦老师))

总结:association标签

association标签,处理关联关系,即多对一关系

示例 | resultMap一对多处理

项目目录结构

同上述示例。


案例背景及概念理解:关联、集合

同上述示例。

现在要求:查询所有的老师,及其集合的学生信息


复杂查询的两种查询思路:

  • 子查询 | 按照查询嵌套处理:先查询老师,为每一个查询到的学生,查询其对应的老师。
-- 对应的SQL写法:好像没法写

-- 上述多对一关系中的写法:关注点在学生
-- 这个写法也是有隐患的,当一个学生对应多个老师的时候,同样会报错
select id, name, tid, (select name from teacher as t where t.id = s.tid) as t_name from student s;

-- 尝试的写法:关注点在老师。直接报错
-- 这样的子查询写法在()中语句返回不是单个值的时候会出现错误,因为select后的子查询,通常希望返回单个值。
select id, name, (select name from student as s where s.tid = t.id) as s_name from teacher as t;

-- 总的来说:还是用连接查询要好点,理解简单,还不容易出错,效率还高
<select id="getTeacher2" resultMap="TeacherStudent2">
    select * from learn_mybatis.teacher where id=#{id}
</select>

<resultMap id="TeacherStudent2" type="GSF.Example.Pojo.Teacher">
	<!--两个地方用到id,这个result就得写出来,不然不展示老师的id-->
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="students" column="id" javaType="ArrayList" ofType="GSF.Example.Pojo.Student" select="getStudentByTeacherId"/>
</resultMap>

<select id="getStudentByTeacherId" resultType="GSF.Example.Pojo.Student">
    select * from learn_mybatis.student where tid =#{id}
</select>
  • 连接查询 | 按照结果嵌套处理:先查询所有的学生、老师,然后封装查询结果
select s.id s_id, s.name s_name, t.name t_name, t.id t_id
from learn_mybatis.student s, learn_mybatis.teacher t
where s.tid = t.id
<select id="getTeacher"  resultMap="getTeacher">
    select s.id s_id, s.name s_name, t.name t_name, t.id t_id
    from learn_mybatis.student s, learn_mybatis.teacher t
    where s.tid = t.id and t.id=#{id}
</select>

<resultMap id="getTeacher" type="GSF.Example.Pojo.Teacher">
    <result property="id" column="t_id"/>
    <result property="name" column="t_name"/>
    <collection property="students" javaType="ArrayList" ofType="GSF.Example.Pojo.Student">
        <result property="id" column="s_id"/>
        <result property="name" column="s_name"/>
        <result property="tid" column="t_id"/>
    </collection>
</resultMap>

测试结果:

Teacher(id=1, name=秦老师, students=[Student(id=1, name=小明, tid=1), Student(id=2, name=小红, tid=1), Student(id=3, name=小张, tid=1), Student(id=4, name=小李, tid=1), Student(id=5, name=小王, tid=1)])

总结:collection标签

collection标签,处理集合关系,即一对多关系

进阶 | 动态SQL标签学习

项目准备

项目目录

image-20240411100755430

数据库环境

-- 
CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `blog`(`id`,`title`,`author`,`create_time`,`views`) VALUES
(1, "如何学Python", "青", "2022-10-11", 300),
(2, "如何学Java", "刘", "2022-10-12", 400),
(3, "如何学Django", "郭", "2022-10-13", 700)

动态SQL-IF

public interface UserDao {
    List<Blog> getBlogIf(Map<String, Object> map);
}
<select id="getBlogIf"  parameterType="map" resultType="GSF.Example.Pojo.Blog">
    select * from learn_mybatis.blog where 1=1
    <if test="title != null">
        and title=#{title}
    </if>

    <if test="author != null">
        and author=#{author}
    </if>
</select>
  • IF标签不具备自动添加and的功能,每个拼接的子SQL语句,需要自行添加and
-- 若传入空的map,真实的sql语句:
select * from learn_mybatis.blog where 1=1

-- 若传入的map带有title键,真实的sql语句:
select * from learn_mybatis.blog where 1=1 and title=?

-- 若传入的map带有title键和author键,真实的sql语句:
select * from learn_mybatis.blog where 1=1 and title=? and author=?

动态SQL-where、choose、when、otherwise

public interface UserDao {
    List<Blog> getBlogChoose_When_Otherwise(Map<String, Object> map);
}
<select id="getBlogChoose_When_Otherwise"  parameterType="map" resultType="GSF.Example.Pojo.Blog">
    select * from learn_mybatis.blog
    <!-- 这里用到了下一个查询才讲述的where标签 -->
    <where>
        <choose>
            <when test="title != null">
               and title = #{title}
            </when>

             <when test="author !=null">
                and author = #{author}
            </when>

            <otherwise>
                and id = 1
            </otherwise>
        </choose>
    </where>
</select>
  • choose、when、otherwisel类似java的switch用法:从上到下的判断语句,遇到满足的就用,即使后续有条件也满足,也不会调用
  • where标签具备自动添加where字符和删除首个子SQL语句的and字符的功能
-- 若传入空的map,真实的sql语句:
select * from learn_mybatis.blog where id=1

-- 若传入的map带有title键,真实的sql语句:
select * from learn_mybatis.blog where title=?

-- 若传入的map带有title键和author键,真实的sql语句:
select * from learn_mybatis.blog where title=?

动态SQL-Set

public interface UserDao {
    int updateBlogSet(Map<String, Object> map);
}
<update id="updateBlogSet" parameterType="map">
    update learn_mybatis.blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
    </set>
    where id = #{id}
</update>
  • set标签具备补充set字符和删除sql语句末尾“,”字符的功能
  • if标签中sql子句末尾的“,”需要写入,不然sql语句报错
-- 若传入空的map或仅仅有id的map,真实的sql语句:
报错

-- 若传入的map带有title键,真实的sql语句:
update learn_mybatis.blog SET title = ? where id = ?

-- 若传入的map带有title键和author键,真实的sql语句:
update learn_mybatis.blog SET title = ?, author = ? where id = ?

动态SQL-trim、sql片段

public interface UserDao {
    int updateBlogTrim(Map<String, Object> map);
}
<sql id="if-title-author">
    <if test="title != null">
        title = #{title},
    </if>
    <if test="author != null">
        author = #{author},
    </if>
</sql>

<update id="updateBlogTrim" parameterType="map">
    update learn_mybatis.blog
    <trim prefix="SET" suffixOverrides=",">
        <include refid="if-title-author">
        </include>
    </trim>
    where id = #{id}
</update>
-- 若传入空的map或仅仅有id的map,真实的sql语句:
报错

-- 若传入的map带有title键,真实的sql语句:
update learn_mybatis.blog SET title = ? where id = ?

-- 若传入的map带有title键和author键,真实的sql语句:
update learn_mybatis.blog SET title = ?, author = ? where id = ?
  • trim标签可以自定义待拼接sql语句的相关前缀、后缀的补充操作及去除操作
  • 上述用trim标签,实现set标签的相关功能
trim标签属性描述
prefix给sql语句拼接的前缀
suffix给sql语句拼接的后缀
prefixOverrides去除sql语句前面的关键字或者字符;
假设该属性指定为"AND",当sql语句的开头为"AND",trim标签将会去除该"AND"
suffixOverrides去除sql语句后面的关键字或者字符;
假设该属性指定为",“,当sql语句的结尾为”,“,trim标签将会去除该”,"

动态SQL-foreach

public interface UserDao {
    List<Blog> getBlogForeach(Map<String, Object> map);
}
<select id="getBlogForeach"  parameterType="map" resultType="GSF.Example.Pojo.Blog">
    select * from learn_mybatis.blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id=#{id}
        </foreach>
    </where>
</select>
  • 提供遍历操作
  • 还是传入的map,只是map的键对应的值是一个list
-- 若传入空的map,真实的sql语句:
select * from learn_mybatis.blog

-- 若传入的map中的list带有值1,真实的sql语句:
select * from learn_mybatis.blog WHERE ( id=? )

-- 若传入的map中的list带有值1、2、3,真实的sql语句:
select * from learn_mybatis.blog WHERE ( id=? or id=? or id=? )

进阶 | 缓存

缓存的概念

什么是缓存?

存在内存中的临时数据。将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用了从磁盘上(关系型数据库数据文件)查询,而是从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

为什么使用缓存?

减少和数据库的交互次数,较少系统开销,提高系统效率

什么样的数据能使用缓存?

经常查询而且不经常改变的数据

Mybatis缓存

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。

MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存

  • 默认情况下,只有一级缓存开启 (SqlSession级别的缓存,也称为本地缓存)
  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存
  • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存(学到了再说)

一级缓存

与数据库同一次会话期间查询到的数据会放在本地缓存中,以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库

测试验证一级缓存

@Test
public void  test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.queryUserById(1);
    System.out.println(user);
    System.out.println("=================================================================");
    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    // true:返回结果为true,且只执行了一次sql语句
    System.out.println(user==user2);

    sqlSession.close();
}

一级缓存失效条件

  • 查询不同的东西
  • 增删改操作,可能会改变原来的数据,所以必定会刷新缓存!
  • 查询不同的Mapper.xml
  • 手动清理缓存!
@Test
public void  test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.queryUserById(1);
    System.out.println(user);

    // 更新数据,导致缓存时效
    //mapper.updateUser(new User(2,"niahoooo","309487"));

    // 手动清理缓存,导致缓存时效
    //sqlSession.clearCache();

    System.out.println("=================================================================");
    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    System.out.println(user==user2);

    sqlSession.close();
}

一级缓存生命周期

生命周期为一个特定mapper.xml的一次sqlsession会话

二级缓存

二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存

基于namespace级别的缓存,一个名称空间,对应一个二级缓存

工作机制:

  • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中:
  • 如果当前会话关闭了,这个会话对应的一级缓存就没了,一级缓存中的数据被保存到二级缓存中;
  • 新的会话查询信息,就可以从二级缓存中获取内容
  • 不同的mapper.xml查出的数据会放在自己对应的缓存(map)中

测试验证二级缓存

  • 在全局开启二级缓存:mybatis-config.xml
<setting name="cacheEnable" value="true"/>
  • 在要开启缓存的mapper.xml中开启
<cache  eviction="FIFO"
        flushInterval="60000"
        size="512"
        readOnly="true"/>
  • 测试
@Test
public void  test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    User user = mapper.queryUserById(1);
    System.out.println(user);
    
    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    User user2 = mapper.queryUserById(1);
    System.out.println(user2);

    System.out.println(user==user2);

    sqlSession.close();
    sqlSession2.close();
}

注意事项:

  • 我们需要将实体类序列化(实现Serializable接口),否则就会报错
  • sqlsession关闭的时候一定要在最后关闭,不能先关闭sqlsession再关闭sqlsession2,这样会导致Cause: org.apache.ibatis.executor.ExecutorException: Executor was closed

二级缓存的生命周期

在同一个Mapper.xml下的多次Sqlsession

只有当sqlsession关闭的时候,数据才会从一级缓存扔到二级缓存

自定义二级缓存-ehcache

  • EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider
  • Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

具体使用,用到再说,开发中常用Redis数据库来做缓存。

Mybatis缓存的调用顺序

  1. 先看二级缓存中有没有
  2. 再看一级缓存中有没有
  3. 查询数据库:查询后将数据放入一级缓存

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

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

相关文章

Golang | Leetcode Golang题解之第22题括号生成

题目&#xff1a; 题解&#xff1a; var res []stringfunc generateParenthesis(n int) []string {res make([]string, 0)dfs(n, 0, 0, "")return res }func dfs(n int, lc int, rc int, path string) {if lc n && rc n {res append(res, path)return }…

一键下载 M3U8 并转换为 MP4升级版

之前的下载 M3U8程序&#xff0c;有很多问题&#xff0c; 为此做了一些升级&#xff0c;分享给大家。 增加了存在播放列表的情况处理播放列表路径和ts路径错误问题多线程问题对于电视剧多文件下载的处理 这里从网上找了一部的链接&#xff0c;可以参考这个网站https://www.zu…

YOLOV5训练KITTI数据集实践

目录 一、YOLOV5下载安装二、KITTI数据集三、标签格式转换四、修改配置文件五、训练六、测试 一、YOLOV5下载安装 git clone https://github.com/ultralytics/yolov5.git conda create -n yolov5 python3.8 -y conda activate yolov5 cd yolov5 pip install -r requirements.t…

百度OCR身份证识别C++离线SDKV3.0 C#对接

百度OCR身份证识别C离线SDKV3.0 C#对接 目录 说明 效果 问题 项目 代码 下载 说明 自己根据SDK封装了动态库&#xff0c;然后C#调用。 SDK 简介 本 SDK 适应于于 Windows 平台下的⾝份证识别系统,⽀持 C接⼜开发的 SDK,开发者可在VS2015 下⾯进⾏开发&#xff08;推荐…

基于FPGA的HDMI设计导航页面

FPGA使用HDMI更多时候用于传输图像数据&#xff0c;并不会传输音频数据&#xff0c;因此以下文章均采用DVI接口协议&#xff0c;HDMI与DVI的视频传输协议基本一致&#xff0c;区别也很小。 首先需要了解HDMI的来源&#xff0c;以及物理接口类型以及引脚信号&#xff0c;最后对几…

网站SEO关键词规划时如何筛选出合适的关键词?

在网站SEO优化过程中&#xff0c;关键词布局是一个至关重要的环节。首先&#xff0c;我们需要确定核心关键词&#xff0c;然后通过各种策略和方法对关键词进行扩展。完成关键词扩展后&#xff0c;接下来的任务就是对这些扩展后的关键词进行筛选。那么&#xff0c;如何进行有效的…

day02 51单片机

51单片机学习 1闪烁LED 1.1 需求描述 这个案例,我们要让P00引脚对应的LED按照1秒闪烁1次。 1.2 硬件设计 1.1 软件设计 1)LED闪烁的代码 想让LED闪烁,就需要P00的值不断在0和1之间循环变化。实现这一功能的代码也很简单: #include <STC89C5xRC.H> //包含STC89…

在线预约小程序怎么做

在快节奏的现代生活中&#xff0c;无论是预约理发、还是预定餐厅&#xff0c;亦或是挂号就医&#xff0c;我们都希望有一个更加便捷、高效的方式来完成这些任务。而今&#xff0c;随着科技的发展&#xff0c;一款全新的在线预约小程序应运而生&#xff0c;为我们的生活带来了前…

SOCKS代理是如何增强网络隐私?

在数字化时代&#x1f310;&#xff0c;网络隐私的重要性日益凸显。个人和组织都在寻找有效的方法来保护自己的网络活动不受侵犯。SOCKS代理作为一种流行的网络协议&#xff0c;提供了一种有效的手段来增强网络隐私。本文将详细介绍SOCKS代理是如何工作的&#xff0c;以及它是如…

【随笔】Git 高级篇 -- 本地栈式提交 rebase | cherry-pick(十七)

&#x1f48c; 所属专栏&#xff1a;【Git】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大…

不允许在constexpr函数中进行声明

这是我用pycharm在windows系统下复现sfm深度学习网络(Deep Two-View Structure-from-Motion Revisited&#xff09;遇见的问题&#xff0c;复现时有段代码pytorch扩展cuda/c&#xff0c;pycharm中出现C标准相关的报错如下&#xff1a; 在网上查找很久无果&#xff0c;后面通过…

局域网tcp通信实验

两台windows系统计算机简单TCP通信测试_两台计算机tcp通信-CSDN博客 使用这篇文章的小工具。 环境&#xff1a; 我和同学的两台笔记本电脑。 使用我的手机开热点&#xff0c;两台电脑连接热点。 我的&#xff1a; IPv4 地址 . . . . . . . . . . . . : 192.168.92.79 子…

码农必看:常见源代码混淆技术详解

背景 一、项目组代码部署存在的问题 在项目组中&#xff0c;核心代码模块被部署于用户服务器上。然而&#xff0c;另一家公司获取了该服务器的root密码&#xff0c;这就存在着潜在的数据泄露和代码泄露的风险。传统的解决方法是通过配置环境变量来进行数据库加密处理&#xf…

全国项目管理标准化技术委员会副秘书长肖杨先生受邀为第十三届中国PMO大会演讲嘉宾

全国PMO专业人士年度盛会 全国项目管理标准化技术委员会副秘书长、微薄之力&#xff08;北京&#xff09;管理咨询有限公司董事长肖杨先生受邀为PMO评论主办的2024第十三届中国PMO大会演讲嘉宾&#xff0c;演讲议题为“数字化时代下&#xff0c;由职能型组织向高度适应性组织转…

免费的GPT-3.5 API服务aurora

什么是 aurora &#xff1f; aurora 是利用免登录 ChatGPT Web 提供的无限制免费 GPT-3.5-Turbo API 的服务&#xff0c;支持使用 3.5 的 access 调用。 【注意】&#xff1a;仅 IP 属地支持免登录使用 ChatGPT的才可以使用&#xff08;也可以自定义 Baseurl 来绕过限制&#x…

03-JAVA设计模式-装饰模式

装饰模式 什么装饰模式 装饰器模式&#xff08;Decorator Pattern&#xff09;也叫包装器模式&#xff0c;是一种结构型设计模式&#xff0c;允许用户在不改变对象的情况下&#xff0c;动态地给对象增加一些额外的职责&#xff08;功能&#xff09;。装饰器模式相比生成子类更…

【重磅福利】智慧餐饮互联网餐饮行业分析数字化报告大合集共40份(免费下载)

【1】关注本公众号 【2】私信发送 智慧餐饮报告合集 【3】获取本方案合集的下载链接&#xff0c;直接下载即可。

前端学习<四>JavaScript基础——15-内置对象 String:字符串的常见方法

内置对象简介 JavaScript 中的对象分为3种&#xff1a;自定义对象、内置对象、浏览器对象。 前面两种对象&#xff1a;是JS的基础内容&#xff0c;属于 ECMAScript&#xff1b; 第三个浏览器对象&#xff1a;属于JS独有&#xff0c;即 JS 内置的API。 内置对象&#xff1a;就是…

为什么大模型训练都需要GPU?现在都有哪些合适的GPU适合训练大模型?价格如何?

大家有没有这样的疑问&#xff0c;为什么大模型训练需要的是GPU&#xff0c;而不是CPU&#xff0c;而现在市面上&#xff0c;有哪些适合训练的GPU型号&#xff0c;价格如何&#xff1f;下面让我来一一给大家进行介绍。 为什么大模型训练需要GPU&#xff0c;而非CPU&#xff1f;…

设计模式——责任链模式13

责任链模式 每个流程或事物处理 像一个链表结构处理。场景由 多层部门审批&#xff0c;问题分级处理等。下面体现的是 不同难度的问题由不同人进行解决。 设计模式&#xff0c;一定要敲代码理解 传递问题实体 /*** author ggbond* date 2024年04月10日 07:48*/ public class…