# springboot-jsp **Repository Path**: tianmaoCode/springboot-jsp ## Basic Information - **Project Name**: springboot-jsp - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-02-07 - **Last Updated**: 2023-02-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # springboot-jsp ## bootstrap ztree - menu.jsp - MenuController.java - Menu.java - menu.sql 使用java8 stream封装父子节点 关系,页面在`menu2.jsp` java代码 ```java /** * 使用java8 stream封装父子节点 关系 */ @SuppressWarnings("unchecked") @RequestMapping("/java8stream") @ResponseBody public Object java8stream() { log.info("menu with java8stream"); // 使用java8 stream 封装父子关系,来展示 ztree 标准JSON格式 List queryForList = jdbcTemplate.query("select id,pId ,name,url,icon from t_menu", new BeanPropertyRowMapper(MenuStream.class)); // 获取取根节点 List collect = queryForList.stream().filter((menu) -> { return menu.getPid() == null; }).map((menu) -> { menu.setChildren(getChildren(menu, queryForList)); return menu; }).sorted((m1, m2) -> { return m1.getId() - m2.getId(); }).collect(Collectors.toList()); System.out.println(); System.out.println(collect); return collect; } /** * 查找所有节点子节点 * * @param root * @param all * @return */ private List getChildren(MenuStream root, List all) { List collect = all.stream().filter(menu -> { // 根据父节点查找子节点 return menu.getPid() == root.getId(); }).map(menuStream -> { // 递归设置 子节点 List children = getChildren(menuStream, all); if (children != null && !children.isEmpty()) { menuStream.setChildren(children); } return menuStream; }).collect(Collectors.toList()); return collect; } ``` ## juc ### volatile ## Redis 缓存 ### 1问题 #### 1.1 缓存穿透 > 查询一个不存在的数据,由于缓存是不命中。将去查询数据库,但是数据库也无此记录,并且处于容错考虑,我们没有将这次查询的null写入缓存,这将导致整个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。在大流量时,可能DB就挂掉了, **风险** > 利用不存在的数据进行攻击,数据库瞬时压力增大,最终导致奔溃 **解决** > 空结果进行缓存,但过期时间最长不要超过5分钟 #### 1.2 缓存雪崩 > 设置的缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。 **解决** > 原有失效时间基础上增加一个随机值,这样每一个缓存过期时间的重复率就会降低,就很难引发集体失效的事件。 #### 1.3 缓存击穿 > 对于一些设置了过期时间的key,如果这些key可能在某些时间点被超高并发地访问,是一种非常“热点”的数据,这个时候,需要考虑一个问题:如果这个key在大量请求同时进来前正好失效,那么所有key的数据查询都落到db,称之为缓存击穿。 > > 击穿和雪崩区别: > > - 击穿是一个热点key失效 > - 雪崩是很多key集体失效 **解决** > 分布式锁 https://www.bilibili.com/video/av76369486?p=125 ### 2 springredis ### 3 缓存数据一致性 > - 双写模式:有产生脏数据的风险 > > - 失效模式(更新数据 删除缓存):也存在脏数据 > > 1. 放入缓存的数据本不应该是实时性、一致性要求超高的,所以缓存数据的时候加上过期时间,保证每天拿到当前最新数据即可。 2. 不应该过度设计,增加系统的复杂性 3. 遇到实时性,一致性要求高的数据,应该查询数据库,及时慢一点 ### 4 spring-cache的不足 ##### 1 读模式 缓存穿透:查询一个null数据.`spring.cache.redis.cache-null-values` 缓存击穿:大量并发同时查询一个正好过期的数据,解决:加锁 缓存雪崩:大量key同时过期。解决,加随机时间:`spring.cache.redis.time-to-live=` ##### 2 写模式(缓存与数据库一致) 1 读写加锁 2 引入Cannal.感知MySQL更新去更新数据库 3 读多写多,直接去数据库查询。 ## ## 并发基础知识 ### 1 同步 #### 1.1 sys #### 1.2 volatile关键字 ## 线程池 ### 1 初始化线程的4种方式 1. 继承Thread 2. 实现Runnable接口 3. 实现Callable接口,+FuturTask(可以拿到返回结果,可以处理异常) 4. 线程池 ## session 共享问题解决 ### 1 session复制 - 优点 tomcat 原生支持,只需要修改配置文件 - 缺点 1. session 同步需要数据传输,占用大量网络带宽,降低了服务器群的业务处理能力 2. 任意一台web-server保存的数据都是所有web-server的session总和,收到内存限制无法水平扩展更多的web-server 3. 大型分布式集群情况下,由于所有web-server都全量保存数据,所有次方案不可取 ### 2 hash一致性 - 优点 1. 只需要该nginx配置,不需要修改应用代码 2. 负载均衡,只要hash属性的值分布式均匀的,多台web-server的负载是均衡的 3. 可以支持web-server水平扩展(session同步是不行的,受内存限制) - 缺点 1. session还是存在web-server中,所有web-server重启可能导致session丢失,影响业务,如部分用户需要重新登录。 2. 如果web-server水平扩展,rehash后的session重新分布,也会有一部分用户路由到不正确的session。 以上的缺点问题不大,因为session本来都是有有效期的。所有这两种反向代理的方式可以使用。 ### 3 统一存储 - 优点 1. 没有安全隐患 2. 可以水平扩展,数据库/缓存水平切分即可 3. web-server重启或扩容都不会丢失 - 不足 1. 增加了一次网络调用,并且需要修改相应的代码,如将所有的getSession方法替换为从Redis查数据的方式,redis获取数据比内存慢很多。 2. 上面的缺点可以用springSession完美解决。 ### 4 session共享问题解决-不同服务,子域session共享 ## 单点登录 ## 购物车 存储在Redis中,采用 hash (类似java中的map) java中存储 `Map>` java计算用bigDecimal ## 遇到的问题 **NoSuchMethodError: com.alibaba.fastjson.serializer.JavaBeanSerializer.processValue** https://github.com/alibaba/fastjson/issues/2780 需要升级 将fastjson从1.2.57升级到1.2.61 **199**