uni-app踩坑+小改造- 掘金

mikel阅读(60)

来源: uni-app踩坑+小改造最近团队内部一直在试点用uni-app去做一些小需求,但主要是先在H5上做试点,之后再按计划编 – 掘金

背景

最近团队内部一直在试点用uni-app去做一些小需求,但主要是先在H5上做试点,之后再按计划编译成小程序去发布。这回分享几个遇到的小问题和解决方案。

下面说到的问题主要在用uni-app开发H5平台时才会遇到,非H5平台可忽略。

跨域的问题

首先,在本地开发时,不同于直接用小程序IDE进行开发,在开发H5平台时,需要使用浏览器进行调试,而浏览器会有跨域的问题。比如直接通过本地IP地址去访问开发中的页面,同时这个页面会调一些现有的接口时,就面临着跨域的问题。

官方的解决方案

uni-app官方介绍了一些解决跨域问题的方法,比如服务端开启CORS,给浏览器安装跨域插件等,详见uni-app的H5版使用注意事项。但里面并没有提到(应该是很久未更新文档导致)的是,如果不想这么麻烦去解决,还有个更方便的办法,也就是用webpack-dev-server去代理即可解决。

更方便的解决方案

根据官方文档的描述,devServer配置被要求在manifest.json去配置,并且由于这个配置文件是json格式的,所以只能对简单类型进行配置。但对于proxy这项配置来说也是足够了的。直接如下方式配置即可解决:

代码解读
复制代码
// manifest.json
{
    "h5": {
        "devServer": {
            "proxy": {
                "/prefix/api/user/list": {
                    "target": "https://api-remote.xxxx.com",
                    "pathRewrite": {
                        "^/prefix": ""
                    }
                }
            }
        }
    }
}

另一种解决方案

直接创建一个vue.config.js文件,并在里面配置devServer,直接上代码

代码解读
复制代码
// vue.config.js
module.exports = {
  devServer: {
    proxy: {
      '/prefix/api/user/list': {
        target: 'https://api-remote.xxxx.com',
        pathRewrite: {
          '^/prefix': ''
        }
      }
    },
  }
}

这种办法的好处显而易见,用js而非json去配置会更加的灵活,需要注意的是以上两种方案不能同时使用,第一种会覆盖第二种方案。

Mock的问题

这可能也不是什么大问题,毕竟现在有很多像Easy Mock这样的在线Mock平台。但有时我们可能嫌麻烦,不想离开代码编辑窗口去注册,编写在线Mock数据,更想一切都用代码解决,那么同样可以用上面的第二种方案来搞定

解决方案

借助mocker-apimockjs这两个工具,直接配置devServerbefore选项即可,代码如下:

代码解读
复制代码
// vue.config.js
const webpackApiMocker = require('mocker-api')

module.exports = {
  devServer: {
    before (app) {
      webpackApiMocker(app, path.resolve('./mock/index.js'))
    }
  }
}

// mock/index.js
const Mock = require('mockjs')

const Random = Mock.Random
const mock = Mock.mock

const proxy = {
  'GET /api/user/list': mock({
    'array|3': [
      {
        id: 1,
        username: 'kenny',
        sex: 'male'
      }
    ]
  }),
  'POST /api/login/account': (req, res) => {
    return res.json({
      status: 'ok',
      data: {
        id: Random.id(),
        userName: Random.cname(),
        city: Random.city()
      }
    })
  }
}

module.exports = proxy

publicPath的问题

到了测试阶段,我们需要将代码部署到CDN上提测,不同的环境对应不同的CDN域名,官方通过manifest.json的方式配置publicPath显然非常的不灵活,我们希望publicPath是动态的,与环境,仓库,工程名甚至开发分支有关,而且不需要开发人员去关心。

解决方案

要解决这个问题就需要对脚手架做一些小改造了。

  • 首先,我们将publicPath这项配置拿出来单独放在一个配置文件中,比如project-config.js,并放在工程根目录下
代码解读
复制代码
const projectName = 'xxx' // 当前工程名,此处自由发挥即可
const isDev = isDev() // 是否为本地开发环境,此处自由发挥即可
const CDN_HOST = process.env.CDN_HOST   // build时指定的CDN域名
const APP_ENV = process.env.APP_ENV // build时指定的自定义环境

module.exports = {
  publicPath: isDev
    ? '/'
    : `//${CDN_HOST}/static/${projectName}/${APP_ENV}/`,
}
  • 其次,我们fork了一版官方的uni-app源码,并对@dcloudio/vue-cli-plugin-uni/index.js做了点改动
