Home Tags Posts tagged with "后端"

后端

0 72

我,一名新入职的工程师;

我,缺乏高并发实战经验;

我,后端回参上千条数据;

我,循环访问数据库一次查一条;

我,从不分页,从不批量处理;

我被称为性能杀手,服务器终结者。

 

秋招时,我能和面试官大谈高并发,高可用,高扩展;答辩时,我能和老师探讨多线程,分布式锁,性能优化…

面试官和老师眼中的我:

查看源图像

实际上的我:

动图

 

实际工作中,为什么要分页?为什么不应该在循环中查询数据库?怎样在工作中去考虑性能问题?相信本文能带给你一些思考。


一、为什么要分页?

分页功能在网页中是非常常见的一个功能,其作用也就是将数据分割成多个页面来进行显示。

  • 使用场景: 当取到的数据量达到一定的时候,就需要使用分页来进行数据分割。

当我们不使用分页功能的时候,会面临许多的问题:

  • 客户端的问题: 如果数据量太多,都显示在同一个页面的话,会因为页面太长严重影响到用户的体验,也不便于操作,也会出现加载太慢的问题
  • 服务端的问题: 如果数据量太多,可能会造成内存溢出(OOM),而且一次请求携带的数据太多,对服务器的性能也是一个考验

 

以C/S架构为例,要实现“展示所有的商品信息”功能,实现流程是:用户点击功能按钮,前端发起请求,后端接收请求去查对应库表,返回响应给前端,前端将数据渲染到App页面上。

假使商品信息表中有上百万条记录,如果不做分页处理,后端直接从表中获取百万条记录

服务器压力过大

首先服务器的内存可能就会溢出,即OOM。

假设公司老板财大气粗,服务器内存特别大,JVM的内存参数设置的也很大,内存没有爆掉,那么就来到了“返回响应给前端”这一步。

网络开销过大

我们都知道,网络传输的数据量越多,时延也会越高。

百万条记录在网络中的传输,究竟要多久呢?

以虚拟机为64位的机器为例,假设单个商品信息对象有8个字段且都是基本数据类型,对象头占用的内存是8(运行时数据)+4(类型指针)=12Byte,实例数据是(8个字段)8 * 4 = 32Byte,由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍,所以按照一个商品信息对象 48Byte的大小进行计算,百万条数据的大小为:

48 * 100W = 45.77MB

传输时间过长

接下来,计算45.77MB在网络速度为100Mb/S的情况下的传输时长为:

45.77 MB* 8bit / 100Mb = 3.66s

实际消耗肯定比3.66s更长,因为有损耗

注意,这仅仅是数据在网络中传输需要的时长,在此之前,客户端和服务端还需要经历TCP三次握手建立连接等等,在前端接收到数据之后,还要对数据进行解析、格式处理等等…

即使假设系统优化做的非常好,客户端的网络、硬件配置也特别高,整个流程仅花费了网络传输的时长3.66s,也无法接受。

用户体验太差

根据1/3/5秒原则,在1s以内得到响应,用户会觉得系统响应很快,体验非常好;1-3秒得到响应,用户可以接收,体验还不错;3-5秒才响应,用户就感觉慢了,体验有点糟糕;一旦响应超过5秒,用户就会认为是个失败的体验,选择离开或重新发起请求。

所以,为什么要一次性返回百万级别的数据呢,如此庞大的网络开销,如此缓慢的响应时间,如此不可接受的用户体验…槽点太多以至于无法吐槽。

那么,我们必须思考一下,用户需要一次性查看这么多条数据吗?

显然不需要。用户想要查看所有的商品信息,但他不可能一目十行,而且手机显示屏也装不下百万条数据,所以他一定是分批次去查看数据。就好像我们看小说一样,一本书300W字,不可能在同一页面展示,所以我们一定是这页看完了再去看下一页。

二、有哪些分页方式?

分页的时间节点

对于用户来说,他并不关心分页怎么实现,但对程序员来说,分页的实现有多种选择。

以 “展示所有的商品信息” 为例,从请求发起到返回数据的整个过程如下图所示:

