Schnittstellen-Idempotenz
Mehrere Anfragen desselben Benutzers haben die gleichen Auswirkungen auf die Ergebnisse wie eine einzige Anfrage, was als Idempotenz bezeichnet wird
Lösung: Erstellen Sie eine Anti-Heavy-Tabelle
CREATE TABLE `anti_repeat` (
`id` int(11) NOT NULL,
`msg` varchar(255) DEFAULT NULL COMMENT '描述信息',
`create_date` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Erstellen Sie einen Benutzertabellen-Mock
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`userName` varchar(255) DEFAULT NULL COMMENT '用户名',
`money` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8
dao
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yujie.model.AntiRepeat;
public interface AntiRepeatDao extends BaseMapper<AntiRepeat> {
}
----------------------------------------------------------------
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yujie.model.User;
public interface UserDao extends BaseMapper<User>{
}
Modell
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;
@TableName(value="anti_repeat")
public class AntiRepeat {
private Integer id;
private String msg;
private Date createDate;
public AntiRepeat(Integer id, String msg) {
this.id = id;
this.msg = msg;
}
public AntiRepeat(Integer id, String msg, Date createDate) {
this.id = id;
this.msg = msg;
this.createDate = createDate;
}
get...
set...
}
--------------------------------------------------------------------
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
@TableName(value = "t_user")
public class User implements Serializable {
private static final long serialVersionUID = -2929599080614903612L;
private Integer id;
private String username;
private Integer money;
get...
set...
}
Regler
@RestController
@RequestMapping("/thread")
public class ThreadController {
@Autowired
private UserService userService;
@RequestMapping("/subtraction")
public JsonResult subtraction(String username,int money, int id){
JsonResult jsonResult= new JsonResult();
try {
jsonResult = userService.subtraction(username, money, id);
}catch (Exception e){
System.out.println("请勿重复提交 ms:"+new Date().getTime());
jsonResult.setMsg("请勿重复提交");
jsonResult.setCode(500);
}
return jsonResult;
}
}
Service
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Autowired
private AntiRepeatDao antiRepeatDao;
@Transactional
@Override
public JsonResult subtraction(String username, int money, int id) {
AntiRepeat antiRepeat = antiRepeatDao.selectById(id);
if(antiRepeat != null){
throw new RuntimeException("请勿重复提交");
}
LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper();
lqw.eq(User::getUsername,username);
User user = userDao.selectOne(lqw);
user.setMoney(user.getMoney()-money);
int count = userDao.updateById(user);
JsonResult jsonResult = new JsonResult();
String str="用户:"+username+"扣减"+money+"金额";
if(count == 0){
jsonResult.setMsg(str+"失败");
jsonResult.setCode(500);
return jsonResult;
}
AntiRepeat antiRepeat1 = new AntiRepeat(id,str+"成功",new Date());
antiRepeatDao.insert(antiRepeat1);
System.out.println(str+"成功 ms:"+new Date().getTime());
return jsonResult;
}
}
Testlink http://localhost:8080/thread/subtraction?username=a&money=10&id=1 0086
Gleichzeitiger 100-Thread-Test mit JMeter
用户:a扣减10金额成功 ms:1675186191711
请勿重复提交 ms:1675186191717
请勿重复提交 ms:1675186191719
请勿重复提交 ms:1675186191721
请勿重复提交 ms:1675186191723
请勿重复提交 ms:1675186191725
请勿重复提交 ms:1675186191726
请勿重复提交 ms:1675186191728
请勿重复提交 ms:1675186191729
请勿重复提交 ms:1675186191733
In der Benutzertabelle können Sie sehen, dass Benutzer a erfolgreich von den ursprünglichen 100 Yuan auf 90 Yuan reduziert hat
In der Anti-Heavy-Tabelle können Sie sehen, dass es einen zusätzlichen Datensatz mit der ID 10086 gibt
总结以上就是保证了接口幂等性,流程:携带用户名和金额以及随机的id发送给后端,
后端防重表进行存储随机id,这个id的生成方式很重要,
同一个页面多次点击前端生成同一个id,只有服务器返回结果后才能改变id,
否则当前页面的id永不变
Der Nachteil besteht darin, dass der Server nicht auf den Benutzer geantwortet hat, wenn der Benutzer auf die Schaltfläche zum Aufladen klickt. Der Benutzer schließt die Seite und der alte ID-Wert wird zu diesem Zeitpunkt gespeichert. Wenn der Benutzer das nächste Mal den Browser zum Aufladen öffnet, wird er dies tun Finden Sie eine Erinnerung zum erneuten Senden. Zu diesem Zeitpunkt sollte die Rückkehr zum Status der wiederholten Übermittlung umgeleitet werden. Gehen Sie zur ersten Seite, um die ID zu aktualisieren, damit der Benutzer einmal auf die Schaltfläche zum Aufladen klicken kann. Wir sollten dasselbe tun. Zurück zum Wiederholte Übermittlungsaufforderung und Weiterleitung zur Startseite. Wenn der Benutzer das zweite Mal aufladen möchte, muss er einmal auf die Aufladeschaltfläche klicken. Die zweite Methode kann den Browser öffnen. Zufällige ID kann auch gelöst werden, wenn