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

mybatis分页实现总结

1.mybatis拦截器相关知识

1.作用

mybatis的拦截器是mybatis提供的一个拓展机制,允许用户在使用时根据各自的需求对sql执行的各个阶段进行干预。比较常见的如对执行的sql进行监控,排查sql的执行时间,对sql进行拦截拼接需要的场景,对最终结果进行如加密等处理。

2.拦截器分类

mybatis提供了四种拦截器供使用,按拦截的执行顺序展示
Executor->StatementHandler->ParameterHandler->ResultHandler

/*
用途:拦截执行器的方法,
可以用来修改执行sql的操作(query,update)
对事务进行操作(commit,rollback,getTransaction),
开启缓存(createCacaheKey,isCached),看方法上注释
*/
public interface Executor {ResultHandler NO_RESULT_HANDLER = null;// 执行insert update delete操作int update(MappedStatement var1, Object var2) throws SQLException;// 执行query操作<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException;<E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;<E> Cursor<E> queryCursor(MappedStatement var1, Object var2, RowBounds var3) throws SQLException;List<BatchResult> flushStatements() throws SQLException;// 提交事务void commit(boolean var1) throws SQLException;// 回滚事务void rollback(boolean var1) throws SQLException;CacheKey createCacheKey(MappedStatement var1, Object var2, RowBounds var3, BoundSql var4);boolean isCached(MappedStatement var1, CacheKey var2);void clearLocalCache();void deferLoad(MappedStatement var1, MetaObject var2, String var3, CacheKey var4, Class<?> var5);// 获取事务Transaction getTransaction();// 关闭事务void close(boolean var1);// 判断事务是否关闭boolean isClosed();void setExecutorWrapper(Executor var1);
}
/**
用途: 拦截sql执行的语句
*/
public interface StatementHandler {// sql预编译拦截,在这个阶段可以修改sql执行的语句Statement prepare(Connection var1, Integer var2) throws SQLException;// 设置参数时拦截void parameterize(Statement var1) throws SQLException;void batch(Statement var1) throws SQLException;// 进行insert,update,delete的sql执行前进行拦截int update(Statement var1) throws SQLException;// 进行query的sql执行前进行拦截<E> List<E> query(Statement var1, ResultHandler var2) throws SQLException;<E> Cursor<E> queryCursor(Statement var1) throws SQLException;BoundSql getBoundSql();ParameterHandler getParameterHandler();
}
/**
用途: 拦截sql语句的参数设置
*/
public interface ParameterHandler {// 获取设置的参数(注意使用这个的时候最好和@param注解合用指定具体名,不然只能按顺序去获取,没有具体名)Object getParameterObject();// 设置sql的参数void setParameters(PreparedStatement var1) throws SQLException;
}
/**
用途:对执行完后返回的结果进行拦截
*/
public interface ResultSetHandler {// 最常用的返回拦截<E> List<E> handleResultSets(Statement var1) throws SQLException;<E> Cursor<E> handleCursorResultSets(Statement var1) throws SQLException;void handleOutputParameters(CallableStatement var1) throws SQLException;
}

2.定义拦截器的相关注解@Intercepts与@Signature

// 用于指定该拦截器是拦截哪个环节的注解,可以配置多个
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Intercepts {Signature[] value();
}
// 指定具体的拦截环节
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {// 即上面的四种拦截器:Executor,StatementHandler,ParameterHandler,ResultHandler Class<?> type();// 上面四种拦截器中的方法名,如指定的是StatementHandler,你需要具体到方法上,可以选择填写queryString method();// method指定方法上的形参,如按query将两个参数的类对象写好即可Class<?>[] args();
}

2.使用SQL_CALC_FOUND_ROWS和found_rows()进行分页

1.直接按要求实现

a.在配置mysql的url处开启返回多个结果集:allowMultiQueries=true

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: rooturl: jdbc:mysql://192.168.175.155:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false&allowMultiQueries=true

b.编写mapper

// 注意要接收多个结果,所以需要List不指定泛型
List select2(@Param("pageNum") int pageNum, @Param("pageSize") int pageSize);