代码解读
复制代码
// @dcloudio/vue-cli-plugin-uni/index.js#L30
// 获取本地的project-config配置
module.exports = (api, options) => {
    const projectConfig = require(api.resolve('project-config'))

    Object.assign(options, { 
        outputDir: process.env.UNI_OUTPUT_TMP_DIR || process.env.UNI_OUTPUT_DIR,
        assetsDir
    }, vueConfig, {
        // 重新对publicPath进行覆盖
        publicPath: process.env.NODE_ENV === 'production' ? projectConfig.publicPath : '/'
    })
}

这样会使manifest.json中的配置失效,也就是如果使用HBuilder开发的话会受到点影响。

作者:前端论道
链接:https://juejin.cn/post/6844904063855755271
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

uni-app <image>和vue中img标签动态绑定src不显示本地图片 - web_pzj - 博客园

mikel阅读(40)

来源: uni-app <image>和vue中img标签动态绑定src不显示本地图片 – web_pzj – 博客园

因为需要根据后端返回的数据渲染不同的图片,所有要对imge标签的src进行动态绑定。

以下是静态绑定时的代码,静态绑定无任何问题。

 

下方是静态绑定时的正常图片:

 

 

以下是动态绑定时的代码,但是图片无法显示。

 

无法显示效果图:

 

解决办法一:用将路径放入require()中。

 

 

解决办法二:不要使用../,改为根目录/

uniapp 中出现 Undefined variable $u-type-primary-light 问题_undefined variable: "$u-type-primary-light".-CSDN博客

mikel阅读(46)

来源: uniapp 中出现 Undefined variable $u-type-primary-light 问题_undefined variable: “$u-type-primary-light”.-CSDN博客

问题描述
uniapp 引入 uview-ui 后 一顿操作,出现 Undefined variable: “$u-type-primary-light” 错误。
解决问题
第一步:确保 HBuilder X 是安装了 scss/sass 编译插件
第二步:确保在根目录下 uni.scss 文件中引入 theme.scss,
@import “uview-ui/theme.scss”; // 放在代码首行
1
第三步:确保在根目录下 App.vue 文件中添加 lang=”scss” 和 index.scss
<style lang=”scss”>
@import “uview-ui/index.scss”;
</style>
1
2
3
问题得以解决。
————————————————
                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_49175501/article/details/118157121

uni-app 分不清的全局变量this, uni, $u, vm, uni.$u, this.$u-CSDN博客

mikel阅读(48)

来源: uni-app 分不清的全局变量this, uni, $u, vm, uni.$u, this.$u-CSDN博客

项目引入了uview,并将uview所有模块指给uniapp全局变量uni

uni.$u=$u

 

在登录页面,或者APP.vue打印以下变量:

this, uni, $u, vm, uni.$u, this.$u

// this,$u,vm,uni, this.$u, uni.$u全局变量说明
console.log(“>>this”, this)
console.log(“>>uni”, uni)
console.log(“>>this===uni”, this === uni) //false
console.log(“>>this.$u “, this.$u)
console.log(“>>uni.$u “, uni.$u)
console.log(“>>this.$u===uni.&u”, this.$u === uni.$u) //ture

try {//$u is not defined
console.log(“>>$u “, $u)
} catch (e) {
console.log(e)
}
try { //vm is not defined
console.log(“>>this.vm”, this.vm)
console.log(“>>vm “, vm)
} catch (e) {
console.log(e)
}
运行结果
$u 是uview挂载到uni上的,方便使用uni来操作uview组件。

uni. 对象是uni-app框架实例。

this. 在.vue页面,对应就是当前vue的实例对象。

this.$u 与uni.$u 在vue页面是同一对象,指向 uview

 

$u来源
uniapp-master\uview-ui\index.vue,在此vue里,通过xx.prototype.$u的方法 ,通过uni.$u方法同时挂载到全局里。

// 引入全局mixin
import mixin from ‘./libs/mixin/mixin.js’

// 防抖方法
import debounce from ‘./libs/function/debounce.js’
// 节流方法
import throttle from ‘./libs/function/throttle.js’
import {fixMoney2Decimal, formatInputMoney, toFixed2Decimal} from “@/uview-ui/libs/function/numberform”;
import {positiveNumber} from “@/uview-ui/libs/function/inputRegExp”;
//…
//…

