Mybatis【分页插件,缓存,一级缓存,二级缓存,常见缓存面试题】

news2024/11/13 15:22:03

文章目录

  • MyBatis缓存
    • 分页
    • 延迟加载和立即加载
      • 什么是立即加载?
      • 什么是延迟加载?
      • 延迟加载/懒加载的配置
    • 缓存
      • 什么是缓存?
      • 缓存的术语
      • 什么是MyBatis 缓存?
      • 缓存的适用性
      • 缓存的分类
      • 一级缓存
        • 引入案例
        • 一级缓存的配置
        • 一级缓存的工作流程
        • 一级缓存失效的情况
      • 二级缓存
        • XML实现
        • 注解实现
        • 二级缓存的缺点
    • 自定义缓存的分类
    • 总结(面试题汇总):

MyBatis缓存

分页

在Mybatis的配置文件中进行声明该插件:

<?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<properties resource="jdbc.properties"></properties>
	<typeAliases>
		<!-- 给单个类起别名 -->
		<!-- <typeAlias alias="Student" type="bean.Student"/> -->
		<!-- 批量别名定义,包扫描,别名为类名,扫描整个包下的类 -->
		<package name="bean" />
	</typeAliases>
	<!-- 分页插件 -->
	<plugins>
		<plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
	</plugins>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<!-- 注册sqlmapper文件 -->
		<!-- 1.同包 接口和sqlMapper 2.同名 接口和sqlMapper 3.sqlMapper的namespace指向接口的类路径 -->
		<!-- <mapper resource="mapper/StudentMapper.xml" /> -->
		<!-- <mapper class="mapper.StudentMapper"/> -->
		<package name="mapper" />
	</mappers>
</configuration>
	// 逻辑分页,减少对磁盘的读取,但是占用内存空间大
	@Select("select * from student")
	public List<Student> findStudentRowBounds(RowBounds rb);

	// 分页插件(推荐)
	@Select("select * from student")
	public List<Student> findStudentPageHelper();

方式1: 使用Map集合来保存分页需要数据,来进行分页

package mapper;
public interface StudentMapper {
	// 物理分页,多次读取磁盘,占用内存小
	@Select("select * from student limit #{cpage},#{size}")
	public List<Student> selectLimit(@Param("cpage") int cpage, @Param("size") int size);
}

package test;
public class Test01 {
	public static void main(String[] args) {
		SqlSession sqlSession = DaoUtil.getSqlSession();
		StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
		List<Student> list = studentMapper.selectLimit((1 - 1) * 3, 3);
		list.forEach(System.out::println);
		DaoUtil.closeSqlSession(sqlSession);
	}
}

在这里插入图片描述
方式2: 使用RowBounds集合来保存分页需要数据,来进行分页

package mapper;
public interface StudentMapper {
	// 逻辑分页,减少对磁盘的读取,但是占用内存空间大
	@Select("select * from student")
	public List<Student> findStudentRowBounds(RowBounds rb);
}
package test;
public class Test01 {
	public static void main(String[] args) {
		SqlSession sqlSession = DaoUtil.getSqlSession();
		StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
		RowBounds rb = new RowBounds((1 - 1) * 3, 3);
		List<Student> list = studentMapper.findStudentRowBounds(rb);

		list.forEach(System.out::println);
		DaoUtil.closeSqlSession(sqlSession);
	}
}

在这里插入图片描述
方式3: 使用分页插件来进行分页【推荐】

package mapper;
public interface StudentMapper {
	// 分页插件(推荐)
	@Select("select * from student")
	public List<Student> findStudentPageHelper();
}
package test;
public class Test01 {
	public static void main(String[] args) {
		SqlSession sqlSession = DaoUtil.getSqlSession();
		StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

		// PageHelper分页插件
		// (页码,每页多少个)
		// 分页第一页少做一次计算,sql语句也不同
		Page<Object> page = PageHelper.startPage(10, 1);
		// 获取page对象
		System.out.println(page);

		List<Student> list = studentMapper.findStudentPageHelper();

		// 详细分页对象
		PageInfo<Student> pageinfo = new PageInfo<Student>(list, 10);
		System.out.println(pageinfo);

		list.forEach(System.out::println);
		DaoUtil.closeSqlSession(sqlSession);
	}
}