c.编写xml的sql

	<!-- 实体和字段的映射配置 --><resultMap id="BaseResultMap" type="com.example.demo.pagehelper.User"><id column="id" jdbcType="BIGINT" property="id"/><result column="name" jdbcType="VARCHAR" property="name"/><result column="age" jdbcType="BIGINT" property="age"/></resultMap><!-- 总行数的配置 --><resultMap id="recordCounts" type="java.lang.Integer"><result column="recordCounts" jdbcType="BIGINT"/></resultMap><select id="select2" resultMap="BaseResultMap, recordCounts">select SQL_CALC_FOUND_ROWS * from user limit #{pageNum}, #{pageSize};SELECT found_rows() AS recordCounts;</select>

d.返回结果的处理

  List<Object> lists = userMapper.select2(1,3);// 获取分页的数据List<User> users = (List<User>) lists.get(0);// 获取查询的总数List<Integer> nums = (List<Integer>) lists.get(1);Integer count = nums.get(0);

总结:
1.sql在写的时候都需要拼接SQL_CALC_FOUND_ROWS和SELECT found_rows() AS recordCounts;
2.处理结果时很麻烦一直强转再分别获取

2.使用自定义拦截器对上述实现进行一定程度优化(思路仅供参考)

a.定义两个拦截器:一个拦截sql执行,一个拦截结果处理

/*** @description: 在准备阶段对sql进行拦截,并处理结果* @author: zengwenbo* @date: 2024/4/11 18:22*/
@Intercepts(value = {@Signature(type = StatementHandler.class, method="prepare", args = {Connection.class, Integer.class} )
})
@Component
public class PagingInterceptor implements Interceptor {private static final String PAGE_NUM = "pageNum";private static final String PAGE_SIZE = "pageSize";private static final String SQL_CALC_FOUND_ROWS = "sql_calc_found_rows";private static final String FOUND_ROWS = "found_rows()";private static final String SEMICOLON = ";";@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler target = (StatementHandler) invocation.getTarget();// 借助metaObject来修改执行的sqlMetaObject metaObject= SystemMetaObject.forObject(target);BoundSql boundSql = target.getBoundSql();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();String sql = boundSql.getSql();// 只处理查询语句if (sql != null && sql.toLowerCase().trim().startsWith("select ")) {// 获取传递的参数所有名称List<String> paramsName = parameterMappings.stream().filter(item -> ParameterMode.IN.equals(item.getMode())).map(ParameterMapping::getProperty).collect(Collectors.toList());// 根据参数名称里面是否有指定两个参数来判断是否需要分页if (paramsName.contains(PAGE_NUM) && paramsName.contains(PAGE_SIZE)) {// 需要分页则对sql进行处理metaObject.setValue("delegate.boundSql.sql", dealSql(sql));} else {metaObject.setValue("delegate.boundSql.sql", sql);}}return invocation.proceed();}@Overridepublic Object plugin(Object o) {return Plugin.wrap(o, this);}@Overridepublic void setProperties(Properties properties) {}/*** 拼接需要的分页sql语句* @param oldSql* @return*/private String dealSql(String oldSql) {if (oldSql.toLowerCase().contains(SQL_CALC_FOUND_ROWS) || oldSql.toLowerCase().contains(FOUND_ROWS)) {return oldSql;}oldSql = oldSql.toLowerCase().replace("select ", "select SQL_CALC_FOUND_ROWS ");if(!oldSql.trim().endsWith(SEMICOLON)) {oldSql = oldSql.concat(SEMICOLON);}return oldSql.concat("select found_rows() AS recordCounts;");}
}
/*** @description: 对分页结果数据进行处理* @author: zengwenbo* @date: 2024/4/12 18:37*/
@Intercepts(value = {@Signature(type = ResultSetHandler.class, method="handleResultSets", args = {Statement.class} )
})
@Component
public class PagingResultInterceptor implements Interceptor {private static final String SQL_CALC_FOUND_ROWS = "sql_calc_found_rows";private static final String FOUND_ROWS = "found_rows()";@Overridepublic Object intercept(Invocation invocation) throws Throwable {Object proceed = invocation.proceed();DefaultResultSetHandler target = (DefaultResultSetHandler) invocation.getTarget();// 借助metaObject来获取执行的sqlMetaObject metaObject= SystemMetaObject.forObject(target);BoundSql boundSql = (BoundSql) metaObject.getValue("boundSql");String sql = boundSql.getSql();// 执行的是分页,则需要封装返回需要的对象if (null != sql && sql.toLowerCase().contains(SQL_CALC_FOUND_ROWS) && sql.toLowerCase().contains(FOUND_ROWS)) {if (proceed instanceof List) {List<Object> result = (List) proceed;if (result.size() == 2) {Object res1 = result.get(0);Object res2 = result.get(1);if (res1 instanceof List && res2 instanceof List) {List<Object> result1 = (List) res1;List<Object> result2 = (List) res2;MyPage<Object> page = new MyPage<>();page.setTotal((Integer) result2.get(0));page.addAll(result1);return page;}}}}return proceed;}
}
/*** @description: 封装分页数据对象* @author: zengwenbo* @date: 2024/4/11 20:14*/
@Data
public class MyPage<E> extends ArrayList<E> {private int total; // 总行数
}

b.编写mapper

// 注意上面对sql拦截需要用到pageNum和pageSize,所以这两个参数不能丢,必须用@Param注解绑定名
// MyPage来接收上面的分页返回结果
MyPage<User> select3(@Param("pageNum") int pageNum, @Param("pageSize") int pageSize);

c.编写xml的sql

