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

前言

本文主要学习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 twhere 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_idfrom learn_mybatis.student s, learn_mybatis.teacher twhere 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=utf8INSERT 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.mzph.cn/news/811631.shtml

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

相关文章

Elasticsearch安装、启动异常问题总结

安装es、kibana、ik分词器可参考&#xff1a;http://t.csdnimg.cn/59mEG 1. 内核过低 我们使⽤的是 centos6 &#xff0c;其 linux 内核版本为 2.6 。⽽ Elasticsearch 的插件要求⾄少 3.5 以上版 本。不过没关系&#xff0c;我们禁 ⽤这个插件即可。 修改 elasticsearch.ym…

spring boot整合Redis监听数据变化

一、前言 Redis提供了数据变化的通知事件&#xff0c;可以实时监测key和value的变化&#xff0c;客户端可以通过订阅相关的channel来接收这些通知事件&#xff0c;然后做相应的自定义处理&#xff0c;详细的介绍可以参考官方文档Redis keyspace notifications | Docs 使用Red…

一次http访问超时服务器端调试

问题&#xff1a;http访问服务器时没有返回&#xff0c;没有超时&#xff0c;一直在阻塞 处理过程&#xff1a;telnet端口能连上&#xff0c;服务端程序也不存在处理时间过长的情况。 说明tcp连接没问题。推测是客户端连接后再发起请求&#xff0c;服务端阻塞了。因为很多客户…

关于 TDengine 的时区(timeZone)问题

背景 在学习SagooIOT物联网平台使用docker部署TDengine时序数据库&#xff0c;根据时间戳&#xff08;timestamp&#xff09;ts查询上报设备数据时 发现结果跟查询条件不匹配。查询问题原因竟然是timezone时区设置问题。 查询数据结果&#xff1a; 查看容器时区&#xff1a; …

分类算法——sklearn转换器和估计器(一)

转换器&#xff08;特征工程的父类&#xff09; 实例化&#xff08;实例化的是一个转换器类&#xff08;Transformer&#xff09;&#xff09;调用fit_transform&#xff08;对于文档建立分类词频矩阵&#xff0c;不能同时调用&#xff09; 把特征工程的接口称之为转换器&…

当你的项目体积比较大?你如何做性能优化

在前端开发中&#xff0c;项目体积优化是一个重要的环节&#xff0c;它直接影响到网页的加载速度和用户体验。随着前端项目越来越复杂&#xff0c;引入的依赖也越来越多&#xff0c;如何有效地减少最终打包文件的大小&#xff0c;成为了前端工程师需要面对的挑战。以下是一些常…

汽车咨询|基于SprinBoot的汽车资讯管理系统设计与实现(源码+数据库+文档)

汽车资讯管理系统目录 基于SprinBoot的汽车资讯管理系统设计与实现 一、前言 二、系统设计 三、系统功能设计 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#xff1a;✌️大厂码农|毕设布道师&#xff…

npm 切换成淘宝源,以及遇到npm 报错如何解决

淘宝源&#xff1a;npm config set registryhttps://registry.npmmirror.com/ 然后再npm下 package-lock.json这个删了 npm i再试一下

MySQL——创建和插入

一、插入数据 INSERT 使用建议; 在任何情况下建议列出列名&#xff0c;在 VALUES 中插入值时&#xff0c;注意值和列的意义对应关系 values 指定的值顺序非常重要&#xff0c;决定了值是否被保存到正确的列中 在指定了列名的情况下&#xff0c;你可以仅对需要插入的列给到…

【已解决】VMware Horizon Client: 无法建立安全加密链路连接

文章目录 问题原因解决方法方法1&#xff1a;在HTTPS拦截中添加VMware忽略列表 (推荐)方法2&#xff1a; 只拦截 浏览器进程的请求 / 取消 HTTPS 拦截&#xff08;如果没有拦截HTTPS的必要 / 只针对浏览器请求&#xff0c;可以使用此方法&#xff09; 当前使用mac 编辑&#xf…

飞书api增加权限