从上图观察得知,我们有三个节点可以进行分页处理,分别是:

  • 数据库分页
  • 后端逻辑分页
  • 前端逻辑分页

其中,数据库分页为物理分页,后端前端分页为逻辑分页

1.真分页(物理分页):

  • 实现原理:SELECT * FROM xxx [WHERE...] LIMIT #{param1}, #{param2}
    第一个参数是开始数据的索引位置
    第二个参数是要查询多少条数据
  • 优点: 不会造成内存溢出
  • 缺点: 翻页的速度比较慢

2.假分页(逻辑分页):

  • 实现原理: 一次性将所有的数据查询出来放在内存之中,每次需要查询的时候就直接从内存之中去取出相应索引区间的数据
  • 优点: 分页的速度比较快
  • 缺点: 可能造成内存溢出

分页时间节点的选择

选择的标准是速度,显而易见,数据库,服务器和客户端之间是网络,如果网络传递的数据量越少,则客户端获得响应的速度越快。而且一般来说,数据库和服务器的处理能力一般比客户端要强很多。从这两点来看,客户端分页的方案是最不可取的。

其次就剩下了在服务器端分页和在数据库端分页两种方式了,如果选择在服务器端分页的话,大部分的被过滤掉的数据还是被传输到了服务器端,与其这样还不如直接在数据库端进行分页。

前端要做的就是尽快接受数据并最快地展示给用户,对于数据不多的场景用前端实现也无妨,然而若考虑到以后会有成千上万条数据应用的场景,显然后端去处理分页更合适些。
每次点击下一页,前端只需发送分页数信息请求后端数据,假设一页显示十条数据,每次点击只需请求这十条数据的信息返回给前端来更快地进行交互。然而若是由前端来进行分页操作,那就得把成千上万条数据全部先拉下来,再进行操作,先不说操作这么多数据拉低的性能,光是先拉下来就得费很长时间了,所以对于数据量大的操作,一般都采用后端分页的操作更合适。
首先要了解为什么要分页。分页主要是为了避免一次性从数据库获取大量数据。其次才是为了展示效果。

因此:数据库端分页 > 后端分页 > 前端分页

 三、各个分页方式的实现

数据库分页(以MySQL为例)

1.LIMIT用法

LIMIT出现在查询语句的最后,可以使用一个参数或两个参数来限制取出的数据。其中第一个参数代表偏移量:offset(可选参数),第二个参数代表取出的数据条数:rows。

  • 单参数用法

当指定一个参数时,默认省略了偏移量,即偏移量为0,从第一行数据开始取,一共取rows条。

/* 查询前五条数据 */

SELECT * FROM Student LIMIT 5;

  • 双参数用法

当指定两个参数时,需要注意偏移量的取值是从0开始的,此时可以有两种写法:

/* 查询第1-10条数据 */

SELECT * FROM Student LIMIT 0,10;


/* 查询第11-20条数据 */

SELECT * FROM Student LIMIT 10 OFFSET 10;