// 配置信息
import config from ‘./libs/config/config.js’
// 各个需要fixed的地方的z-index配置文件
import zIndex from ‘./libs/config/zIndex.js’
import {timeFormatCmm} from “@/uview-ui/libs/function/timeFormatStr”;

const $u = {
queryParams: queryParams,
positiveNumber: positiveNumber,
route: route,
timeFormat: timeFormat,
date: timeFormat, // 另名date
timeFormatCmm: timeFormatCmm,
timeFrom,
colorGradient: colorGradient.colorGradient,
colorToRgba: colorGradient.colorToRgba,
guid,
color,
sys,
os,
type2icon,
randomArray,
wranning,
get: http.get,
post: http.post,
put: http.put,
‘delete’: http.delete,
hexToRgb: colorGradient.hexToRgb,
rgbToHex: colorGradient.rgbToHex,
test,
random,
deepClone,
deepMerge,
getParent,
$parent,
addUnit,
trim,
type: [‘primary’, ‘success’, ‘error’, ‘warning’, ‘info’],
http,
toast,
toastErr,
toastS,
modal,
config, // uView配置信息相关,比如版本号
zIndex,
debounce,
throttle,

//–
toFixed2Decimal,
fixMoney2Decimal,
formatInputMoney
}

// $u挂载到uni对象上
uni.$u = $u

const install = Vue => {
Vue.mixin(mixin)
if (Vue.prototype.openShare) {
Vue.mixin(mpShare);
}
// Vue.mixin(vuexStore);
// 时间格式化,同时两个名称,date和timeFormat
Vue.filter(‘timeFormat’, (timestamp, format) => {
return timeFormat(timestamp, format)
})
Vue.filter(‘date’, (timestamp, format) => {
return timeFormat(timestamp, format)
})
// 将多久以前的方法,注入到全局过滤器
Vue.filter(‘timeFrom’, (timestamp, format) => {
return timeFrom(timestamp, format)
})
Vue.prototype.$u = $u
}

export default {
install
}
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/LlanyW/article/details/132522228

【uni-app项目如何引入 uView组件库】_uview安装到uni-app项目-CSDN博客

mikel阅读(40)

来源: 【uni-app项目如何引入 uView组件库】_uview安装到uni-app项目-CSDN博客

uniapp项目引入uView组件库
一、uView官方文档
二、公司项目中引入并使用uView
一、uView官方文档
uView官方文档

二、公司项目中引入并使用uView
第一步:

在公司创建完成uniapp项目后引入uView

 

第二步:

您如果是使用HBuilder X创建的uniapp项目,使用uView组件库的话需要在HBuilder X下载插件库 下载 uni_modules ,(如果这个看不懂可以看官方文档)

(1) HBuilder X插件库中下载 uni_modules

 

 

 

 

 

 

 

现在是已经将 uView导入到项目中了,接下来还需要对项目中uView组件库样式的导入,(具体步骤官方文档里都有)

 

如果之前安装过scss,可以直接跳过

这里的scss仅限于是通过Vcode开发uniapp的

 

通过HBuilder X 下载scss

 

 

在项目根目录中的main.js中,引入并使用uView的JS库,注意这两行要放在import Vue之后。

// main.js
import uView from ‘@/uni_modules/uview-ui’
Vue.use(uView)

在项目根目录的uni.scss中引入此文件。

/* uni.scss */
@import ‘@/uni_modules/uview-ui/theme.scss’;

 

 

到这一步可以直接启动项目,里边的组件均可使用
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Lnbd_/article/details/129470614

关于uni-app的ui库、ui框架、ui组件 - DCloud问答

mikel阅读(51)

来源: 关于uni-app的ui库、ui框架、ui组件 – DCloud问答

组件的概念

组件是现代开发的重要里程碑。组件重构了分工模型,让大量的轮子出现,让开发者可以拿来轮子直接用,大幅提升了整个产业的效率。

uni-app是有内置组件的。这和web开发不一样。
web开发基本上不用基础组件,都是找一个三方ui库,全套组件都包含。那是因为html的基础组件默认样式不适配手机风格。
但uni-app体系不是这样,内置组件就是为手机优化的。

但内置组件只能满足基础需求,更多场景,需要扩展组件。
扩展组件是基于内置组件的二次封装,从性能上来讲,扩展组件的性能略低于内置组件,所以开发者切勿抛弃内置组件,直接全套用三方UI组件库。

