当前位置: 首页 > news >正文

Mybatis框架详解(全)

目录

MyBatis简介

MyBatis整体架构及运行流程

1.数据源配置文件

2.Sql映射文件

3.会话工厂与会话

4.运行流程

mybatis实现增删改查

Mybatis的获取参数的方式

mapper中自定义映射

mybatis注解开发

mybatis缓存

mybatis分页插件


MyBatis简介

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

2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

回顾JDBC的使用步骤:

  • 1.加载驱动

Class.forName("com.mysql.jdbc.Driver");
  • 2.获取连接对象

DiverManerger.getConnection(url,username,password)
  • 3.获取执行sql的Statement对象

connection.CreateStatement();
  • 4.执行sql语句

  • 5.处理结果集

  • 6.释放连接

connection.Close()

与JDBC相比:

  1. Mybatis通过参数映射方式,可以将参数灵活的配置在SQL语句中的配置文件中,避免在Java类中配置参数

  2. Mybatis通过输出映射机制,将结果集的检索自动映射成相应的Java对象,避免对结果集手工检索

  3. Mybatis可以通过Xml配置文件对数据库连接进行管理

MyBatis整体架构及运行流程

Mybatis整体构造由 数据源配置文件、Sql映射文件、会话工厂、会话、执行器和底层封装对象组成

1.数据源配置文件

通过配置的方式将数据库的配置信息从应用程序中独立出来,由独立的模块管理和配置。Mybatis的数据源配置文件包含数据库驱动、数据库连接地址、用户名密码、事务管理等,还可以配置连接池的连接数、空闲时间等

一个MapConfig.xml基本的配置信息如下:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><environments default="development"><environment id="development"><!-- 事务的管理 JDBC  MANAGED--><transactionManager type="JDBC"/><!-- 数据源 POOLED UNPOOLED JNDI --><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><mapper resource="org/mybatis/example/BlogMapper.xml"/></mappers>
</configuration>

mybatis mapper文件映射

 

 设置资源文件路径

Maven中默认是只会打包resource下的资源文件。如果我们的文件不放在resource, 则需要通过配置告知Maven

2.Sql映射文件

Mybatis中所有数据库的操作都会基于该映射文件和配置的sql语句,在这个配置文件中可以配置任何类型的sql语句。框架会根据配置文件中的参数配置,完成对sql语句以及输入输出参数的映射配置。

Mapper.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="命名空间"><select id="方法名" resultMap="返回值类型" parameterType="参数类型">-- sql语句</select></mapper>

 

3.会话工厂与会话

Mybatis中会话工厂SqlSessionFactory类可以通过加载资源文件,读取数据源配置MapConfig.xml信息,从而产生一种可以与数据库交互的会话实例SqlSession,会话实例SqlSession根据Mapper.xml文件中配置的sql,对数据库进行操作。

4.运行流程

会话工厂SqlSessionFactory通过加载资源文件获取MapConfig.xml配置文件信息,然后生成可以与数据库交互的会话实例SqlSession。会话实例可以根据Mapper配置文件中的Sql配置去执行相应的增删改查操作

执行流程图:

mybatis实现增删改查