在这里插入图片描述
在这里插入图片描述

延迟加载和立即加载

什么是立即加载?

立即加载是: 不管用不用信息,只要调用,马上发起查询并进行加载

比如: 当我们查询学生信息时,就需要知道学生在哪个班级中,所以就需要立马去查询班级的信息

通常:当 一对一或者 多对一 的时候需要立即加载

什么是延迟加载?

延迟加载是: 在真正使用数据时才发起查询,不用的时候不查询,按需加载(也叫 懒加载)

比如: 在查询班级信息,每个班级都会有很多的学生(假如每个班有100个学生),如果我们只是查看 班级信息,但是学生对象也会加载到内存中,会造成浪费。 所以我门需要进行懒加载,当确实需要查看班级中的学生信息,我门在进行加载班级中的学生信息。

通常: 一对多,或者多对多的是需要使用延迟加载

延迟加载/懒加载的配置

在这里插入图片描述
如果设置 lazyLoadingEnabled = false,则禁用延迟加载,会级联加载所有关联对象的数据

如果设置 lazyLoadingEnabled = true,默认情况下mybatis 是按层级延时加载的。

aggressiveLazyLoading = true,mybatis 是按层级延时加载 aggressiveLazyLoading = false,mybatis 按需求加载。

延迟加载的sqlmap
在这里插入图片描述

实现:

StudentMapper

@Results({ @Result(column = "classid", property = "classid"),
			@Result(column = "classid", property = "clazz", one = @One(select = "mapper.ClazzMapper.selectAll")) })
	@Select("select * from student")
	public List<Student> findStudentAndClassid();

测试类

public class Test02 {
	public static void main(String[] args) {
		SqlSession sqlSession = DaoUtil.getSqlSession();
		StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
		List<Student> list = studentMapper.findStudentAndClassid();
		Student stu = list.get(0);
		System.out.println(stu);
//		list.forEach(System.out::println);
		DaoUtil.closeSqlSession(sqlSession);
	}
}

发现这里执行了多条sql,但是我只需要List集合中第一个学生的所有数据
在这里插入图片描述
这里就需要进行懒加载!

将上面的StudentMapper改为:

// mybatis底层默认立即加载
	// FetchType.DEFAULT 从配置文件进行读取加载
	// FetchType.EAGER 立即加载
	// FetchType.LAZY 延迟加载,懒加载
	@Results({ @Result(column = "classid", property = "classid"),
			@Result(column = "classid", property = "clazz", one = @One(select = "mapper.ClazzMapper.selectAll", fetchType = FetchType.LAZY)) })
	@Select("select * from student")
	public List<Student> findStudentAndClassid();

在这里插入图片描述

就解决了查询一个Student而执行了多条SQL的问题

缓存

什么是缓存?

缓存(cache),数据交换的缓冲区,当应用程序需要读取数据时,先从数据库中将数据取出,放置在缓冲区中,应用程序从缓冲区读取数据。

在这里插入图片描述

特点:数据库取出的数据保存在内存中,具备快速读取和使用。
限制:读取时无需再从数据库获取,数据可能不是最新的;导致数据不一致性。

缓存的术语

针对缓存数据:

命中 需要的数据在缓存中找到结果。
未命中 需要的数据在缓存中未找到,重新获取。

在这里插入图片描述

什么是MyBatis 缓存?

功能 减少Java Application 与数 据库的交互次数,从而提升程 序的运行效率;
方式 通过配置和定制。

缓存的适用性

适合使用缓存: 经常查询并且不经常改变的 数据的正确与否对最终结果影响不大的 比如:一个公司的介绍,新闻等
不适合用于缓存: 经常改变的数据 数据的正确与否对最终结果影响很大 比如商品的库存,股市的牌价等

缓存的分类

在这里插入图片描述

一级缓存

将数据放在SqlSession对象中,一般默认开启一级缓存

在这里插入图片描述

引入案例

StudentMapper

@Select("select * from student where sid=#{v}")
	public Student findStudentBySid(int sid);

测试类

情况1:

SqlSession sqlSession = DaoUtil.getSqlSession();
StudentMapper stuMapper = sqlSession.getMapper(StudentMapper.class);
Student s1 = stuMapper.findStudentBySid(10);
System.out.println(s1);
System.out.println();
Student s2 = stuMapper.findStudentBySid(10);
System.out.println(s1 == s2);//true
DaoUtil.closeSqlSession(sqlSession);

