通用Service + 多线程完美解决批处理问题
前言在对数据量大的情况下,进行批量操作的时候,效率直接拉跨,同时还要考虑事务机制问题。那是否有既简单又通用的批处理思路呢?当然,多线程执行批量任务就是一种十分重要的操作思路
步骤
获取数据库连接,控制事务机制
对大集合进行拆分成N个小集合。
开启线程池,对小集合进行批量更新操作,并返回执行结果。
线程批量提交,返回Future对象,进而判断事务是否需要提交或回滚
实战Servicepackage cn.goitman.service;import com.google.common.collect.Lists;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.sql.Connection;import java ...
SpringBoot同时支持 form 表单、form-data、json 的优雅写法
在 Java 中,一个接口只支持一种 content-type,json 就用 @RequestBody,form 表单就用 @RequestParam 或不写,form-data 就用 MultipartFile。
兼容版本如果要把在一个接口中同时兼容三种,比较笨的办法就是获取 HttpServletRequest,然后自己再写方法解析。类似如下:
private Map<String, Object> getParams(HttpServletRequest request) { String contentType = request.getContentType(); if (contentType.contains("application/json")) { // json 解析... return null; } else if (contentType.contains("application/x-www-form-urlencoded")) ...
一键部署Redis任意版本
今天给大家分享一个超级实用的脚本,Linux环境下一键自动安装部署Redis的任意版本,记住是任意版本哦!
脚本用法:chmod 755 redis-install.sh && sh redis-install.sh 4.0.10 (后面跟的是你需要的版本号,需要什么版本就写什么版本),我这里安装的4.0.10
执行脚本#! /usr/bin/bash##redis任何版本全程自动化源码编译安装##用法: sh redis-install.sh 4.0.10 (后面跟的是你需要的版本号,需要什么版本就写什么版本),我这里安装的4.0.10version=$1usage(){echo "usage: $0 version"}if [ $# -ne 1 ]thenusageexit -1fi#Redis安装包下载cd /usr/local/srcif [ ! -f redis-${version}.tar.gz ]thencurl -o /usr/local/src/redis-${version ...
Redis分布式锁的8大坑
在分布式系统中,由于Redis分布式锁相对于更简单和高效,成为了分布式锁的首先,被用到了很多实际业务场景当中。
但不是说用了Redis分布式锁,就可以高枕无忧了,如果没有用好或者用对,也会引来一些意想不到的问题。
今天一起聊聊Redis分布式锁的一些坑,给有需要的朋友一个参考。
非原子操作使用Redis的分布式锁,首先想到的可能是setNx命令。
if (jedis.setnx(lockKey, val) == 1) { jedis.expire(lockKey, timeout);}
容易,三下五除二就可以把代码写好。
这段代码确实可以加锁成功,但有没有发现什么问题?
加锁操作和后面的设置超时时间是分开的,并非原子操作。
假如加锁成功,但是设置超时时间失败了,该lockKey就变成永不失效。假如在高并发场景中,有大量的lockKey加锁成功了,但不会失效,有可能直接导致redis内存空间不足。
那么,有没有保证原子性的加锁命令呢?
答案是:有,请看下面。
忘了释放锁上面说到使用setNx命令加锁操作和设置超时时间是分开的,并非原子操作。
而在Redis ...
SpringBoot打包 + shell脚本部署
SpringBoot打包并结合shell脚本命令部署,重点在分享一个shell程序启动工具,希望能便利工作:
profiles指定不同环境的配置
maven-assembly-plugin打发布压缩包
shenniu_publish.sh程序启动工具
linux上使用shenniu_publish.sh启动程序
示例项目文件结构:
profiles指定不同环境的配置通常一套程序分为了很多个部署环境:开发,测试,uat,线上 等,要想对这些环境区分配置文件,可以通过两种方式:
通过application.yml中编码指定profile.active=uat方式指定
通过pom.xml中profiles来区分不同环境对应的配置文件夹,人工可以手动在idea勾选生成不同环境的包(推荐)
这里要讲的是第二种,首先在pom.xml中配置如下内容:
<profiles> <profile> <id>node</id> <properties> <!--传递给 ...
So easy 将程序部署到服务器
导入镜像打开VMWare,点击“打开虚拟机”,本文选择centos7.ova镜像存储路径
点击导入
选择“不再显示此消息”,点击“重试”按钮
点击“编辑虚拟机设置”,修改处理器、内存、硬盘等信息后,启动。按Ctrl+Alt键可以切换到windows下。启动成功后,输入账号root密码123456(帐号密码以镜像系统的设置为准),登录。
配置IP地址先在VMWare里设置好网络连接方式为桥接模式
有关于centos7获取IP地址的方法主要有两种,
动态获取ip
设置静态ip
动态获取ip前提是你的路由器已经开启了DHCP,修改网卡配置文件
vi /etc/sysconfig/network-scripts/ifcfg-enp0s3# ifcfg-enp0s3 为网卡名称
动态获取IP地址需要修改两处地方即可
BOOTPROTO="dhcp"ONBOOT="yes"
修改后重启一下网络服务即可 systemctl restart network
[root@mini ~]# systemctl restart network[r ...
延迟任务的10种实现方式
延迟任务的10种实现方式,主要内容如下:
手动无线循环
ScheduledExecutorService
DelayQueue
Redis zset 数据判断的方式
Redis 键空间通知的方式
Netty 提供的 HashedWheelTimer 工具类
RabbitMQ 死信队列
RabbitMQ 延迟消息插件 rabbitmq-delayed-message-exchange
Spring Scheduled
Quartz
什么是延迟任务顾明思议,我们把需要延迟执行的任务叫做延迟任务。延迟任务的使用场景有以下这些:
红包 24 小时未被查收,需要延迟执退还业务;
每个月账单日,需要给用户发送当月的对账单;
订单下单之后 30 分钟后,用户如果没有付钱,系统需要自动取消订单。
等事件都需要使用延迟任务。
延迟任务实现思路分析延迟任务实现的关键是在某个时间节点执行某个任务。基于这个信息我们可以想到实现延迟任务的手段有以下两个:
自己手写一个“死循环”一直判断当前时间节点有没有要执行的任务;
借助JDK或者第三方提供的工具类来实现延迟任务。
JDK 实现延迟任 ...
SpringBoot中实现跨域的 5 种方式
为什么会出现跨域问题出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
什么是跨域当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
非同源限制
无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
无法接触非同源网页的 DOM
无法向非同源地址发送 AJAX 请求
java实现对于 CORS的跨域请求,主要有以下几种方式可供选择:
返回新的CorsFilter
重写 WebMvcConfigurer
使用注解 @CrossOrigin
手动设置响应头 (HttpServletResponse)
自定 web filter 实现跨域
...
Redis高效点赞与取消功能
像CSDN的点赞功能只记录了数量,微信朋友圈的点赞功能有显示点赞人头像(获取userId查询用户信息封装返回即可)
点赞、取消点赞是高频次的操作,若每次都读写数据库,大量的操作会影响数据库性能,甚至宕机,所以用缓存处理再合适不过。本文以文章点赞为例来展开叙述
数据格式选择Redis有5种数据结构分别为:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
由于需要记录文章和点赞人,还有点赞状态(点赞、取消),分析下 Redis 数据格式中Hash最合适。
因为Hash里的数据都是存在一个Key中,通过Key很方便的把所有的点赞数据都取出。Key里面的数据还可以存成键值对的形式,方便存入点赞人、被点赞人和点赞状态。
文章 id 为 articleId,点赞人的 id 为 userId ,点赞状态为 1(点赞)和0(取消点赞)。文章 id 和点赞人 id 作为HashKey,两个 id 中间用::隔开,点赞状态作为HashValue。
整合SpringBoot依赖<dependency> <groupId> ...
So easy Spring事务回滚机制
事务控制的3种方式
编程式事务:直接在代码里手动开启事务,手动提交,手动回滚。优点就是可以灵活控制,缺点就是太麻烦了,太多重复的代码了。
声明式事务:就是使用Spring Aop配置事务,这种方式简化了编码。需要注意的是切入点表达式一定要写正确。
注解事务:直接在Service层的方法上面加上@Transactional注解,最简单方便的方式。
伪代码排序往后的方法报错,导致排序前的方法不回滚,如下:updataFlag方法出错,analyseRedBall 和 analyseBlueBall 方法不会回滚
public void statistics() { // 三个子方法中有操作数据库方法 analyseRedBall(periods, redBalls); analyseBlueBall(periods, blueBalls); updataFlag(periods);}
为什么不会滚呢Spring默认情况下是捕获到方法的RuntimeException异常,也就是说只要属于RuntimeException异常或及其子类都能回滚。不属于 ...