public class TestStudent {@Testpublic void test01(){try {//加载配置文件InputStream in = Resources.getResourceAsStream("config/mybatis-config.xml");//获取sqlSession对象SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();//查询所有学生信息List<Student> students = sqlSession.selectList("cn.kgc.mybatis.dao.StudentDao.getAll");	students.forEach(student -> System.out.println(student) );} catch (IOException e) {e.printStackTrace();}}@Testpublic void test02(){//查询一个学生信息try {//加载配置文件InputStream in = Resources.getResourceAsStream("config/mybatis-config.xml");//获取sqlSession对象SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();//根据用户名查询一个学生信息Student student = sqlSession.selectOne("cn.kgc.mybatis.dao.StudentDao.findOne","tom");System.out.println(student);sqlSession.close();} catch (IOException e) {e.printStackTrace();}}@Testpublic void test03() {//添加一个学生信息try {//加载配置文件InputStream in = Resources.getResourceAsStream("config/mybatis-config.xml");//获取sqlSession对象SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();//添加一个学生信息Student student = Student.builder().stuBirth(new Date()).stuName("lilei").stuNo("2021073001").stuSex("男").build();int i = sqlSession.insert("cn.kgc.mybatis.dao.StudentDao.addOne", student);System.out.println(i);sqlSession.commit();sqlSession.close();} catch (IOException e) {e.printStackTrace();}}@Testpublic void test04() {//删除一个学生信息try{InputStream in = Resources.getResourceAsStream("config/mybatis-config.xml");//获取sqlSession对象 同时可设置事务的自动提交  openSession(true)SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();int delete = sqlSession.delete("cn.kgc.mybatis.dao.StudentDao.delOne","lilei" );sqlSession.commit();sqlSession.close();System.out.println(delete);}catch (Exception e){e.printStackTrace();}}@Testpublic void test05() {//修改一个学生信息try{InputStream in = Resources.getResourceAsStream("config/mybatis-config.xml");//获取sqlSession对象SqlSession sqlSession = new SqlSessionFactoryBuilder().build(in).openSession();Student student = Student.builder().stuBirth(new Date()).stuName("lili").stuNo("2021073001").stuSex("女").build();int delete = sqlSession.update("cn.kgc.mybatis.dao.StudentDao.updateStudent",student);sqlSession.commit();sqlSession.close();System.out.println(delete);}catch (Exception e){e.printStackTrace();}}}

 

mybatis中使用log4j日志工具

1.配置mybatis-config.xml

开启驼峰命名  

设置别名

 

2.配置log4j.properties文件,放置在resources目录下

log4j.rootLogger=DEBUG,Console#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Target=System.out
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%nlog4j.logger.org.apache=ERROR
log4j.logger.org.mybatis=ERROR
log4j.logger.org.springframework=ERROR#这个需要
log4j.logger.log4jdbc.debug=ERROR
log4j.logger.com.gk.mapper=ERROR
log4j.logger.jdbc.audit=ERROR
log4j.logger.jdbc.resultset=ERROR
#这个打印SQL语句非常重要
log4j.logger.jdbc.sqlonly=DEBUG
log4j.logger.jdbc.sqltiming=ERROR
log4j.logger.jdbc.connection=FATAL

 

 使用mapper代理对象实现增删改查

public class TestStudentMapper {SqlSessionFactory factory;@Beforepublic void init(){try {InputStream  in = Resources.getResourceAsStream("config/mybatis-config.xml");SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();factory = sfb.build(in);} catch (IOException e) {e.printStackTrace();}}@Testpublic void test01(){//开启事务自动提交SqlSession sqlSession = factory.openSession(true);//获取dao层的代理对象StudentDao studentDao = sqlSession.getMapper(StudentDao.class);List<Student> students = studentDao.getAll();students.forEach(student -> System.out.println(student));}@Testpublic void test02(){ //添加数据SqlSession sqlSession = factory.openSession(true);Student student = Student.builder().stuSex("男").stuNo("2021073100").stuName("李四").stuBirth(new Date()).build();StudentDao studentDao = sqlSession.getMapper(StudentDao.class);Integer line = studentDao.addOne(student);System.out.println(line);}@Testpublic  void test03(){//删除一条数据SqlSession sqlSession = factory.openSession(true);StudentDao studentDao = sqlSession.getMapper(StudentDao.class);Integer line = studentDao.delOne("李四");System.out.println(line);}@Testpublic void test04() { //修改数据SqlSession sqlSession = factory.openSession(true);StudentDao studentDao = sqlSession.getMapper(StudentDao.class);Student student = Student.builder().stuSex("女").stuNo("2021073100").stuName("李四").stuBirth(new Date()).build();Integer line = studentDao.updateOne(student);System.out.println(line);}@Testpublic void test06(){//模糊查询一个学生信息 一个参数SqlSession sqlSession = factory.openSession(true);StudentDao studentDao = sqlSession.getMapper(StudentDao.class);List<Student> students = studentDao.selectLikeName("li");System.out.println(students.toString());}@Testpublic void test07(){//模糊查询一个学生信息 两个参数SqlSession sqlSession = factory.openSession(true);StudentDao studentDao = sqlSession.getMapper(StudentDao.class);List<Student> students = studentDao.selectLikeName2("li", "2021072902");System.out.println(students.toString());}@Testpublic void test08(){//模糊查询一个学生信息 一个集合参数  mapper文件中按照key取值SqlSession sqlSession = factory.openSession(true);StudentDao studentDao = sqlSession.getMapper(StudentDao.class);HashMap<String, String> map = new HashMap<>();map.put("stuname","li");map.put("stuno", "2021072902");List<Student> students = studentDao.selectLikeName3(map);System.out.println(students.toString());}}

 

Mybatis的获取参数的方式

方式1:${} 字符串拼接

方式2:#{} 占位符

1.Mapper接口参数为单个参数

2.Mapper接口参数是多个参数的获取

mybatis在处理多个参数时,会将多个参数保存到map集合中会 以 agr0 ,agr1或param1 param2为键 以参数位置进行存储

 

3.将参数设为map集合进行数据的传递

 

4.通过注解@param("键名")设置参数的获取名字

 

5.将多个参数设置成对象进行数据的传递

 

Mybatis中的模糊查询