    <resultMap id="BaseResultMap" type="com.example.demo.pagehelper.User"><id column="id" jdbcType="BIGINT" property="id"/><result column="name" jdbcType="VARCHAR" property="name"/><result column="age" jdbcType="BIGINT" property="age"/></resultMap><resultMap id="recordCounts" type="java.lang.Integer"><result column="recordCounts" jdbcType="BIGINT"/></resultMap><!-- 正常的写分页sql即可 --><select id="select3" resultMap="BaseResultMap, recordCounts">select * from user limit #{pageNum}, #{pageSize};</select>

d.返回结果的处理

// 直接获取结果数据
List<User> lists = userMapper.select3(1,3);
// 总数需要转换下
int total = ((MyPage<User>) lists).getTotal();

3.使用PageHelper第三方插件来进行分页

1.实现过程

a.导包

        <dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>1.4.1</version></dependency>

b.mapper和xmlsql的编写

    @Select("select * from user")List<User> select1();

c.调用处和结果的处理

// 调用前设置当前页和当前页数据大小PageHelper.startPage(1,3);List<User> lists = userMapper.select1();// 借助PageInfo来获取总数PageInfo<User> userPageInfo = new PageInfo<>(lists);long total = userPageInfo.getTotal();

2.实现原理

1.PageHelper.startPage(1,3):将pagNum和pageSize通过ThreadLocal存储起来;