1&#xff0c;进入飞书开发者后台&#xff1a;飞书开放平台 给应用增加权限 2&#xff0c;进入飞书管理后台 https://fw5slkpbyb3.feishu.cn/admin/appCenter/audit 审核最新发布的版本 如果还是不行&#xff0c;则需要修改数据权限&#xff0c;修改为全部成员可修改。 改完…

Matlab与ROS(1/2)---Message(三)

0. 简介 消息是ROS中交换数据的主要容器。主题和服务使用消息在节点之间传输数据。为了标识其数据结构&#xff0c;每条消息都有一个消息类型。例如&#xff0c;来自激光扫描仪的传感器数据通常以sensor_msgs/LaserScan类型的消息发送。每种消息类型标识消息中包含的数据元素。…

类和对象二

一、运算符重载 为了使自定义类型可以使用加减等运算符&#xff0c;CPP提供了一个功能叫运算符重载。 关键字&#xff1a;operator操作符 运算符重载最好定义在类对象里&#xff0c;这也可以避免访问不到私有成员的问题。 代码演示&#xff1a; 在类里定义之后&#xff0c;…

Java常用数据结构与集合

数据结构 数组&#xff1a; 内存地址连续检索效率高(可以通过下标访问成员)增删操作效率低(保证数据越界的问题,需动态扩容)长度固定&#xff0c;扩容的需要新的数组复制或者Arrays类的copyOf方法 链表 内存地址不连续查询快删除慢&#xff0c;因为需要移动指针又分双向链表…

区块链安全-----区块链基础

区块链是一种全新的信息网络架构 &#xff0c;是新一代信息基础设施 &#xff0c;是新型的价值交换方式、 分布式协 同生产机制以及新型的算法经济模式的基础。 区块链技术可以集成到多个领域。 区块链的主要用途 是作为加密货币的分布式总帐。 它在银行 &#xff0c;金融 &…

浏览器工作原理与实践--HTTP/3:甩掉TCP、TLS 的包袱,构建高效网络

前面两篇文章我们分析了HTTP/1和HTTP/2&#xff0c;在HTTP/2出现之前&#xff0c;开发者需要采取很多变通的方式来解决HTTP/1所存在的问题&#xff0c;不过HTTP/2在2018年就开始得到了大规模的应用&#xff0c;HTTP/1中存在的一大堆缺陷都得到了解决。 HTTP/2的一个核心特性是使…

机器学习基础入门(一)(机器学习定义及分类)

机器学习定义 给予计算机无需特意带有目的性编程便有学习能力的算法 深度学习算法 主要有监督学习和非监督学习两类 监督学习&#xff08;supervised learning&#xff09; 定义 1、学习由x映射到y的映射关系 2、主动给予机器学习算法正确示例&#xff0c;算法通过示例来学习…

订单中台架构:打造高效订单管理系统的关键

在现代商业环境下&#xff0c;订单管理对于企业来说是至关重要的一环。然而&#xff0c;随着业务规模的扩大和多渠道销售的普及&#xff0c;传统的订单管理方式往往面临着诸多挑战&#xff0c;如订单流程复杂、信息孤岛、数据不一致等问题。为了应对这些挑战并抓住订单管理的机…

大数据迁移工具开发思路

数据存储MySQL中&#xff0c;迁移到hive中&#xff0c;建立数据仓库&#xff0c;为后期的大数据分析、主题订阅、消息分发提供海量数据支持。 涉及到的服务及中间件版本如下&#xff1a; 1、MySQL&#xff0c;版本&#xff1a;8.0.19 2、Hive&#xff0c;版本&#xff1a;3.0.0…

云计算:Linux 部署 OVS 集群(控制端)实现OpenFlow

目录 一、实验 1.环境 2.Linux 部署 OVS 集群&#xff08;控制端&#xff09; 3.控制端对接服务端OVS网元 4.服务端OVS添加流表 5.服务端删除OVS 二、问题 1. ODL如何查找已安装插件 2.查看流表显示不全 3.如何删除OVS流表 一、实验 1.环境 (1) 主机 表1 宿主机 主…