 6.批量删除

mapper中自定义映射

自定义映射的用法之一,解决表格查询的字段名和实体类中不一致的情况

 

mybatis对象的关联关系

一对多关系处理(一方)

<resultMap id="selectByEIdMap" type="cn.kgc.mybatis.entity.Emp"><result column="id" property="dept.id" ></result><result column="dname" property="dept.dName"></result></resultMap><resultMap id="selectByEIdMap2" type="cn.kgc.mybatis.entity.Emp"><id column="eid" property="eId"></id><result column="ename" property="EName"></result><result column="age" property="age"></result><result column="deptno" property="deptNo"></result><!--实体对象标识--><association property="dept" javaType="dept"><id column="id" property="id"></id><result column="dname" property="dName"></result></association></resultMap><!-- 分步查询 --><resultMap id="selectByEIdMap3" type="cn.kgc.mybatis.entity.Emp"><id column="eid" property="eId"></id><result column="ename" property="EName"></result><result column="age" property="age"></result><result column="deptno" property="deptNo"></result><association property="dept" select="cn.kgc.mybatis.mapper.DeptMapper.selectById" column="deptno" fetchType="eager"></association></resultMap>注:延迟加载设置  :1. <setting name="lazyLoadingEnabled" value="true"/> 2. <setting name="aggressiveLazyLoading" value="false"/>  3.4.1之前的版本需要设置<select id="selectByEId" resultMap="selectByEIdMap2">select  * from emp left  join  dept on  emp.deptno = dept.id  where eid = #{eid}</select><select id="selectByEId2" resultMap="selectByEIdMap3">select  * from emp  where eid = #{eid}</select>

 

 一对多关系处理(多方)

 <resultMap id="BaseResultMap" type="cn.kgc.mybatis.entity.Dept"><id property="id" column="id" /><result property="dName" column="dname" /><collection property="emps" ofType="emp"><id column="eid" property="eId"></id><result column="ename" property="EName"></result><result column="age" property="age"></result><result column="deptno" property="deptNo"></result></collection></resultMap><resultMap id="BaseResultMap2" type="cn.kgc.mybatis.entity.Dept"><id property="id" column="id" /><result property="dName" column="dname" /><collection property="emps" select="cn.kgc.mybatis.mapper.EmpMapper.selectByDeptId" column="id"></collection></resultMap><select id="selectById" resultType="dept">select  * from dept where id = #{id}</select><select id="selectById2" resultMap="BaseResultMap">select emp.* ,dept.* from dept left join emp on dept.id = emp.deptno where id = #{id}</select><select id="selectById3" resultMap="BaseResultMap2">select dept.* from dept  where id = #{id}</select>

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦

动态SQL:if 语句

根据 stu_name 和 stu_sex 来查询数据。如果stu_name为空,那么将只根据stu_sex来查询;反之只根据stu_name来查询

首先不使用 动态SQL 来书写

可以发现,如果 #{stu_name} 为空,那么查询结果也是空,如何解决这个问题呢?使用 if 来判断

 

 

这样写我们可以看到,如果 sex 等于 null,那么查询语句为 select * from student where stu_name=#{stu_name},但是如果stu_name 为空呢?那么查询语句为 select * from user where and stu_sex=#{sex},这是错误的 SQL 语句,如何解决呢?

if+where 语句

 

这个where标签会知道如果它包含的标签中有返回值的话,它就插入一个where。此外,如果标签返回的内容是以AND 或OR 开头的,则它会剔除掉

动态SQL:if+set 语句

上面的对于查询 SQL 语句包含 where 关键字,如果在进行更新操作的时候,含有 set 关键词

 