在这里插入图片描述
从同一个SqlSession的一级缓存中拿的Student是同一个对象

情况2:从两个SqlSession的一级缓存中查询同一个对象,返回的不是同一个Student对象

【发生了一级缓存失效】

SqlSession sqlSession1 = DaoUtil.getSqlSession();
StudentMapper stuMapper1 = sqlSession1.getMapper(StudentMapper.class);
Student s1 = stuMapper1.findStudentBySid(10);
System.out.println(s1);
for (int i = 0; i < 100; i++) {
	System.out.print(".");
}
System.out.println();
SqlSession sqlSession2 = DaoUtil.getSqlSession();
StudentMapper stuMapper2 = sqlSession2.getMapper(StudentMapper.class);

Student s2 = stuMapper2.findStudentBySid(10);
System.out.println(s2);

System.out.println(s1 == s2);// false

在这里插入图片描述
情况3:

清空SQLSession后,查询的不是同一个Student对象

【发生了一级缓存失效】

SqlSession sqlSession = DaoUtil.getSqlSession();
StudentMapper stuMapper = sqlSession.getMapper(StudentMapper.class);
Student s1 = stuMapper.findStudentBySid(10);
System.out.println(s1);
for (int i = 0; i < 100; i++) {
	System.out.print(".");
}
System.out.println();
sqlSession.clearCache();//清空SqlSession()
Student s2 = stuMapper.findStudentBySid(10);
System.out.println(s2);
System.out.println(s1 == s2);// false
DaoUtil.closeSqlSession(sqlSession);

在这里插入图片描述
关闭sqlsession 或者清空sqlsession缓存都可以实现

注意:当调用sqlsession的修改,添加,删除,commit(),close() 等方法时, 就会清空一级缓存

一级缓存的配置

在这里插入图片描述

一级缓存的工作流程

在这里插入图片描述
在这里插入图片描述

一级缓存失效的情况

1.不同SqlSession对应不同的一级缓存
2.同一个SqlSession单查询条件不同
3.同一个SqlSession两次查询期间执行了任何一次增删改操作
4.同一个SqlSession两次查询期间手动清空了缓存

案例:

MappertStudent

@Insert("insert into student(sname) values (#{sname})")
public int addStudent(Student s);
@Select("select * from student where sid=#{v}")
public Student findStudentBySid(int sid);
package test;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import bean.Student;
import dao.DaoUtil;
import mapper.StudentMapper;

public class Test03 {
	public static void main(String[] args) {
		SqlSession sqlSession = DaoUtil.getSqlSession();
		StudentMapper stuMapper = sqlSession.getMapper(StudentMapper.class);
		Student s1 = stuMapper.findStudentBySid(10);
		System.out.println(s1);

		for (int i = 0; i < 100; i++) {
			System.out.print(".");
		}
		stuMapper.addStudent(new Student());
		System.out.println();
//		sqlSession.clearCache();//清空SqlSession()

		Student s2 = stuMapper.findStudentBySid(10);
		System.out.println(s2);

		System.out.println(s1 == s2);// false

	}
}

在这里插入图片描述
这里在两个查询之间进行了插入insert数据操作,就使一级缓存失效了,第二次查询的数据不是从缓存中拿,而是从数据库中去查询。

二级缓存

在这里插入图片描述
在这里插入图片描述

二级缓存就是在SqlSessionFactory,然后通过同一个Factory工厂,去获得相同的Cache,通过namespace去拿到对应的Student对象

XML实现

在mybatis中进行配置的参数说明:
在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

	<properties resource="jdbc.properties"></properties>
	<settings>
		<!-- 全局启用或者禁用延迟加载
		<setting name=" lazyLoadingEnabled" value="true" />
		当启用时有延迟加载属性的对象会在被调用时按需进行加载,如果设置为false,会按层级进行延迟加载,默认为true
		<setting name=" aggressiveLazyLoading" value="true" /> -->
		<setting name="cacheEnabled" value="true"/>
	</settings>
	<typeAliases>
		<!-- 给单个类起别名 -->
		<!-- <typeAlias alias="Student" type="bean.Student"/> -->
		<!-- 批量别名定义,包扫描,别名为类名,扫描整个包下的类 -->
		<package name="bean" />
	</typeAliases>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<!-- 注册sqlmapper文件 -->
		<!-- 1.同包 接口和sqlMapper 2.同名 接口和sqlMapper 3.sqlMapper的namespace指向接口的类路径 -->
		<!-- <mapper resource="mapper/StudentMapper.xml" /> -->
		<!-- <mapper class="mapper.StudentMapper"/> -->
		<package name="mapper" />
	</mappers>
