spring如何支持事务
@Transactional注解:加在方法上,表示方法受事务保护
不加参数:表示默认隔离级别,repeatable read
@Transactional
public Order createOrder(int userId, int itemId, int amount, Integer promotionId) {
// 校验参数
if (amount < 1 || (promotionId != null && promotionId.intValue() <= 0)) {
throw new BusinessException(PARAMETER_ERROR, "指定的参数不合法!");
}
加参数:影响事务传播机制
-
@Transactional(propagation = Propagation.REQUIRED)默认参数,可以不写。当前方法中没有启用事务,就生成事务事务。如果已经有事务(比如此处嵌套事务,外部方法有事务,还调用了该方法),就不做处理。
-
@Transactional(propagation = Propagation.REQUIRES_NEW):不管当前方法是不否在事务内,该方法都是个独立事务。
- 因为要generateOrderID()方法是独立的,希望id永远是递增的,即使createOrder方法失败,浪费一个id,id也不回滚
- 加注解,generateOrderID()方法受事务保护。方法开始自动给定事务,结束时,自动commit提交,中间抛异常自动回滚。底层是基于AOP实现。
@Transactional(propagation = Propagation.REQUIRES_NEW)
private String generateOrderID() {
StringBuilder sb = new StringBuilder();
// 拼入日期
sb.append(Toolbox.format(new Date(), "yyyyMMdd"));
// 获取流水号
SerialNumber serial = serialNumberMapper.selectByPrimaryKey("order_serial");
Integer value = serial.getValue();
// 更新流水号
serial.setValue(value + serial.getStep());
serialNumberMapper.updateByPrimaryKey(serial);
// 拼入流水号
String prefix = "000000000000".substring(value.toString().length());
sb.append(prefix).append(value);
return sb.toString();
}
-
创建流水号的方法serialNumberMapper.selectByPrimaryKey("order_serial"),根据主键查询流水【读】。方法的sql结尾加了
for update,X锁 -
generateOrderID()方法的事务a,读到这一行的时候,如果不加for update,有可能已经有别的事务b在改数据,加了X锁。此时基于MVCC原理,a不读正在改的数据,a读的是历史版本数据。但应该是读b更新完后的数据。
-
所以加for update【X锁】,与已经在改的b事务X锁互斥,等事务b改完之后,才轮到a。
-
强制事务不去读历史版本数据
select name, value, step
from serial_number
where name = #{name,jdbcType=VARCHAR} for update
云端部署
重点:项目——创建流水、云端部署、压测。原理——spring事务。
服务器部署Nginx,部署前端代码,配置反向代理,还有tomcat的秒杀代码
需要修改配置
- 配置test配置文件
- 把jdbc的MySQL公网ip改成本地ip,mysql和tomca都在云服务器上,本机就能访问
- 允许跨域的ip,改成公网ip
修改配置test环境log的xml文件 配置日志在服务器的存储路径
⭐项目代码用meaven打jar包,传到服务器上
——————环境变量path配置jdk的bin目录。(给meaven用)
- springboot的meaven插件,双击运行packang可以顺序执行等等测试+打包。
- test测试代码逻辑有数据处理的流程,复杂,手动敲命令跳过
mvn clean package -Dmaven.test.skip=true。清理target,打包,跳过测试代码。回车运行cd target。查看jar包是否打包成功scp seckill-0.0.1-SNAPSHOT.jar root@服务器IP:/root把包传到服务器。要输入密码
服务器上运行jar包,需要安装jdk
yum list java*显示安装包。yum install -y java-1.8.0-openjdk.aarch64。安装java version查看安装是否完成
- 后台启动jar,本地编写sh脚本启动,传到服务器上
nohup表示运行过程中出现日志信息,存到文件中不打印到控制台- “
&”结尾,表示后台启动。链接的客户端关了,仍在后台运行 java -jar xxx.jar表示启动xxxjar包文件--spring.profiles.active=test,指定配置文件的参数,运行test环境的配置文件-Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m,声明jvm内存空间大小。JVM最小最大分配1G内存,新生代0.5G- 查询seckill服务的端口,杀。每次启动是先杀掉现有旧的,在启动新的。
- pid=
ps aux | grep seckill | grep -v grep | awk '{print $2}' - kill -9 $pid
- pid=
scp startup. sh root@服务器IP:/root。上传脚本到服务器,要输入服务器密码
安装Nginx
yum list nginx*看包yum install -y nginx.aarch64安装
先启动tomcat再配置nginx
- 有JDK以后就能启动了
- 设置权限
- 启动启动文件
- 尝试访问tomcat。tomcat默认路径是8080端口。访问IP:8080
- 可以访问,配置完成
tomcat配置好了,没有前端代码访问麻烦。
⭐把前端代码装到nginx中
nginx -c /etc/nginx/nginx.conf启动Nginx,指定配置文件- 浏览器访问服务器IP,会看到Nginx默认页面
- 把本地前端代码压缩发到Nginx的前端访问文件夹中
- 本地压缩包路径下,打开cmd命令框,
scp seckill-site.zip root@服务器IP:/usr/share/nginx/html unzip seckill-site.zip解压,得到seckill-site文件夹【蓝色】- 修改参数。
cd seckill-site,cd js,vim common.js修改seckill-site/js目录下的common.js- 修改服务器路径。把本机IP改成
服务器IP:90
配置Nginx
cd etc/nginx,vim nginx.cong。修改配置- 需要两个虚拟server
- 一个监听80端口,代理web服务
- 一个监听90端口,代理后端代码
- 注释掉原有server部分
- 代理前端
- 监听80端口
location /访问路径是根路径。没有后缀,直接访问80端口。alias分发,代替根路径。index设施首页。访问80端口时,默认访问的页面。
- 负载均衡
- 监听90
server_name声明服务器名,防止重复,取为“_”下划线- 路径是根路径
proxy_pass http://myserver;,负载均衡,分发给其他服务器组。分发传给myserver处理。- myserver是自己配置的服务器组。多个服务器会均匀分发
- 配置服务器组
upstream配置- 配置本机虚拟server组地址。
- 超过三次访问失败就不访问(认为服务器组挂了?)。超过30s访问不到就认为访问失败,不再访问。
- ⭐
:wq保存退出文本编辑模式
- 重启Nginx。nginx -s reload
- 后台启动jar,本地编写sh脚本启动,传到服务器上
nohup表示运行过程中出现日志信息,存到文件中不打印到控制台- “
&”结尾,表示后台启动。链接的客户端关了,仍在后台运行 java -jar xxx.jar表示启动xxxjar包文件--spring.profiles.active=test,指定配置文件的参数,运行test环境的配置文件-Xms1024m -Xmx1024m -XX:NewSize=512m -XX:MaxNewSize=512m,声明jvm内存空间大小。JVM最小最大分配1G内存,新生代0.5G- 查询seckill服务的端口,杀。每次启动是先杀掉现有旧的,在启动新的。
- pid=
ps aux | grep seckill | grep -v grep | awk '{print $2}' - kill -9 $pid
- pid=
scp startup. sh root@服务器IP:/root。上传脚本到服务器,要输入服务器密码
安装jmeter,配置path变量。
cmd命令行,敲Jmeter打开软件
压测设置
- 创建线程组。50线程,10秒内,循环10次
- 创建取样器,http请求。设置参数。
- 指定协议、服务器IP、端口号90【因为监听后端】、请求类型、压测路径、编码格式
- 添加监听器-查看结果树
- 添加监听器聚合报告。样本:线程数、吞吐量:每秒处理请求数
- 保存
压测前先查看服务器状态
top -H,查看界面- load average系统负载,即任务队列的平均长度。三个数值分别为 1分钟、5分钟、15分钟前到现在的平均值。2核CPU要在2以下。
- us用户空间占CPU的百分比。在100%以下
- MySQL靠前,后面要降低占用的百分比
top命令及参数
原文链接:blog.csdn.net/langzi6/art…
带宽是瓶颈 压测商品界面:get请求,50/10/10 mysql,nginx都占用14% 吞吐量:43-74
新建测试组,http请求中,添加三个参数
添加配置元件-HTTP cookie管理器
配置cookie参数
压测“创建订单”:post请求。300/10/10 mysql占用14% 吞吐量300,因为库存少,后面都直接失败
可参考 原文链接:blog.csdn.net/qq_43950000…