  • 如果第一个条件 username 为空,那么 sql 语句为:update user u set u.sex=? where id=?

  • 如果第一个条件不为空,那么 sql 语句为:update user u set u.username = ? ,u.sex = ? where id=?

动态SQL:choose(when,otherwise) 语句

有时候,我们不想用到所有的查询条件,只想选择其中的一个,查询条件有一个满足即可,使用 choose 标签可以解决此类问题,类似于 Java 的 switch 语句

 

这里我们有三个条件,id,username,sex,只能选择一个作为查询条件

  • 如果 id 不为空,那么查询语句为:select * from user where id=?

  • 如果 id 为空,那么看username 是否为空,如果不为空,那么语句为 select * from user where username=?;

  • 如果 username 为空,那么查询语句为 select * from user where sex=?

动态SQL:trim 语句

trim标记是一个格式化的标记,可以完成set或者是where标记的功能

用 trim 改写上面的 if+where 语句

  • prefix:前缀  

  • prefixoverride:去掉第一个and或者是or   

用 trim 改写上面的 if+set 语句

 

  • suffix:后缀  

  • suffixoverride:去掉最后一个逗号(也可以是其他的标记,就像是上面前缀中的and一样)

动态SQL: foreach 语句

需求:我们需要查询 user 表中 id 分别为1,2,3的用户,sql语句:

 

用 foreach 来改写 select * from user where id=1 or id=2 or id=3

 

 

用 foreach 来改写 select * from user where id in (1,2,3)

 

动态SQL: SQL 片段

有时候可能某个 sql 语句我们用的特别多,为了增加代码的重用性,简化代码,我们需要将这些代码抽取出来,然后使用时直接调用。

假如我们需要经常根据用户名和性别来进行联合查询,那么我们就把这个代码抽取出来,如下:

  

 

注意:①、最好基于 单表来定义 sql 片段,提高片段的可重用性

    ②、在 sql 片段中最好不要包括 where

mybatis注解开发

public interface StudentDao2 {@Select("select * from student where stu_no = #{stu_no}")@Results({@Result(property = "stuNo" ,column="stu_no"),@Result(property = "stuSex",column = "stu_sex"),@Result(property = "birth",column = "stu_birth")})List<Student> getAll(String stu_no);@Insert("insert into student (stu_no,stu_name,stu_sex,stu_birth)values(#{stuNo},#{stuName},#{stuSex},#{birth})")int addStudent(Student student);@Delete("delete from student where stu_no = #{stu_no}")int delOne(String stu_no);@Update("update student set stu_name = #{stuName} where stu_no = #{stuNo}")int uptStudent(Student student);}

 

mybatis缓存

MyBatis 中的缓存就是说 MyBatis 在执行一次SQL查询或者SQL更新之后,这条SQL语句并不会消失,而是被MyBatis 缓存起来,当再次执行相同SQL语句的时候,就会直接从缓存中进行提取,而不是再次执行SQL命令。

mybatis的缓存机制有两级:

(1)一级缓存:一级缓存mybatsi已经为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。(SqlSession级别.提交事务,缓存清空)

一级缓存失效的情况:

 

(2)二级缓存:二级缓存需要我们手动开启。(全局级别 SqlSessionFactory)

 