    public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {Page<E> page = new Page(pageNum, pageSize, count);page.setReasonable(reasonable);page.setPageSizeZero(pageSizeZero);Page<E> oldPage = getLocalPage();if (oldPage != null && oldPage.isOrderByOnly()) {page.setOrderBy(oldPage.getOrderBy());}// 核心代码:将page对象存储到ThreadLocal中进行线程隔离setLocalPage(page);return page;}

2.自定义一个拦截器对相关实现进行拦截PageInterceptor,该拦截器实现分页的方式是进行了两次sql的执行,第一次组sql查询出总数,再按参数修改原sql进行分页,然后将数据封装成Page对象,最后将TreadLocal里面的参数进行移除。代码中有标出,追代码可以看如何操作的。

@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
public class PageInterceptor implements Interceptor {private static final Log log = LogFactory.getLog(PageInterceptor.class);private volatile Dialect dialect;private String countSuffix = "_COUNT";protected Cache<String, MappedStatement> msCountMap = null;private String default_dialect_class = "com.github.pagehelper.PageHelper";public PageInterceptor() {String bannerEnabled = System.getProperty("pagehelper.banner");if (StringUtil.isEmpty(bannerEnabled)) {bannerEnabled = System.getenv("PAGEHELPER_BANNER");}if (StringUtil.isEmpty(bannerEnabled) || Boolean.parseBoolean(bannerEnabled)) {log.debug("\n\n,------.                           ,--.  ,--.         ,--.                         \n|  .--. '  ,--,--.  ,---.   ,---.  |  '--'  |  ,---.  |  |  ,---.   ,---.  ,--.--. \n|  '--' | ' ,-.  | | .-. | | .-. : |  .--.  | | .-. : |  | | .-. | | .-. : |  .--' \n|  | --'  \\ '-'  | ' '-' ' \\   --. |  |  |  | \\   --. |  | | '-' ' \\   --. |  |    \n`--'       `--`--' .`-  /   `----' `--'  `--'  `----' `--' |  |-'   `----' `--'    \n                   `---'                                   `--'                        is intercepting.\n");}}public Object intercept(Invocation invocation) throws Throwable {try {Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement)args[0];Object parameter = args[1];RowBounds rowBounds = (RowBounds)args[2];ResultHandler resultHandler = (ResultHandler)args[3];Executor executor = (Executor)invocation.getTarget();CacheKey cacheKey;BoundSql boundSql;if (args.length == 4) {boundSql = ms.getBoundSql(parameter);cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);} else {cacheKey = (CacheKey)args[4];boundSql = (BoundSql)args[5];}this.checkDialectExists();if (this.dialect instanceof Chain) {boundSql = ((Chain)this.dialect).doBoundSql(Type.ORIGINAL, boundSql, cacheKey);}List resultList;if (!this.dialect.skip(ms, parameter, rowBounds)) {if (this.dialect.beforeCount(ms, parameter, rowBounds)) {// 1.组sql获取总数的地方Long count = this.count(executor, ms, parameter, rowBounds, (ResultHandler)null, boundSql);if (!this.dialect.afterCount(count, parameter, rowBounds)) {Object var12 = this.dialect.afterPage(new ArrayList(), parameter, rowBounds);return var12;}}// 2.修改原sql进行分页查询并返回分页结果resultList = ExecutorUtil.pageQuery(this.dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);} else {resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);}// 3.组装Page对象进行返回Object var16 = this.dialect.afterPage(resultList, parameter, rowBounds);return var16;} finally {if (this.dialect != null) {// 4.核心是移除最开始设置到Threadlocal里面的参数this.dialect.afterAll();}}}private void checkDialectExists() {if (this.dialect == null) {String var1 = this.default_dialect_class;synchronized(this.default_dialect_class) {if (this.dialect == null) {this.setProperties(new Properties());}}}}private Long count(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {String countMsId = ms.getId() + this.countSuffix;MappedStatement countMs = ExecutorUtil.getExistedMappedStatement(ms.getConfiguration(), countMsId);Long count;if (countMs != null) {count = ExecutorUtil.executeManualCount(executor, countMs, parameter, boundSql, resultHandler);} else {if (this.msCountMap != null) {countMs = (MappedStatement)this.msCountMap.get(countMsId);}if (countMs == null) {countMs = MSUtils.newCountMappedStatement(ms, countMsId);if (this.msCountMap != null) {this.msCountMap.put(countMsId, countMs);}}count = ExecutorUtil.executeAutoCount(this.dialect, executor, countMs, parameter, boundSql, rowBounds, resultHandler);}return count;}public Object plugin(Object target) {return Plugin.wrap(target, this);}public void setProperties(Properties properties) {this.msCountMap = CacheFactory.createCache(properties.getProperty("msCountCache"), "ms", properties);String dialectClass = properties.getProperty("dialect");if (StringUtil.isEmpty(dialectClass)) {dialectClass = this.default_dialect_class;}try {Class<?> aClass = Class.forName(dialectClass);this.dialect = (Dialect)aClass.newInstance();} catch (Exception var4) {throw new PageException(var4);}this.dialect.setProperties(properties);String countSuffix = properties.getProperty("countSuffix");if (StringUtil.isNotEmpty(countSuffix)) {this.countSuffix = countSuffix;}}
}

因此可以看出使用PageHelper时,在用PageHelper调用startPage设置参数后,中间必须要紧跟当前的查询语句,如果两者之间存在其他的查询语句就会出问题,这点在使用时需要注意。

4.使用Mybatis-plus封装来进行分页

参考链接:mybatis-plus实现分页
其实现过程和pageHelper差不多,也是先算出总数在执行原sql

相关文章:

mybatis分页实现总结

1.mybatis拦截器相关知识 1.作用 mybatis的拦截器是mybatis提供的一个拓展机制&#xff0c;允许用户在使用时根据各自的需求对sql执行的各个阶段进行干预。比较常见的如对执行的sql进行监控&#xff0c;排查sql的执行时间&#xff0c;对sql进行拦截拼接需要的场景&#xff0c…...

Vue3——html-doc-js(html导出为word的js库)

一、下载 官方地址 html-doc-js - npm npm install html-doc-js 二、使用方法 // 使用页面中引入 import exportWord from html-doc-js// 配置项以及实现下载方法 const wrap document.getElementById(test)const config {document:document, //默认当前文档的document…...

第19天:信息打点-小程序应用解包反编译动态调试抓包静态分析源码架构

第十九天 本课意义 1.如何获取到目标小程序信息 2.如何从小程序中提取资产信息 一、Web&备案信息&单位名称中发现小程序 1.国内主流小程序平台 微信 百度 支付宝 抖音头条 2.小程序结构 1.主体结构 小程序包含一个描述整体程序的app和多个描述各自页面的page …...

外观模式:简化复杂系统的统一接口

在面向对象的软件开发中&#xff0c;外观模式是一种常用的结构型设计模式&#xff0c;旨在为复杂的系统提供一个简化的接口。通过创建一个统一的高级接口&#xff0c;这个模式帮助客户端通过一个简单的方式与复杂的子系统交互。本文将详细介绍外观模式的定义、实现、应用场景以…...

PHP数组去重

public function array_unique_key($arr,$key) {$tmp_arrarray();foreach($arr as $k > $v){if(in_array($v[$key],$tmp_arr)){ //判断是否重复unset($arr[$k]); //重复则删除}else{$tmp_arr[]$v[$key]; //将值存储在临时数组中}}return $arr; } public function array…...

论软件系统的架构风格,使用三段论 写一篇系统架构师论文

软件系统的架构风格是指在软件系统设计与开发过程中&#xff0c;采用的一组相互协调的设计原则、模式和实践。这些风格不仅影响着系统的技术实现&#xff0c;还关乎到系统的可维护性、可扩展性和可靠性等关键质量属性。通过三段论的结构&#xff0c;本文旨在探讨软件系统架构风…...

深度挖掘响应式模式的潜力,从而精准优化AI与机器学习项目的运行效能,引领技术革新潮流

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f525; 转载自热榜文章&#xff1a;探索设计模式的魅力&#xff1a;深度挖掘响应式模式的…...

企业级网络安全:入侵防御实时阻止,守护您的业务安全

随着互联网技术的快速发展&#xff0c;企业级网络安全问题日益凸显。在这个数字化时代&#xff0c;企业的业务安全不仅关系到企业的形象和声誉&#xff0c;还直接影响到企业的生存和发展。因此&#xff0c;加强企业级网络安全&#xff0c;预防和抵御各种网络攻击已成为企业的重…...

(一)Java八股——Redis

1 Redis缓存 1.1 什么是缓存穿透 ? 怎么解决 ?&#xff08;穿透&#xff09; ​ 缓存穿透是指查询一个一定不存在的数据&#xff0c;如果从存储层查不到数据则不写入缓存&#xff0c;这将导致这个不存在的数据每次请求都要到 DB 去查询&#xff0c;可能导致 DB 挂掉。这种情…...

2024.4.15力扣每日一题——设计哈希映射

2024.4.15 题目来源我的题解方法一 链表自定义哈希函数 题目来源 力扣每日一题&#xff1b;题序&#xff1a;706 我的题解 方法一 链表自定义哈希函数 使用链表存储每个<key,value>。由于题目有限制put的次数不超过10000次&#xff0c;因此对于哈希函数的设计为&#…...

数据结构DAY4--哈希表

哈希表 概念&#xff1a;相当于字典&#xff0c;可以根据数据的关键字来寻找相关数据的查找表。 步骤&#xff1a;建立->插入->遍历->查找->销毁 建立 建立数据&#xff0c;形式随意&#xff0c;但一般为结构体&#xff08;储存的数据量大&#xff09;&#xff…...

MySQL二阶段和三阶段提交

在分布式系统中&#xff0c;事务管理是一个至关重要的方面。MySQL作为一种常用的关系型数据库管理系统&#xff0c;提供了二阶段提交&#xff08;Two-Phase Commit&#xff0c;2PC&#xff09;和三阶段提交&#xff08;Three-Phase Commit&#xff0c;3PC&#xff09;等协议来支…...

代码随想录算法训练营第四十二天|01背包问题、416. 分割等和子集

动态规划 文章目录 一、01背包问题二、分割等和子集总结 一、01背包问题 1.在有限的背包内放入最高价值的东西 2.二维数据和一维数据都可以解决 3.二维数据&#xff0c;递推公式为dp[i][j] max(dp[i-1][j], dp[i-1][j-weight[i]]value[i])&#xff0c;分为两个状态&#xff0…...

JVM主要知识点详解

目录 1. 性能监控和调优 1.1 调优相关参数 1.2 内存泄漏排查 1.3 cpu飙⾼ 2. 内存与垃圾回收 2.1JVM的组成&#xff08;面试题&#xff09; 2.2 Java虚拟机栈的组成 2.3 本地方法栈 2.4 堆 2.5 方法区&#xff08;抽象概念&#xff09; 2.5.1 方法区和永久代以及元空…...

hot100 -- 链表(中)

不要觉得力扣核心代码模式麻烦&#xff0c;它确实比不上ACM模式舒服&#xff0c;可以自己处理输入输出 只是你对 链表 和 return 的理解不到位 &#x1f442; ▶ 屿前世 (163.com) &#x1f442; ▶ see you tomorrow (163.com) 目录 &#x1f382;两数相加 &#x1f6a9;删…...

数据结构面试常见问题

数据结构是计算机科学中非常重要的一部分&#xff0c;也是面试中经常被考察的内容。以下是一些在数据结构面试中常见的问题&#xff1a; 1. 数组 (Array): 描述数组和链表的区别。如何在数组中实现循环队列&#xff1f;给定一个数组&#xff0c;如何找到两个数的和等于给定值…...

蓝桥杯2024年第十五届省赛真题-R 格式(高精度乘法 + 加法)

本题链接&#xff1a;蓝桥杯2024年第十五届省赛真题-R 格式 - C语言网 题目&#xff1a;​​​​​​​ 样例&#xff1a; 输入 2 3.14 输出 13 思路&#xff1a; 根据题意&#xff0c;结合数据范围&#xff0c;这是一道模板的高精度乘以低精度问题。 题意是double 类型 d 与…...

普通人做抖音小店真的能赚钱吗?可以,但更取决于个人

大家好&#xff0c;我是电商花花。 现在做抖音小店的基本上都是一些新商家&#xff0c;对于我们众多零基础的朋友来说&#xff0c;是期待也是一份挑战。 抖音小店作为一个充满机会的新兴平台&#xff0c;许多人都欣喜的投入其中&#xff0c;期望能够借此来改变自己的命运&…...

基于单链表实现通讯管理系统!(有完整源码!)

​ 个人主页&#xff1a;秋风起&#xff0c;再归来~ 文章专栏&#xff1a;C语言实战项目 个人格言&#xff1a;悟已往之不谏&#xff0c;知来者犹可追 克心守己&#xff0c;律己则安&#xff01; 1、前言 友友们&#xff0c;这篇文章是基于单链…...

MATLAB入门介绍

MATLAB是由MathWorks公司开发的一款专业的数学计算软件&#xff0c;主要用于算法开发、数据可视化、数据分析以及数值计算等领域。它提供了一个易于使用的环境&#xff0c;让用户可以通过矩阵计算、函数和数据绘图、用户界面的创建以及编程和文档编写来解决各种数学问题。 MATL…...

【k8s】:深入理解 Kubernetes 中的污点(Taints)与容忍度(Tolerations)

【k8s】&#xff1a;深入理解 Kubernetes 中的污点&#xff08;Taints&#xff09;与容忍度&#xff08;Tolerations&#xff09; 1、污点&#xff08;Taints&#xff09;2、容忍度&#xff08;Tolerations&#xff09;3、示例演示-测试污点的具体应用场景3.1 给节点打污点&…...

Angular 使用DomSanitizer防范跨站脚本攻击

跨站脚本Cross-site scripting 简称XSS&#xff0c;是代码注入的一种&#xff0c;是一种网站应用程序的安全漏洞攻击。它允许恶意用户将代码注入到网页上&#xff0c;其他用户在使用网页时就会收到影响&#xff0c;这类攻击通常包含了HTML和用户端脚本语言&#xff08;JS&…...

(八)PostgreSQL的数据库管理

PostgreSQL的数据库管理 基础信息 OS版本&#xff1a;Red Hat Enterprise Linux Server release 7.9 (Maipo) DB版本&#xff1a;16.2 pg软件目录&#xff1a;/home/pg16/soft pg数据目录&#xff1a;/home/pg16/data 端口&#xff1a;57771 创建数据库 CREATE DATABASE创建一…...

外包干了30天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…...

ruoyi-nbcio-plus基于vue3的flowable的自定义业务单表例子的升级修改

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://122.227.135.243:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a…...

【ENSP】华为三层交换机配置AAA认证,开启telnet服务

配置步骤 1.给交换机配置ip地址&#xff0c;以便登陆 2.配置AAA&#xff0c;用户名&#xff0c;密码&#xff0c;服务类型&#xff0c;用户权限 3.配置接入设备的数量 4.开启telnet服务 LSW2交换机配置 u t m #关闭提示 sys …...

collections模块下的Counter函数讲解

&#x1f4da;博客主页&#xff1a;knighthood2001 ✨公众号&#xff1a;认知up吧 &#xff08;目前正在带领大家一起提升认知&#xff0c;感兴趣可以来围观一下&#xff09; &#x1f383;知识星球&#xff1a;【认知up吧|成长|副业】介绍 ❤️感谢大家点赞&#x1f44d;&…...

HarmonyOS开发实例:【分布式邮件】

概述 基于TS扩展的声明式开发范式编程语言编写的一个分布式邮件系统&#xff0c;可以由一台设备拉起另一台设备&#xff0c;每次改动邮件内容&#xff0c;都会同步更新两台设备的信息。效果图如下&#xff1a; 搭建OpenHarmony开发环境 完成本篇Codelab我们首先要完成开发环境…...

llama2.c与chinese-baby-llama2语言模型本地部署推理

文章目录 简介Github文档克隆源码英文模型编译运行中文模型&#xff08;280M&#xff09;main函数 简介 llama2.c是一个极简的Llama 2 LLM全栈工具&#xff0c;使用一个简单的 700 行 C 文件 ( run.c ) 对其进行推理。llama2.c涉及LLM微调、模型构建、推理端末部署&#xff08…...

008、Python+fastapi,第一个后台管理项目走向第8步:ubutun 20.04下安装vscode+python环境配置

一、说明 白飘了3个月无影云电脑&#xff0c;开始选了个windows server 非常不好用&#xff0c;后台改为ubuntu想升级到22&#xff0c;没成功&#xff0c;那就20.04吧。 今天先安装下开发环境&#xff0c;后续2个月就想把他当做开发服务器&#xff0c;不知道行不行&#xff0c;…...

泰州做兼职的网站/宁波网站优化公司推荐

//以轮播3张图片abc为例&#xff0c; //&#xff08;1&#xff09;首先在首尾各插一张图片&#xff0c;在第一个图片a前面插入一张c图片&#xff0c;在最后一张图片c后面插入一张a图片&#xff08;过渡效果使用&#xff09;CabcA //&#xff08;2&#xff09;当移动至最后一个图…...

湛江市研发网站建设/网址如何被快速收录

成员函数的存储方式 学习C语言的变量定义时&#xff0c;我们就知道&#xff0c;定义一个变量&#xff0c;就需要在内存中申请空间&#xff0c;存放变量的数据。例如&#xff1a; double a; 此时&#xff0c;定义一个double类型的变量。double类型占据8个字节的内存空间&#x…...

wordpress有商城吗/谷歌seo搜索

前言 相信遇到这个问题的小伙伴&#xff0c;一定很无奈&#xff0c;要想知道这个问题的原因&#xff0c;并根治这个问题&#xff0c;需要研究fragment系列的大部分源码。网上很多文章&#xff0c;只是简单描述了这个问题如何出现&#xff08;使用的方法很麻烦&#xff0c;下面…...

做直播的小视频在线观看网站/产品推广介绍怎么写

目录 Python基础小结一.执行Python程序的两种方式1.1交互式1.2 命令行式二、执行Python程序的两种IDE2.1 Pycharm2.3 Jupyter三.变量3.1 什么变量&#xff1f;3.2 变量的组成?3.3 变量名的定义规范3.4 定义变量的两种方式3.5 常量四、注释4.1单行注释4.2 多行注释4.3 引用计数…...

大丰企业做网站多少钱/佛山网站优化软件

面试中纯粹考算法的问题一般是让很多程序员朋友痛恨的&#xff0c;这里分享下我对于解答算法题的一些思路和技巧。 一般关于算法的文章&#xff0c;都是从经典算法讲起&#xff0c;一种一种算法介绍&#xff0c;见得算法多了&#xff0c;自然就有了感悟&#xff0c;但如此学习花…...

建设党的群众路线网站 简报/美橙互联建站

前言 由于安装某个项目的执行文件&#xff0c;提示要卸载MySQL以便它自身MySQL安装&#xff0c;然后我禁用了MYSQL服务&#xff0c;再把这个文件夹删除后&#xff0c;发现还是提示请卸载MYSQL服务。 -------------------------------------------------------------------- …...