0 39
layui.use(['form', 'table'], function () {
    var $ = layui.jquery,
        form = layui.form,
        table = layui.table;

    table.render({
        elem: '#currentTableId',
        url: '/admin/fansMsg',接口地址
        toolbar: '#toolbarDemo',
        defaultToolbar: ['filter', 'exports', 'print', {
            title: '提示',
            layEvent: 'LAYTABLE_TIPS',
            icon: 'layui-icon-tips'
        }],
        cols: [[ 对应字段渲染
            {type: "checkbox", width: 50},
            {field: 'id', width: 80, title: 'ID', sort: true},
            {field: 'userName', width: 80, title: '用户名'},
            {field: 'gender', width: 80, title: '性别', sort: true},
            {field: 'email', width: 200, title: '邮箱'},
            {field: 'score', width: 80, title: '评分', sort: true},
            {field: 'classify', width: 80, title: '职业'},
            {field: 'wealth', width: 135, title: '财富', sort: true},
            {title: '操作', minWidth: 150, toolbar: '#currentTableBar', align: "center"}
        ]],
        limits: [10, 15, 20, 25, 50, 100],
        limit: 15,
        page: true,
        skin: 'line'
    });

后端:
/**
 * 获取粉丝信息
 */
@GetMapping("/fansMsg")
@ResponseBody
public JSONObject showFansMsg(){

    JSONObject result = new JSONObject();
    // 店铺粉丝列表
    QueryWrapper wrapper = new QueryWrapper();
    wrapper.eq("sub_storeid",1);
    List fanslist = userService.list(wrapper);
    result.put("code", "0");
    result.put("msg", "操作成功!");
    result.put("data", fanslist);
    return result;
}

总结:后端接口获取数据库数据,将数据转化为json格式,再返回json格式!前端通过ajax的url调用后端接口得到数据,通过 cols: [[ 对应字段渲染 进行字段渲染!!!

0 36

前端按钮调用Controller  使用ajax调用

 

个人实现:

 

 

后端代码:


 

利用Ajax调用controller方法并传递参数

原文链接:https://blog.csdn.net/taxuezcy/article/details/80682687

 

 

不提交表单获取文本框的值,使用js

js:

文本框

 

 

前端向后台传值的5种方式总结

JSai 2019-06-05 21:35:54 26524 收藏 175
文章标签: 前台向后台 传值 from表单传值 ajax传值 js传值
版权
一、form表单提交(常用)
from表单把所有属于表单中的内容提交给后台,例如输入框,单选框,多选框,文本域,文件域等。

在后台可通过对应的name属性获取相应的值。
from表单中的action属性标识提交数据的地址。
method属性指明表单提交的方式。
<form action=”demo.do” method=”post”>
用户名:<br>
<input type=”text” name=”username”><br>
密码:<br>
<input type=”password” name=”password” ><br><br>
<input type=”submit” value=”提交”>
</form>

二、JQuery中的ajax提交(常用)
JavaScript中也有ajax提交,但是代码太多,所以JQuery对JS中的ajax进行了简化。引入JQuery相应的包即可使用。一般格式为:

$.ajax({
url: “TestJsonServlet”, //提价的路径
type: “post”, //提交方式
data: {
//向后台提交的数据
},
dataType: “JSON”, //规定请求成功后返回的数据
success: function (data) {
//请求成功之后进入该方法,data为成功后返回的数据
},
error: function (errorMsg) {
//请求失败之后进入该方法,errorMsg为失败后返回的错误信息
}
});

总结:以上两种方式如果不显示的指定post提交方式,则默认的提交方式为get方式提交。此外,ajax中的url也可以直接通过字符串拼接,然后向后台提交数据,这种方式为get方式提交。下面详细说明

三、通过url字符串拼接向后台提交数据
直接在ajax中url拼接数据
$.ajax({
url: “TestJsonServlet?id=”+id+”&gender=”+”男”, //提价的路径
type: “get”, //提交方式
dataType: “JSON”, //规定请求成功后返回的数据
success: function (data) {
//请求成功之后进入该方法,data为成功后返回的数据
},
error: function (errorMsg) {
//请求失败之后进入该方法,errorMsg为失败后返回的错误信息
}
});

JS提交数据,通过window.location.href指定路径提交数据。
var deleteUser = function (deleteId) {
if (confirm(“确认删除编号是【”+deleteId+”】的成员吗?”)){
window.location.href=”DeleteUserServlet?deleteId=”+deleteId;

通过a标签提交数据,通过a标签的href属性提交数据,和js提交数据类似。
<a href=”DeleteUserServlet?id=’3’&gender=’男'”></a>

在后台中也可以互相访问相应的Servlet
request.setAttribute(“id”,”3″);
request.setAttribute(“gender”,”男”);
request.getRequestDispatcher(“updateUser.jsp”).forward(request,response);

然后在对应的Servlet中接受参数,进行相应的处理

String id = request.getAttribute(“id”);
String gender = request.getAttribute(“gender”);

原文链接:https://blog.csdn.net/s2152637/article/details/90947003

 

 

数据从前台传到后台的几种方式

https://blog.csdn.net/sinat_21026543/article/details/80944986