uni-app的插件市场,有很多扩展组件,有的是单独的,有的是成套的。
有些开发者喜欢成套的组件,但注意成套扩展组件也不可能覆盖所有需求,很多场景还是需要单独下载专业组件。

扩展组件的选择

众多扩展组件如何选择?我们首先要搞清楚组件的分类。
组件分2大类:1、vue组件(文件后缀为vue);2、小程序自定义组件(文件后缀为wxml或其他小程序平台特有后缀名称)

  • vue组件又分为2个细项:only for web、全端兼容
  • 小程序组件又分为:微信/QQ小程序组件、阿里小程序组件、百度小程序组件、字节跳动小程序组件。
    这些组件uni-app都支持,但受组件本身技术特点限制,在不同端有不一样的支持度。
    下面这张表格,可以清楚的表达不同类型的组件的兼容性。

 

 

从表格中可以很明显看出,更推荐使用的是全端兼容的uni规范组件。

很多人容易搞错2个问题:

  1. 同样是vue组件,only for web的和全端的有什么区别?
    传统的vue组件,比如elementUI,都是only for web的,里面有大量dom和window对象操作。但小程序和App是没有dom这些api的,自然无法跨端使用。
    想要跨端,其实也不难,做一套无dom的vue组件即可。官方的uni-ui即是如此。还有众多开发者在插件市场提交了更多这种类型的库。
  2. vant是分web版和weapp版的,千万别搞混
    vant的web版操作了dom,所以只能用于web端;而vant weapp是微信小程序组件规范,可以用于微信、App、H5;vant自身并没有提供全端可用的无dom vue组件。

除了兼容性,在性能和生态完善度层面,不同类型组件有什么差别?

  1. 性能:
    • vue组件性能好于小程序自定义组件。这是因为uni-app在底层对vue数据更新使用了自动差量更新的机制。而小程序自定义组件,默认的setData写法是没有差量数据更新的,需要写代码手动实现差量更新才能达到相同性能。
  2. 生态完善度
    • 首先除了微信小程序,其他几个平台的小程序几乎是没有三方组件和模板生态的。开发其他端小程序,得靠uni-app的生态
    • 再说微信小程序生态,之前在微信小程序平台上一些有名的库(比如wxParse、wx-Echart),实际上在性能、功能、技术支持上,大多做的不如uni-app生态下的新库好。而vant、iview的weapp版,其性能也均不如uni ui。
  3. 其他指标
    • vue doc:HBuilderX支持vue doc,组件作者在vue组件源码里编写vue doc,可以让组件使用者写代码时得到良好的代码提示。
    • easycom:uni-app支持easycom,可以大幅简化组件的使用
    • nvue支持:如果开发App,可能会涉及到nvue原生渲染页面,这种渲染方式支持的css有限,此时就要甄别组件是否兼容nvue。

再来看看各种成套UI的优劣分析

uni ui

DCloud官方出了一套扩展组件,即uni-ui
这些扩展组件支持单个组件从插件市场下载,也支持npm引入uni ui,当然更方便的是在HBuilderX新建项目时直接选择uni ui项目模板
uni ui有如下优势:

  1. 优化逻辑层和视图层的通信折损:非H5端的各个平台,包括App和各种小程序,其逻辑层和视图层是分离的,两层之间通信交互会有折损,导致诸如跟手滑动不流畅。uni ui在底层会利用wxs等技术,把适当的js代码运行在视图层,减少通信折损,保证诸如swiperAction左滑菜单等跟手操作流畅顺滑
  2. 自动差量diff数据:在uni-app下,开发App和小程序,不需要手动setData,底层自动会差量更新数据。但如果使用了小程序组件,则需要按小程序的setData方式来更新数据,很难做到自动diff更新数据。
  3. 背景停止:很多ui组件是会一直动的,比如轮播图、跑马灯。即便这个窗体被新窗体挡住,它在背景层仍然在消耗着硬件资源。在Android的webview版本为chrome66以上,背景操作ui会引发很严重的性能问题,造成前台界面明显卡顿。而uni ui的组件,会自动判断自己的显示状态,在组件不再可见时,不会再做动画消耗硬件资源。
  4. 纯vue语法:uni ui的引用、开发都是纯vue方式。而小程序组件的引用注册、开发都是小程序语法,两种语法混合在一个工程,写的也不舒服,维护也麻烦。
  5. uni统计自动整合:比如使用uni ui的导航栏组件,就不需要写统计的自定义事件来触发页面标题上报。uni统计会自动识别导航栏组件的标题。类似的,收藏组件、购物车组件,都可以免打点直接使用。
  6. uni ui兼容Android 4.4等低端机webview,没有浏览器兼容问题。
  7. uni ui支持nvue:App端,uni-app同时支持webview渲染和原生渲染,而uni ui是可以一套代码同时支持webview渲染和原生渲染的。为了兼容原生渲染,uni ui也做到了纯flex布局。
  8. uni ui内置vue doc,使用组件时有良好的代码提示
  9. 支持easycom规范,使用非常简单
  10. 支持datacom规范,云端一体全部封装掉
  11. 支持uni_module规范,方便插件的更新