</configuration>

step1:

设置为true

<settings>
		<!-- 全局启用或者禁用延迟加载
		<setting name=" lazyLoadingEnabled" value="true" />
		当启用时有延迟加载属性的对象会在被调用时按需进行加载,如果设置为false,会按层级进行延迟加载,默认为true
		<setting name=" aggressiveLazyLoading" value="true" /> -->
		<setting name="cacheEnabled" value="true"/>
 </settings>

step2:

表明这个映射文件开启了二级缓存

<cache/>

step3:

useCache="true"表明这条查询用到了二级缓存

<select id="findStudent" parameterType="int"
		resultType="student" useCache="true">
		select * from student where sid = #{value}
  </select>

在这里插入图片描述

注解实现

在这里插入图片描述
step1:

<?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

	<properties resource="jdbc.properties"></properties>
	<settings>
		<!-- 全局启用或者禁用延迟加载
		<setting name=" lazyLoadingEnabled" value="true" />
		
		<setting name=" aggressiveLazyLoading" value="true" /> -->
		<setting name="cacheEnabled" value="true"/>
	</settings>
	<typeAliases>
		<!-- 给单个类起别名 -->
		<!-- <typeAlias alias="Student" type="bean.Student"/> -->
		<!-- 批量别名定义,包扫描,别名为类名,扫描整个包下的类 -->
		<package name="bean" />
	</typeAliases>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${jdbc.driver}" />
				<property name="url" value="${jdbc.url}" />
				<property name="username" value="${jdbc.username}" />
				<property name="password" value="${jdbc.password}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<!-- 注册sqlmapper文件 -->
		<!-- 1.同包 接口和sqlMapper 2.同名 接口和sqlMapper 3.sqlMapper的namespace指向接口的类路径 -->
		<!-- <mapper resource="mapper/StudentMapper.xml" /> -->
		<!-- <mapper class="mapper.StudentMapper"/> -->
		<package name="mapper" />
	</mappers>
</configuration>

step2:

在接口前面加上@CacheNamespace(blocking = true),表示这个接口中的所有查询都是二级缓存

package mapper;
//让此处的所有内容都为二级缓存
@CacheNamespace(blocking = true)
public interface StudentMapper {
	@Select("select * from student where sid=#{v}")
	public Student findStudentBySid(int sid);
}

案例:

说明使用到了二级缓存,需要实体类实现序列化接口
在这里插入图片描述
在这里插入图片描述
序列化后的两个student对象不是同一个对象,二级缓存的数据存在磁盘上。
在这里插入图片描述

二级缓存的缺点

当数据库服务器和客户端是通过网络传输的,这里用二级缓存是为了减少由于网络环境不好加载时间。主要是为了解决数据库不在本机,且网络不稳定带来的问题,但是现在不推荐使用

1.Mybatis 的二级缓存相对于一级缓存来说, 实现了缓存数据的共享,可控性也更强;
2.极大可能会出现错误数据,有设计上的缺陷, 安全使用的条件比较苛刻;
3.分布式环境下,必然会出现读取到错误 数据,所以不推荐使用。

分布式就是同一个数据库连接多台服务器,给多个用户服务。二级缓存在分布式情况下必然会出错,二级缓存绝对不可能用。
在这里插入图片描述

但是现在基本不用,弊端如下:
在这里插入图片描述

案例完整代码:

bean.Student实体类

package bean;

import java.io.Serializable;
import java.util.Date;

public class Student implements Serializable{
	private int sid;
	private String sname;
	private Date birthday;
	private String Ssex;
	private int classid;
	private Clazz clazz;

	public int getSid() {
		return sid;
	}

	public void setSid(int sid) {
		this.sid = sid;
	}

	public String getSname() {
		return sname;
	}