 @Testpublic void test02(){//验证mybatis的缓存机制  一级缓存 默认开启 sqlsession级别try {InputStream resource = Resources.getResourceAsStream("config/mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);SqlSession sqlSession = factory.openSession(true);StudentDao mapper1 = sqlSession.getMapper(StudentDao.class);StudentDao mapper2 = sqlSession.getMapper(StudentDao.class);System.out.println(mapper1);System.out.println(mapper2);List<Student> a1 = mapper1.getAll();System.out.println(a1);//手动提交事务 清空缓存sqlSession.commit();List<Student> a2 = mapper2.getAll();System.out.println(a2);sqlSession.close();} catch (IOException e) {e.printStackTrace();}}@Testpublic void test03(){//验证mybatis的缓存机制  二级缓存 需要配置mybatis-config.xml  和mapper文件try {InputStream resource = Resources.getResourceAsStream("config/mybatis-config.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resource);SqlSession sqlSession1 = factory.openSession(true);SqlSession sqlSession2 = factory.openSession(true);SqlSession sqlSession3 = factory.openSession(true);StudentDao mapper1 = sqlSession1.getMapper(StudentDao.class);StudentDao mapper2 = sqlSession2.getMapper(StudentDao.class);StudentDao mapper3 = sqlSession3.getMapper(StudentDao.class);List<Student> a1 = mapper1.getAll();System.out.println(a1);//关闭session将查询结果写入二级缓存sqlSession1.close();//当对同一张表进行增删改操作后  二级缓存清除mapper3.delStudent("2021072901");// sqlSession3.close();List<Student> a2 = mapper2.getAll();System.out.println(a2);} catch (IOException e) {e.printStackTrace();}}

mybatis分页插件

 

实例

 

今天的分享就到此结束了

创作不易点赞评论互关三连

 

 

 

相关文章:

Mybatis框架详解(全)

目录 MyBatis简介 MyBatis整体架构及运行流程 1.数据源配置文件 2.Sql映射文件 3.会话工厂与会话 4.运行流程 mybatis实现增删改查 Mybatis的获取参数的方式 mapper中自定义映射 mybatis注解开发 mybatis缓存 mybatis分页插件 MyBatis简介 MyBatis 是一款优秀的持久…...

2023年爆火的csgo搬砖项目详细拆解,steam搬砖长期稳定

不懂的同学可以听我下面慢慢道来 我的态度&#xff1a;存在即有意义&#xff0c;没有长久的赚钱项目&#xff0c;但是一定有长久赚钱的人。 我们团队也一直在做这个项目&#xff0c;赚钱是一定的&#xff0c;简单总结&#xff1a;执行力技巧量化。 开门见山 一、steam搬砖项…...

C语言实现动态管理通讯录信息系统(静态通讯录plus版)

文章目录前言&#xff1a;一.动态管理思想1.通讯录结构体声明发生变化2.通讯录结构体初始化发生变化3.通讯录能够动态增容4.通讯录销毁数据二.优化通讯录可持续读写信息1.保存通讯录中的信息到文件中2.加载文件信息到通讯录中三.源码1.text.c2.contact.c3.contact.h前言&#x…...

核心技术: springboot 启动类加载时方法执行的几种实现方式, bean声明周期, 启动执行顺序

目录 1. 业务场景 -> 1.1 初始化操作 -> 1.2 业务操作 -> 1.3优势 2. 实现方式(多种方式,不同思想) -> 2.1 定时调度任务(常用四种方式 task ) --> 2.1.1 Timer(单线程) --> 2.1.2 scheduledExecutorService(多线程并发执行,线程池) --> 2.1…...

拒绝背锅:测试项目中的风险管理一定要知道

测试经理除了要管理产品线的质量保障和日常部门事务工作外&#xff0c;另一项比较重要的就是测试项目全流程的管理。 今天不聊整体的测试项目流程如何开展&#xff0c;而是想聊一聊在同行中比较高频出现的一个字眼&#xff1a;风险管理。 什么是风险管理 引用百度上的解释&a…...

20-js本地存储

js本地存储 localStorage localStorage是window下的对象&#xff0c;可以使用window.localStorage调用&#xff0c;也可以直接使用localStorage调用。 浏览器关闭&#xff0c;localStorage也不会消失 示例&#xff1a; <body><h2>localStorage</h2><…...

ABAP 辨析ON INPUT|REQUEST|CHAIN-INPUT|CHAIN-REQUEST

1、逻辑流 在屏幕开发中&#xff0c;存在如下逻辑流&#xff1a; PBO&#xff08;Process Before Output&#xff09;&#xff1a;屏幕输出之前触发 PAI&#xff08;Process After Input&#xff09;&#xff1a;用户在屏幕中执行操作触发 POH&#xff08;Process On Help-…...

LeetCode:逆波兰式;

150. 逆波兰表达式求值 给你一个字符串数组 tokens &#xff0c;表示一个根据 逆波兰表示法 表示的算术表达式。 请你计算该表达式。返回一个表示表达式值的整数。 注意&#xff1a; 有效的算符为 、-、* 和 / 。每个操作数&#xff08;运算对象&#xff09;都可以是一个整…...

为什么阳康后,感觉自己变傻了?

不少人在阳康后出现脑力下降的情况&#xff0c;好像脑子里被雾笼罩。脑雾并不是新名词&#xff0c;已经存在了十几年。以前慢性疲劳综合征患者和脑震荡患者会用它来形容自己的症状。脑雾其实是认知障碍&#xff0c;它可由多种原因引起。比如过度劳累、长期酗酒、缺乏睡眠、久坐…...

考公和大厂40万年薪的offer,选哪个?

眼看毕业将至&#xff0c;相信很多小伙伴已经摩拳擦掌&#xff0c;在为毕业季就业做准备了。2023年高校毕业生规模预计1158万人&#xff0c;同比增加82万人。在资深人力资源服务家汪张明看来&#xff0c;2023年的就业态势不仅是大学毕业生数量有增加&#xff0c;还存在一定的存…...

多线程环境下调用 HttpWebRequest 并发连接限制

.net 的 HttpWebRequest 或者 WebClient 在多线程情况下存在并发连接限制&#xff0c;这个限制在桌面操作系统如 windows xp , windows 7 下默认是2&#xff0c;在服务器操作系统上默认为10. 如果不修改这个并发连接限制&#xff0c;那么客户端同时可以建立的 http 连接数就只有…...

vue3-element-admin搭建

vue3-element-admin 是基于 vue-element-admin 升级的 Vue3 Element Plus 版本的后台管理前端解决方案&#xff0c;是 有来技术团队 继 youlai-mall 全栈开源商城项目的又一开源力作功能清单技术栈清单技术栈 描述官网Vue3 渐进式 JavaScript 框架 https://v3.cn.vuejs.org/Ty…...

蓝海创意云vLive虚拟直播亮相2023昆山元宇宙产品展览会

2月15日-19日&#xff0c;由中国计算机行业协会“元宇宙创见未来”2023元宇宙产品展览会在江苏昆山隆重召开&#xff0c;共吸引了省内外32家企业参展&#xff0c;展出近百款元宇宙产品或技术&#xff0c;涵盖芯片、显示、VR、AR等硬件设备&#xff0c;以及工业、文旅、娱乐、教…...

ThreadLocal线程变量

首先看下ThreadLocal的set()方法存数据的过程&#xff0c;首先获取当前的线程中保持的ThreadLocalMap&#xff0c;每个线程的ThreadLocalMap都是不一样的&#xff0c;因此存储的值是不同的。 public void set(T value) {Thread t Thread.currentThread();ThreadLocalMap map …...

【linux安装redis详解】小白如何安装部署redis,linux安装部署只需5步骤(图文结合,亲测有效)

【写在前面】前端时间接触了一下redis&#xff0c;也是迫于页面查询响应太慢&#xff0c;没办法听说redis这个可持久化内存数据库&#xff0c;于是乎便想着在自己的机器上安装一套&#xff0c;接下来就重点和大家说说怎么从小白开始摸索redis 目录1、下载2、安装2.1 创建文件存…...

2023只会“点点点”,被裁只是时间问题,高薪的自动化测试需要掌握那些技能?

互联网已然是存量市场了&#xff0c;对人员规模的需求正在放缓。在存量市场里&#xff0c;冗余人员和低效人员会被淘汰、被外包。而优秀的人才也会一直受到招聘方的青睐。所以我们就看到了近期行业里冰火两重天的一幕&#xff0c;一边是大量的低端测试工程师被淘汰、求职屡屡碰…...

C语言【柔性数组】

柔性数组&#x1fac5;什么是柔性数组&#x1fac5;柔性数组的使用&#x1fac5;柔性数组的优势&#x1fac5;什么是柔性数组 也许你从来没有听说过柔性数组&#xff08;flexible array&#xff09;这个概念&#xff0c;但是它确实是存在的。 C99 中&#xff0c;结构中的最后一…...

AcWing275. 传纸条

AcWing275. 传纸条小渊和小轩是好朋友也是同班同学&#xff0c;他们在一起总有谈不完的话题。一次素质拓展活动中&#xff0c;班上同学安排坐成一个 m行 n 列的矩阵&#xff0c;而小渊和小轩被安排在矩阵对角线的两端&#xff0c;因此&#xff0c;他们就无法直接交谈了。幸运的…...

圆角矩形的绘制和曲线均匀化

摘要&#xff1a; 圆角矩形是软件 UI 等视觉设计中的常见表达&#xff0c;一种常见的绘制方法是将矩形的四角替换为与边相切的四分之一圆弧&#xff0c;然而这种绘制方式会在连接处产生视觉上的切折感&#xff0c;这是因为圆弧和直线的连接处只满足 G1G^1G1 连续性。本文探究了…...

【Linux】环境变量,命令行参数,main函数三个参数保姆教学

目录 ☃️1.奇奇怪怪的现象和孤儿进程 ☃️2.环境变量 ☃️3.深刻理解main函数的前两个参数和命令行参数 ☃️1.奇奇怪怪的现象和孤儿进程 首先回顾一下之前我们学过的fork&#xff08;&#xff09;创建子进程 fork(void)的返回值有两种 注意fork&#xff08;&#xff09;头…...

美国访问学者生活中有哪些饮食文化特点?

美国的教育毋庸置疑&#xff0c;排在世界数一数二的位置&#xff0c;美食美景更是数不胜数&#xff0c;那么他们有哪些饮食习惯&#xff0c;下面51访学网小编为你们详细介绍这些内容吧。 一、美国饮食文化特点 1、美国的饮食文化体现科学、适度、快捷&#xff0c;以满足人体的…...

RxJava中的Subject

要使用Rxjava首先要导入两个包&#xff0c;其中rxandroid是rxjava在android中的扩展 implementation io.reactivex:rxandroid:1.2.1implementation io.reactivex:rxjava:1.2.0Subject Subject 既可以是一个 Observer 也可以是一个 Observerable&#xff0c;它是连接 Observer 和…...

vue-element-admin在git 上 clone 之后无法install

一. 无法install的原因因为vue-element-admin引入的富文本编辑插件所导致 由于tui-editor变更 名字 导致 依赖查询找不到对应的版本二. 解决的办法先删掉package.json中tui-editor:1.3.3找到 \src\components\MarkdownEditor\index.vue 把所有的import 替换成下面4个import cod…...

Linux线程调度实验

Linux线程调度实验 1.获取线程属性 #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <pthread.h> #include <time.h> #include <stdlib.h> #include <errno.h> #define _GNU_SOURCE#define handle_error…...

洛谷P5735 【深基7.例1】距离函数 C语言/C++

【深基7.例1】距离函数 题目描述 给出平面坐标上不在一条直线上三个点坐标 (x1,y1),(x2,y2),(x3,y3)(x_1,y_1),(x_2,y_2),(x_3,y_3)(x1​,y1​),(x2​,y2​),(x3​,y3​)&#xff0c;坐标值是实数&#xff0c;且绝对值不超过 100.00&#xff0c;求围成的三角形周长。保留两位…...

企业什么要建设自有即时通讯软件系统

随着科技的不断发展&#xff0c;各种即时通讯软件也不断发展进步&#xff0c;而这也与企业的发展息息相关&#xff0c;因为每个人&#xff0c;每个企业都有属于自己的机密&#xff0c;属于自己的隐私。 钉钉&#xff0c;企业微信&#xff0c;等公有的即时通讯软件给企业带来便利…...

LocalDNS

目录 文章目录目录本节实战DNS优化1、dns 5s 超时问题解决办法2、NodeLocal DNSCache实验软件关于我最后本节实战 实战名称&#x1f498; 实战&#xff1a;NodeLocal DNSCache-2022.7.30(测试成功)&#x1f498; 实战&#xff1a;NodeLocal DNSCache-2023.2.21(测试成功) DNS优…...

线程池种类和拒绝策略

1、newCachedThreadPool()&#xff1a;可缓存的线程池&#xff0c;核心线程数量为0&#xff0c;最大线程数量为INT_MAX。线程空闲时间超过60秒被回收。适合处理大量小任务。 2、newFixedThreadPool()。固定线程个数的线程池&#xff0c;线程都是核心线程&#xff0c;没有应急线…...

Python制作9行最简单音乐播放器?不,我不满足

嗨害大家好鸭~我是小熊猫 好久不见啦~这次就来给大家整个大福利 ~ 源码资料电子书:点击此处跳转文末名片获取 最简单的9行代码音乐播放器如下&#xff1a; import time import pygamefile r歌曲路径 pygame.mixer.init() print(正在播放,file) track pygame.mixer.music.lo…...

零基础小白如何学会数据分析?

随着数字经济、大数据时代的发展&#xff0c;数据已然成为当下时代最重要的盈利资源&#xff0c;让企业在做决策和计划方案时更有针对性和依据&#xff0c;能提前预测市场发展方向&#xff0c;做好布局。由此而产生的数据分析岗位也逐渐被更多企业重视&#xff0c;特别是中大型…...