推荐在HBuilderX新建项目时,直接选择uni ui项目模板,然后在代码里直接敲u,所有组件都拉出来,不用引用、不用注册,直接就用。

 

插件市场更多组件

插件市场,https://ext.dcloud.net.cn,有各种玲琅满目的组件、模板。
其中成套的全端兼容ui库包括:

其他

  • 如果你仍坚持使用微信小程序的自定义组件ui,插件市场也有很多vant weapp版的集成示例https://ext.dcloud.net.cn/search?q=vant。同时要注意,小程序自定义组件的性能不如vue组件。
  • 如果你的nvue文件使用weex编译模式,也支持weex ui。三方商业ui库有graceUI weex版。但weex编译模式属于被淘汰技术,不再提供技术支持,nvue开发请使用uni-app编译模式。

综上,官方对组件的使用建议是:

  1. 首先使用内置组件
  2. 然后使用uni ui扩展组件
  3. 其他需求依靠插件市场其他组件灵活补充

使用uniapp创建项目,并使用uni-ui,引入uView及遇到的一些问题_全局使用uni-ui-CSDN博客

mikel阅读(43)

来源: 使用uniapp创建项目,并使用uni-ui,引入uView及遇到的一些问题_全局使用uni-ui-CSDN博客

一、uniapp中使用uni-ui
1.创建uniapp项目
点击 文件 —— 新建 —— 项目
选择 默认模板 给项目命名
2.运行项目
点击 运行 —— 运行到浏览器 —— Chrome
看到后台提示编译成功
项目的页面展示
3.引入uni-ui
在cmd中输入命令
npm i @dcloudio/uni-ui
1
4.在项目中全局使用uni-ui
在pages.json中进行配置easycom,
“easycom”: {
“autoscan”: true,
“custom”: {
// uni-ui 规则如下配置
“^uni-(.*)”: “@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue”
}
},
二、uniapp中使用uView
1.创建uniapp项目,步骤同上
点击 文件 —— 新建 —— 项目——选择 默认模板——给项目命名
2.引入uView,步骤同上
在cmd中输入命令
初始化,创建package.json文件
npm init -y
1
安装uview-ui组件库
npm install uview-ui
1
3.在main.js中全局引入uview组件
ps:注意uview引入的位置,必须是在import Vue from “vue” 之后,并且是在 app.$mount()之前,否则在使用uview组件时会报错!!!
在uni.scss中全局引入uview-ui样式
4.使用uview组件
效果图如下
uview相关的问题
1.u-tabs子项水平居中
u-tabs默认是这样的,想着把子项水平居中
这是修改后的
代码如下
.mytabs ::v-deep .uni-scroll-view-content {
display: flex;
justify-content: space-around;
}
.mytabs ::v-deep .u-tabs__wrapper__nav {
flex:none !important;
}
style flex属性
https://www.runoob.com/jsref/prop-style-flex.html
————————————————
                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/blue__k/article/details/122921646

百万商品查询,性能提升了10倍 - 苏三说技术 - 博客园

mikel阅读(58)

来源: 百万商品查询,性能提升了10倍 – 苏三说技术 – 博客园

前言

最近在我的知识星球中,有个小伙伴问了这样一个问题:百万商品分页查询接口,如何保证接口的性能?

这就需要对该分页查询接口做优化了。

这篇文章从9个方面跟大家一起聊聊分页查询接口优化的一些小技巧,希望对你会有所帮助。

图片

1 增加默认条件

对于分页查询接口,如果没有特殊要求,我们可以在输入参数中,给一些默认值。

这样可以缩小数据范围,避免每次都count所有数据的情况。

对于商品查询,这种业务场景,我们可以默认查询当天上架状态的商品列表。

例如:

select * from product 
where edit_date>='2023-02-20' and edit_date<'2023-02-21' and status=1