	public void setSname(String sname) {
		this.sname = sname;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public String getSsex() {
		return Ssex;
	}

	public void setSsex(String ssex) {
		Ssex = ssex;
	}

	public int getClassid() {
		return classid;
	}

	public void setClassid(int classid) {
		this.classid = classid;
	}

	public Clazz getClazz() {
		return clazz;
	}

	public void setClazz(Clazz clazz) {
		this.clazz = clazz;
	}

	public Student(int sid, String sname, Date birthday, String ssex, int classid, Clazz clazz) {
		super();
		this.sid = sid;
		this.sname = sname;
		this.birthday = birthday;
		Ssex = ssex;
		this.classid = classid;
		this.clazz = clazz;
	}

	public Student() {
		super();
	}

	@Override
	public String toString() {
		return "Student [sid=" + sid + ", sname=" + sname + ", birthday=" + birthday + ", Ssex=" + Ssex + ", classid="
				+ classid + ", clazz=" + clazz + "]";
	}
}

Daoutil工具类

package dao;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class DaoUtil {
	static SqlSessionFactory factory = null;
	static {
		try {
			// 1.读取配置文件
			InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
			// 2.生产sqlSession的工厂
			factory = new SqlSessionFactoryBuilder().build(is);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static SqlSession getSqlSession() {
		// 3.返回sqlSession对象
		return factory.openSession();
	}

	public static void closeSqlSession(SqlSession sqlSession) {
		// 4.释放资源
		sqlSession.close();
	}
}

StudentMapper

package mapper;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.One;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.jdbc.SQL;
import org.apache.ibatis.mapping.FetchType;
import org.apache.ibatis.session.RowBounds;

import bean.Student;

//让此处的所有内容都为二级缓存
@CacheNamespace(blocking = true)
public interface StudentMapper {
	@Insert("insert into student(sname) values (#{sname})")
	public int addStudent(Student s);
	
	// 物理分页,多次读取磁盘,占用内存小
	@Select("select * from student limit #{cpage},#{size}")
	public List<Student> selectLimit(@Param("cpage") int cpage, @Param("size") int size);

	// 逻辑分页,减少对磁盘的读取,但是占用内存空间大
	@Select("select * from student")
	public List<Student> findStudentRowBounds(RowBounds rb);

	// 分页插件(推荐)
	@Select("select * from student")
	public List<Student> findStudentPageHelper();

	// mybatis底层默认立即加载
	// FetchType.DEFAULT 从配置文件进行读取加载
	// FetchType.EAGER 立即加载
	// FetchType.LAZY 延迟加载,懒加载
	@Results({ @Result(column = "classid", property = "classid"),
			@Result(column = "classid", property = "clazz", one = @One(select = "mapper.ClazzMapper.selectAll", fetchType = FetchType.LAZY)) })
	@Select("select * from student")
	public List<Student> findStudentAndClassid();

	@Select("select * from student where sid=#{v}")
	public Student findStudentBySid(int sid);
}

测试类

package test;

import org.apache.ibatis.session.SqlSession;

import bean.Student;
import dao.DaoUtil;
import mapper.StudentMapper;

public class Test04 {
	public static void main(String[] args) {
		SqlSession sqlSession1 = DaoUtil.getSqlSession();
		StudentMapper stuMapper1 = sqlSession1.getMapper(StudentMapper.class);
		Student s1 = stuMapper1.findStudentBySid(10);
		System.out.println(s1);
		DaoUtil.closeSqlSession(sqlSession1);

		SqlSession sqlSession2 = DaoUtil.getSqlSession();
		StudentMapper stuMapper2 = sqlSession2.getMapper(StudentMapper.class);
		Student s2 = stuMapper2.findStudentBySid(10);
		System.out.println(s1);
		DaoUtil.closeSqlSession(sqlSession2);
	}
}

自定义缓存的分类

在这里插入图片描述

总结(面试题汇总):

一级缓存和二级缓存的区别:

一级缓存指的是一个对象存到了SqlSession里面了,它是内存式的缓存,写在内存上的

二级缓存指的是缓存在SqlSessionFactory里面了,它是写在磁盘上的

二级缓存不用的原因:

分布式环境下,必然会出现读取到错误 数据,所以不推荐使用。

分页查询

什么是缓存

​ • 数据交换的缓冲区,当应用程序需要读取数据时,先从数据库中将数据取出,放置在缓冲区中,应用程序从缓冲区读取数据;

什么是一级缓存

​ • 相对同一个 SqlSession 对象而言的缓存;

什么是二级缓存

​ • 一个 namespace 下的所有操作语句,都影响着同一个Cache;

自定义缓存的方式

​ • 实现 org. apache. ibatis. cache. Cache 接口自定义缓存;

​ • 引入 Redis 等第三方内存库作为 MyBatis 缓存。
补充:
缓存击穿、雪崩、穿透
缓存击穿、雪崩、穿透

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

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

相关文章

《OpenCV计算机视觉》—— 图像形态学(腐蚀、膨胀等)

文章目录 一、图像形态学基本概念二、基本运算1.简单介绍2.代码实现 三、高级运算1.简单介绍2.代码实现 一、图像形态学基本概念 图像形态学是图像处理科学的一个独立分支&#xff0c;它基于集合论和数学形态学的理论&#xff0c;专门用于分析和处理图像中的形状和结构。图像形…

分贝通助力元气森林企业支出一体化降本提效

凭借着“0糖0脂0卡”这句广告语,元气森林几乎是一锤砸中了年轻消费者的内心,让“好喝不胖”深入人心,成为了国内饮品消费的新风向标。如果我们从近两年的快消饮品中选出几款深受消费者喜爱的“国货品牌”的话,相信「元气森林」一定上榜。 元气森林成立于2016年,旗下拥有元气森林…

深入理解并实现——快排【C语言版】

目录 一、快排介绍及其思想 二、hoare版本 三、前后指针版 四、挖坑法 五、优化版本 5.1 三数取中 5.2 小区间优化 六 、非递归实现快排 七、三路划分 八、introsort 小结 一、快排介绍及其思想 快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一…

【数据结构】Map的使用与注意事项

文章目录 概念模型Map 的使用put() 和 get()getOrDefault()remove()keySet()entrySet() 注意事项 概念 Map 和 set 是一种专门用来进行搜索的容器或者数据结构&#xff0c;其搜索的效率与其具体的实例化子类有关。 以前常见的搜索方式有&#xff1a; 直接遍历&#xff0c;时间…

Spring AOP(下)原理

本文我们来学习 Spring AOP 的原理&#xff0c;也就是 Spring 是如何实现 AOP 的。Spring AOP 是基于动态代理来实现 AOP 的&#xff1b; 1. 代理模式 1.1 代理弄模式的定义 代理模式&#xff0c;也叫委托模式。 定义&#xff1a;为其他对象提供一种代理以控制这个对象的访问…

【第三版 系统集成项目管理工程师】第14章 收尾过程组

持续更新。。。。。。。。。。。。。。。 【第三版】第十四章 收尾过程组 14.1结束项目或阶段14.1.1主要输入1.项目章程-P5392.项目管理计划-P5393.项目文件-P5394.验收的可交付成果-P5405.协议-P5406.采购文档-P540 14.1.2主要输出1.最终产品、服务或成果-P5402.项目最终报告…

如何在IntelliJ IDEA中将Tab设置为4个空格

前言 IntelliJ IDEA是一个强大的开发工具&#xff0c;支持多种编程语言。为了保持代码整洁一致&#xff0c;开发者经常需要调整编辑器中的Tab和缩进设置。 步骤1: 打开设置 首先&#xff0c;启动IntelliJ IDEA。在主界面上方的菜单栏中找到 File&#xff08;文件&#xff09…

体育直播平台开发:初创公司突破资金与市场的双重挑战

在当今竞争激烈的数字娱乐行业中&#xff0c;体育直播平台的发展潜力巨大。然而&#xff0c;面对如此巨大的蓝海市场&#xff0c;对于初创公司或中小型平台而言&#xff0c;高昂的开发和运营成本可能成为进入该行业的主要障碍。本文将探讨一些可行的低成本开发策略&#xff0c;…

Matlab三维图的坐标轴标签 自动平行坐标/自动旋转

下载解压工具包&#xff1a; https://www.mathworks.com/matlabcentral/fileexchange/49542-phymhan-matlab-axis-label-alignment 添加至MATLAB路径: 在三维绘图后增加下列语句即可 ax struct(Axes, gca); align_axislabel([],ax) h3d rotate3d; set(h3d,ActionPreCa…

k8s项目的发布(金丝雀发布)

目录 三种发布方式 1.蓝绿发布 2.金丝雀发布&#xff08;灰度发布&#xff09; 实验&#xff1a;k8s实现金丝雀发布 3.滚动发布&#xff08;默认形式&#xff09; 因为应用升级以及新旧业务切换&#xff0c;所以在这个过程当中如何保证对外的服务正常是一个非常重要的问题…

/单元测试

承接上文 统一异常处理&#xff0c;封装结果-CSDN博客 ******************************************** 登录业务 Service public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {Resourceprivate JwtUtils j…

深入探索批处理中的变量与命令:从基础到高级

更多内容前往&#xff1a;孔乙己大叔 在Windows环境中&#xff0c;批处理&#xff08;Batch&#xff09;文件是一种非常有用的脚本工具&#xff0c;允许用户自动化重复性任务。通过编写批处理脚本&#xff0c;用户可以执行一系列命令&#xff0c;而无需手动输入每个命令。变量是…

怎么把视频压缩变小?快码住这篇视频压缩教程

众所周知&#xff0c;视频已经成为人们交流信息的重要方式之一。 然而&#xff0c;随着视频分辨率越来越高&#xff0c;文件大小也随之膨胀&#xff0c;这给存储空间带来了不小的压力&#xff0c;同时也影响了视频在网络上的传输速度。 因此&#xff0c;掌握视频压缩技巧&…

E1.S接口如何解决SSD过热问题?

针对SSD接口标准&#xff0c;目前业内有两大组织&#xff1a; PCI-SIG&#xff1a;这个就是定义pcie协议标准的那个组织&#xff0c;我们常见的传统接口M.2, U.2, 2.5英寸的接口都归这个组织定义规范。M.2&#xff0c;U.2起源与客户端&#xff0c;也是企业级当前最常用的接口形…

Day22_K8S

文章目录 3.资源管理方式通过命令管理通过配置文件管理4. 基本概念入门4.1 Namespace4.2 Pod4.3 Label4.4 Deployment4.5 Service5. Pod详解5.1 Pod介绍5.2 Pod配置5.3 Pod生命周期5.3.1 初始化容器5.3.2 钩子函数5.3.3 容器探测5.3.4 重启策略5.4 Pod调度5.4.1 定向调度5.4.2 …

【技巧】Excel检查单元格的值是否在另一列中

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 用到的excel函数 IF(ISNUMBER(MATCH(H2, I2:I10, 0)), H2, "") 注意改上面的“H2、I2、I10”&#xff01; 函数效果 函数解释 检查单元格 …

简述二叉树先序遍历、中序遍历和后序遍历的思想。

先序遍历&#xff08;根左右&#xff09;(DLR) 若二叉树为空&#xff0c;则退出&#xff0c;否则进行下面操作:访问根结点、先序遍历左子树、先序遍历右子树。 中序遍历&#xff08;左根右&#xff09;(LDR) 若二叉树为空&#xff0c;则退出&#xff0c;否则进行下面操作:中…

Nginx: 配置文件重载的原理和热部署

配置文件的重载原理 我们可以通过给Nginx的master进程发送 HUP 信号, 或者是使用Nginx的二进制程序 执行 reload命令来重新载入配置文件, 从而实现Nginx的一个平滑升级对Nginx的背后到底是发生了一个什么样的事情去保证新老配置的平滑过渡的 reload 重载配置文件的流程 第一步…

Amazon SPAPI Deloitte(德勤)审计问题流程

作为Amazon开发者审计的一部分&#xff0c;亚马逊会对使用其API的开发者进行严格的审核和评估。 这个过程旨在确保开发者遵守亚马逊的各项政策和安全要求&#xff0c;特别是在处理个人身份信息&#xff08;PII&#xff09;和其他敏感数据时。 下面是一些关于亚马逊开发者审计的…

【Python 千题 —— 算法篇】逆序字符串

Python 千题持续更新中 …… 脑图地址 👉:⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目背景 字符串操作在编程中非常常见,无论是数据处理、文本分析还是算法设计,字符串的处理都是基础且关键的一部分。尤其是在数据处理和编程竞赛中,字符串逆序是…