如果每天有变更的商品数量不多,通过这两个默认条件,就能过滤掉绝大部分数据,让分页查询接口的性能提升不少。

温馨提醒一下:记得给时间状态字段增加一个联合索引

2 减少每页大小

分页查询接口通常情况下,需要接收两个参数:pageNo(即:页码)和pageSize(即:每页大小)。

如果分页查询接口的调用端,没有传pageNo默认值是1,如果没有传pageSize也可以给一个默认值10或者20。

不太建议pageSize传入过大的值,会直接影响接口性能。

在前端有个下拉控件,可以选择每页的大小,选择范围是:10、20、50、100。

前端默认选择的每页大小为10

不过在实际业务场景中,要根据产品需求而且,这里只是一个参考值。

3 减少join表的数量

有时候,我们的分页查询接口的查询结果,需要join多张表才能查出数据。

比如在查询商品信息时,需要根据商品名称、单位、品牌、分类等信息查询数据。

这时候写一条SQL可以查出想要的数据,比如下面这样的:

select 
  p.id,
  p.product_name,
  u.unit_name,
  b.brand_name,
  c.category_name
from product p
inner join unit u on p.unit_id = u.id
inner join brand b on p.brand_id = b.id
inner join category c on p.category_id = c.id
where p.name='测试商品' 
limit 0,20;

使用product表去join了unit、brand和category这三张表。

其实product表中有unit_id、brand_id和category_id三个字段。

我们可以先查出这三个字段,获取分页的数据缩小范围,之后再通过主键id集合去查询额外的数据。

我们可以把SQL改成这样:

select 
  p.id,
  p.product_id,
  u.unit_id,
  b.brand_id,
  c.category_id
from product
where name='测试商品'
limit 0,20;

这个例子中,分页查询之后,我们获取到的商品列表其实只要20条数据。

再根据20条数据中的id集合,获取其他的名称,例如:

select id,name 
from unit
where id in (1,2,3);

然后在程序中填充其他名称。

伪代码如下:

List<Product> productList = productMapper.search(searchEntity);
List<Long> unitIdList = productList.stream().map(Product::getUnitId).distinct().collect(Collectors.toList());
List<Unit> unitList = UnitMapper.queryUnitByIdList(unitIdList);
for(Product product: productList) {
   Optional<Unitoptional = unitList.stream().filter(x->x.getId().equals(product.getId())).findAny();
   if(optional.isPersent()) {
      product.setUnitName(optional.get().getName());
   } 
}

这样就能有效的减少join表的数量,可以一定的程度上优化查询接口的性能。

4 优化索引

分页查询接口性能出现了问题,最直接最快速的优化办法是:优化索引

因为优化索引不需要修改代码,只需回归测试一下就行,改动成本是最小的。

我们需要使用explain关键字,查询一下生产环境分页查询接口的执行计划

看看有没有创建索引,创建的索引是否合理,或者索引失效了没。

索引不是创建越多越好,也不是创建越少越好,我们需要根据实际情况,到生产环境测试一下sql的耗时情况,然后决定如何创建或优化索引。

建议优先创建联合索引

如果你对explain关键字的用法比较感兴趣,可以看看我的这篇文章《explain | 索引优化的这把绝世好剑,你真的会用吗?》。

如果你对索引失效的问题比较感兴趣,可以看看我的这篇文章《聊聊索引失效的10种场景,太坑了》。

5 用straight_join

有时候我们的业务场景很复杂,有很多查询sql,需要创建多个索引。

在分页查询接口中根据不同的输入参数,最终的查询sql语句,MySQL根据一定的抽样算法,却选择了不同的索引。

不知道你有没有遇到过,某个查询接口,原本性能是没问题的,但一旦输入某些参数,接口响应时间就非常长。

这时候如果你此时用explain关键字,查看该查询sql执行计划,会发现现在走的索引,跟之前不一样,并且驱动表也不一样。

之前一直都是用表a驱动表b,走的索引c。

此时用的表b驱动表a,走的索引d。

为了解决Mysql选错索引的问题,最常见的手段是使用force_index关键字,在代码中指定走的索引名称。

但如果在代码中硬编码了,后面一旦索引名称修改了,或者索引被删除了,程序可能会直接报错。

这时该怎么办呢?

答:我们可以使用straight_join代替inner join

straight_join会告诉Mysql用左边的表驱动右边的表,能改表优化器对于联表查询的执行顺序。

之前的查询sql如下:

select p.id from product p
inner join warehouse w on p.id=w.product_id;
...

我们用它将之前的查询sql进行优化:

select p.id from product p
straight_join warehouse w on p.id=w.product_id;
...

6 数据归档

随着时间的推移,我们的系统用户越来越多,产生的数据也越来越多。

单表已经到达了几千万。

这时候分页查询接口性能急剧下降,我们不能不做分表处理了。

做简单的分表策略是将历史数据归档,比如:在主表中只保留最近三个月的数据,三个月前的数据,保证到历史表中。

我们的分页查询接口,默认从主表中查询数据,可以将数据范围缩小很多。

如果有特殊的需求,再从历史表中查询数据,最近三个月的数据,是用户关注度最高的数据。

7 使用count(*)

在分页查询接口中,需要在sql中使用count关键字查询总记录数

目前count有下面几种用法:

  • count(1)
  • count(id)
  • count(普通索引列)
  • count(未加索引列)

那么它们有什么区别呢?

  • count(*) :它会获取所有行的数据,不做任何处理,行数加1。
  • count(1):它会获取所有行的数据,每行固定值1,也是行数加1。
  • count(id):id代表主键,它需要从所有行的数据中解析出id字段,其中id肯定都不为NULL,行数加1。
  • count(普通索引列):它需要从所有行的数据中解析出普通索引列,然后判断是否为NULL,如果不是NULL,则行数+1。
  • count(未加索引列):它会全表扫描获取所有数据,解析中未加索引列,然后判断是否为NULL,如果不是NULL,则行数+1。

由此,最后count的性能从高到低是:

count(*) ≈ count(1) > count(id) > count(普通索引列) > count(未加索引列)

所以,其实count(*)是最快的。

我们在使用count统计总记录数时,一定要记得使用count(*)。

8 从ClickHouse查询

有些时候,join的表实在太多,没法去掉多余的join,该怎么办呢?

答:可以将数据保存到ClickHouse

ClickHouse是基于列存储的数据库,不支持事务,查询性能非常高,号称查询十几亿的数据,能够秒级返回。

为了避免对业务代码的嵌入性,可以使用Canal监听Mysqlbinlog日志。当product表有数据新增时,需要同时查询出单位、品牌和分类的数据,生成一个新的结果集,保存到ClickHouse当中。

查询数据时,从ClickHouse当中查询,这样使用count(*)的查询效率能够提升N倍。

需要特别提醒一下:使用ClickHouse时,新增数据不要太频繁,尽量批量插入数据。

其实如果查询条件非常多,使用ClickHouse也不是特别合适,这时候可以改成ElasticSearch,不过它跟Mysql一样,存在深分页问题。

9 数据库读写分离

有时候,分页查询接口性能差,是因为用户并发量上来了。

在系统的初期,还没有多少用户量,读数据请求和写数据请求,都是访问的同一个数据库,该方式实现起来简单、成本低。

刚开始分页查询接口性能没啥问题。

但随着用户量的增长,用户的读数据请求和写数据请求都明显增多。

我们都知道数据库连接有限,一般是配置的空闲连接数是100-1000之间。如果多余1000的请求,就只能等待,就可能会出现接口超时的情况。

因此,我们有必要做数据库的读写分离。写数据请求访问主库,读数据请求访问从库,从库的数据通过binlog从主库同步过来。

根据不同的用户量,可以做一主一从,一主两从,或一主多从。

数据库读写分离之后,能够提升查询接口的性能。

如果你对性能优化比较感兴趣,可以看看《性能优化35讲》,里面有更多干货内容。

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。
求一键三连:点赞、转发、在看。
关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

怎么在横向li很多的情况下自动适应ul宽度换行_前端-CSDN问答

mikel阅读(55)

来源: 怎么在横向li很多的情况下自动适应ul宽度换行_前端-CSDN问答

以下内容由CHATGPT及阿里嘎多学长共同生成、有用望采纳:


要实现<ul>标签中的<li>元素在达到<ul>的宽度限制时自动换行,你可以使用CSS的display: flex属性和flex-wrap: wrap属性。以下是具体的CSS代码实现:

  1. ul {
  2. display: flex; /* 设置ul为flex容器 */
  3. flex-wrap: wrap; /* 允许子元素换行 */
  4. width: 100%; /* 或者设置一个固定的宽度,根据需要调整 */
  5. list-style: none; /* 可选,去掉列表项的默认样式 */
  6. padding: 0; /* 可选,去掉内边距 */
  7. margin: 0; /* 可选,去掉外边距 */
  8. }
  9. li {
  10. flex: 0 1 auto; /* 允许li元素自动调整大小 */
  11. margin: 5px; /* 可选,设置li元素之间的间隔 */
  12. }

这段代码会使得<ul>内的<li>元素在达到<ul>的宽度限制时自动换行。flex: 0 1 auto; 表示<li>元素不会强制占据固定空间,而是根据内容自动调整大小,并在需要时换行。

参考资料:

  1. CSS Flexible Box Layout Module Level 1 – W3C
  2. Flexbox Froggy – A game for learning CSS flexbox
  3. CSS-Tricks – A Complete Guide to Flexbox

这些参考资料将帮助你更深入地了解Flexbox的工作原理和使用方法。

高版本数据库附加到低版本解决办法 - 党鹏飞 - 博客园

mikel阅读(54)

来源: 高版本数据库附加到低版本解决办法 – 党鹏飞 – 博客园

在我们使用别人导出的数据库的时候,有时候我们会通过附加数据库的方法,把别人导出的数据库附加到我们的电脑中,这时,或许你会遇到这种问题,附加时,提示版本为XXX,无法打开,支持AAA版本。

 

这是怎么回事呢?

 

原来,版本号是指SQL Server的版本号,例如版本号661是SQL Server 2008 R2,版本号655是SQL Server 2008 等。它拥有向上兼容的特点。由此可见,标题的意思就是说,你要附加的数据库,只能在SQL Server 2008 R2及更高版本上运行,不能在SQL Server 2008 上运行,那么,我们该怎么处理这个问题呢?

 

处理这种问题,有很多种方法,下面我就说一个我查到并使用的方法,仅供参考,如果有更好的方法,欢迎沟通。

1.把这个数据库附加到装有SQL Server 2008 R2的数据上。

2.打开Management Studio,登录到服务器,在数据库中选择要转移的数据库,右键--“任务(T)”--“生成脚本(E)…”。

3.在“生成和发布脚本”窗口中,点击“下一步”

4.“选择要编写脚本的数据库对象”,可以不做设置,点击“下一步”

5.点击[保存到文件]右边的“高级”按钮,在对话框中,设置“为服务器版本编写脚本”为“SQL Server 2008”,设置“要编写脚本的数据的类型”为“架构和数据”。选择保存脚本的位置

6.下一步,再下一步。导出完成

 

把导出完成的程序,在放到SQL  Server 2008 中,按下面步骤:

1.打开Management Studio,登录到服务器

2.选择菜单“文件”——“打开”——“文件”,选择.sql脚本文件,点击工具栏中的“执行”按钮

3.在左侧的“对象资源管理器”中右键“数据库”——“刷新”

到此为止,“版本号661,无法打开,支持655版本及其以下版本……”这个错误就算是解决了。当然,如果你直接把数据库卸载,在装SQL Server 2008R2 , 也是可以完美解决这个问题的。

 

 

版本655指的是SQL2008, 版本611指的是SQL2005, (还有一个版本539指的是SQL2000)
楼主的情况属于典型的从高版本降低至低版本使用的情景.
按微软的官方说法, 是不支持从高版本附加到低版本的.
如果一定要这么做, 那怎么办呢? 有办法.
首先, 找一台装有SQL Server 2008的电脑, 将你的数据库文件附加到这台电脑里.
附加成功后, 在SSMS的对象资源管理器窗口右键单击刚刚附加的数据库,依次选”任务>生成脚本…”, 此时会弹出脚本向导对话框.
点”下一步”.
在”选择数据库”对话框选中刚刚附加的数据库, 同时将底部的”为所选数据库中的所有对象编写脚本”打勾. 点下一步.
在”选择脚本选项”对话框中,还需要修改以下几个选项:
1).”编写数据的脚本”,设为”True”; (SQL2005没有这个选项,所以才要找一台装有SQL2008的电脑嘛,多省事啊,省去了数据导入导出的麻烦)
2).”编写触发器脚本”,设为”True”;
3).”编写创建数据库的脚本”,设为”True”;
4).”为服务器版本编写脚本”,选”SQL Server 2005″;(如果是要用的SQL2000中,那就选SQL Server 2000)
以上4个选项是非常建议这样设置的,其他的选项就自己看着办,其他的一般也不用改. 点下一步.
在”输出选项”对话框中,选”将脚本保存到文件”,其他默认,点下一步.
点完成.
点关闭.