Java监听mysql的binlog
- binlog
- mysql开启binlog
- 查看是否开启binlog
- 重启mysql服务
- 代码实现
- 运行结果
binlog
mysql开启binlog
修改mysql配置文件my.ini。添加下配置:
位于:C:\ProgramData\MySQL\MySQL Server 5.7
log_bin=mysql-bin
binlog-format=Row
查看是否开启binlog
1.正常开启状态
mysql> show variables like 'log_bin';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
1 row in set (0.02 sec)
mysql> show binary logs;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 154 |
+------------------+-----------+
1 row in set (0.09 sec)
2.权限不足情况
mysql> show binary logs;
1227 - Access denied; you need (at least one of) the SUPER, REPLICATION CLIENT privilege(s) for this operation
3.未开启状态(默认情况下是不开启的)
mysql> show binary logs;
ERROR 1381 - You are not using binary logging
重启mysql服务
我的电脑->(右键)管理->服务与应用程序->服务->MYSQL->开启(停止、重启动)
命令方式:net stop mysql、net start mysql
代码实现
引入依赖pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>test_binlog</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.4</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/args4j/args4j -->
<dependency>
<groupId>args4j</groupId>
<artifactId>args4j</artifactId>
<version>2.33</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.shyiko/mysql-binlog-connector-java -->
<dependency>
<groupId>com.github.shyiko</groupId>
<artifactId>mysql-binlog-connector-java</artifactId>
<version>0.17.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 9013
spring:
# 将thymeleaf 关闭缓存
thymeleaf:
cache: false
datasource:
# 注意:pom文件中,mysql版本为8以上时,驱动加 cj url加上 时区serverTimezone=GMT%2B8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://127.0.0.1:3306/test_binlog?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
hikari:
pool-name: Retail_HikariCP #连接池名称
minimum-idle: 10 #最小空闲连接数量
idle-timeout: 120000 #空闲连接存活最大时间,默认600000(10分钟)
maximum-pool-size: 20 #连接池最大连接数,默认是10
auto-commit: true #此属性控制从池返回的连接的默认自动提交行为,默认值:true
max-lifetime: 1800000 #此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
connection-timeout: 30000 #数据库连接超时时间,默认30秒,即30000
connection-test-query: SELECT 1
#showSql
logging:
level:
com:
example:
mapper: debug
# binlog listener
binlog:
columns: # 订阅binlog数据库连接信息,ip,端口,用户密码(用户必须要有权限)
host: 127.0.0.1
port: 3306
username: root
passwd: 123456
db: test_binlog # 监听数据库
table: user
mybatis:
mapper-locations: classpath*:mapper/**/*Mapper.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
BinLogConstants.java
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author zj
* @date 2022/10/09 16:55
* 监听配置信息
*/
@Data
@Component
public class BinLogConstants {
@Value("${binlog.columns.host}")
private String host;
@Value("${binlog.columns.port}")
private int port;
@Value("${binlog.columns.username}")
private String username;
@Value("${binlog.columns.passwd}")
private String passwd;
@Value("${binlog.db}")
private String db;
@Value("${binlog.table}")
private String table;
public static final int consumerThreads = 5;
public static final long queueSleep = 1000;
}
BinLogItem.java
import com.github.shyiko.mysql.binlog.event.EventType;
import com.google.common.collect.Maps;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
import static com.github.shyiko.mysql.binlog.event.EventType.isDelete;
import static com.github.shyiko.mysql.binlog.event.EventType.isWrite;
/**
* @author zj
* @date 2022/10/09 17:38
* binlog对象
*/
@Data
public class BinLogItem {
private static final long serialVersionUID = 5503152746318421290L;
private String dbTable;
private EventType eventType;
private Long timestamp = null;
private Long serverId = null;
// 存储字段-之前的值之后的值
private Map<String, Serializable> before = null;
private Map<String, Serializable> after = null;
// 存储字段--类型
private Map<String, Colum> colums = null;
/**
* 新增或者删除操作数据格式化
*/
public static BinLogItem itemFromInsertOrDeleted(Serializable[] row, Map<String, Colum> columMap, EventType eventType) {
if (null == row || null == columMap) {
return null;
}
if (row.length != columMap.size()) {
return null;
}
// 初始化Item
BinLogItem item = new BinLogItem();
item.eventType = eventType;
item.colums = columMap;
item.before = Maps.newHashMap();
item.after = Maps.newHashMap();
Map<String, Serializable> beOrAf = Maps.newHashMap();
columMap.entrySet().forEach(entry -> {
String key = entry.getKey();
Colum colum = entry.getValue();
beOrAf.put(key, row[colum.inx]);
});
// 写操作放after,删操作放before
if (isWrite(eventType)) {
item.after = beOrAf;
}
if (isDelete(eventType)) {
item.before = beOrAf;
}
return item;
}
/**
* 更新操作数据格式化
*/
public static BinLogItem itemFromUpdate(Map.Entry<Serializable[], Serializable[]> mapEntry, Map<String, Colum> columMap, EventType eventType) {
if (null == mapEntry || null == columMap) {
return null;
}
// 初始化Item
BinLogItem item = new BinLogItem();
item.eventType = eventType;
item.colums = columMap;
item.before = Maps.newHashMap();
item.after = Maps.newHashMap();
Map<String, Serializable> be = Maps.newHashMap();
Map<String, Serializable> af = Maps.newHashMap();
columMap.entrySet().forEach(entry -> {
String key = entry.getKey();
Colum colum = entry.getValue();
be.put(key, mapEntry.getKey()[colum.inx]);
af.put(key, mapEntry.getValue()[colum.inx]);
});
item.before = be;
item.after = af;
return item;
}
}
BinLogListener.java
/**
* @author zj
* @date 2022/10/09 18:05
* BinLogListener监听器
*/
@FunctionalInterface
public interface BinLogListener {
void onEvent(BinLogItem item);
}
BinLogUtils.java
import com.ccn.entity.User;
import com.ccn.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.github.shyiko.mysql.binlog.event.EventType;
import com.google.common.collect.Lists;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.Serializable;
import java.sql.*;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.github.shyiko.mysql.binlog.event.EventType.isDelete;
import static com.github.shyiko.mysql.binlog.event.EventType.isUpdate;
import static com.github.shyiko.mysql.binlog.event.EventType.isWrite;
/**
* @author zj
* @date 2022/10/09 18:02
* 监听工具
*/
@Slf4j
@Component
public class BinLogUtils {
private static BinLogUtils binLogUtils;
@Resource
private UserMapper userMapper;
@PostConstruct
public void init() {
binLogUtils = this;
binLogUtils.userMapper = this.userMapper;
}
/**
* 拼接dbTable
*/
public static String getdbTable(String db, String table) {
return db + "-" + table;
}
/**
* 获取columns集合
*/
public static Map<String, Colum> getColMap(Conf conf, String db, String table) throws ClassNotFoundException {
try {
Class.forName("com.mysql.jdbc.Driver");
// 保存当前注册的表的colum信息
Connection connection = DriverManager.getConnection("jdbc:mysql://" + conf.getHost() + ":" + conf.getPort(), conf.getUsername(), conf.getPasswd());
// 执行sql
String preSql = "SELECT TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME, DATA_TYPE, ORDINAL_POSITION FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? and TABLE_NAME = ?";
PreparedStatement ps = connection.prepareStatement(preSql);
ps.setString(1, db);
ps.setString(2, table);
ResultSet rs = ps.executeQuery();
Map<String, Colum> map = new HashMap<>(rs.getRow());
while (rs.next()) {
String schema = rs.getString("TABLE_SCHEMA");
String tableName = rs.getString("TABLE_NAME");
String column = rs.getString("COLUMN_NAME");
int idx = rs.getInt("ORDINAL_POSITION");
String dataType = rs.getString("DATA_TYPE");
if (column != null && idx >= 1) {
map.put(column, new Colum(schema, tableName, idx - 1, column, dataType)); // sql的位置从1开始
}
}
ps.close();
rs.close();
return map;
} catch (SQLException e) {
log.error("load db conf error, db_table={}:{} ", db, table, e);
}
return null;
}
/**
* 根据DBTable获取table
*
* @param dbTable
* @return java.lang.String
*/
public static String getTable(String dbTable) {
if (StrUtil.isEmpty(dbTable)) {
return "";
}
String[] split = dbTable.split("-");
if (split.length == 2) {
return split[1];
}
return "";
}
/**
* 将逗号拼接字符串转List
*
* @param str
* @return
*/
public static List<String> getListByStr(String str) {
if (StrUtil.isEmpty(str)) {
return Lists.newArrayList();
}
return Arrays.asList(str.split(","));
}
/**
* 根据操作类型获取对应集合
*
* @param binLogItem
* @return
*/
public static Map<String, Serializable> getOptMap(BinLogItem binLogItem) {
// 获取操作类型
EventType eventType = binLogItem.getEventType();
if (isWrite(eventType) || isUpdate(eventType)) {
return binLogItem.getAfter();
}
if (isDelete(eventType)) {
return binLogItem.getBefore();
}
return null;
}
/**
* 获取操作类型
*
* @param binLogItem
* @return
*/
public static Integer getOptType(BinLogItem binLogItem) {
// 获取操作类型
EventType eventType = binLogItem.getEventType();
if (isWrite(eventType)) {
return 1;
}
if (isUpdate(eventType)) {
return 2;
}
if (isDelete(eventType)) {
return 3;
}
return null;
}
/**
* 根据storeId获取imgUrl
*/
public static String getImgUrl(Long storeId) {
if (storeId == null) {
return "";
}
//获取url
User searchStoreLogo = new User();
searchStoreLogo.setId(storeId);
List<User> searchStoreLogos = binLogUtils.userMapper.selectList(searchStoreLogo);
if (CollectionUtil.isNotEmpty(searchStoreLogos)) {
User storeLogo = searchStoreLogos.get(0);
if (storeLogo != null) {
return storeLogo.getName();
}
}
return "";
}
/**
* 格式化date
*
* @param date
* @return java.util.Date
*/
public static Date getDateFormat(Date date) {
if (date == null) {
return null;
}
String dateFormat = "yyyy-MM-dd HH:mm:ss";
String strDate = DateUtil.format(date, dateFormat);
if (StrUtil.isEmpty(strDate)) {
return null;
}
Date formatDate = DateUtil.parse(strDate, dateFormat);
return formatDate;
}
}
Colum.java
import lombok.Data;
/**
* @author zj
* @date 2022/10/09 17:46
* 字段属性对象
*/
@Data
public class Colum {
public int inx;
public String colName; // 列名
public String dataType; // 类型
public String schema; // 数据库
public String table; // 表
public Colum(String schema, String table, int idx, String colName, String dataType) {
this.schema = schema;
this.table = table;
this.colName = colName;
this.dataType = dataType;
this.inx = idx;
}
}
Conf.java
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* @author zj
* @date 2022/10/09 17:38
* 数据库配置
*/
@Data
@AllArgsConstructor
public class Conf {
private String host;
private int port;
private String username;
private String passwd;
}
MysqlBinLogListener.java
import com.github.shyiko.mysql.binlog.BinaryLogClient;
import lombok.extern.slf4j.Slf4j;
import com.github.shyiko.mysql.binlog.event.*;
import com.github.shyiko.mysql.binlog.event.deserialization.EventDeserializer;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import org.kohsuke.args4j.Option;
import java.io.IOException;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.*;
import static com.ccn.util.BinLogUtils.getColMap;
import static com.ccn.util.BinLogUtils.getdbTable;
import static com.github.shyiko.mysql.binlog.event.EventType.*;
/**
* @author zj
* @date 2022/10/09 18:06
* 数据库监听器
*/
@Slf4j
public class MysqlBinLogListener implements BinaryLogClient.EventListener {
@Option(name = "-binlog-consume_threads", usage = "the thread num of consumer")
private int consumerThreads = BinLogConstants.consumerThreads;
private BinaryLogClient parseClient;
private BlockingQueue<BinLogItem> queue;
private final ExecutorService consumer;
// 存放每张数据表对应的listener
private Multimap<String, BinLogListener> listeners;
private Conf conf;
private Map<String, Map<String, Colum>> dbTableCols;
private String dbTable;
/**
* 监听器初始化
*
* @param conf
*/
public MysqlBinLogListener(Conf conf) {
BinaryLogClient client = new BinaryLogClient(conf.getHost(), conf.getPort(), conf.getUsername(), conf.getPasswd());
EventDeserializer eventDeserializer = new EventDeserializer();
//eventDeserializer.setCompatibilityMode(//序列化
// EventDeserializer.CompatibilityMode.DATE_AND_TIME_AS_LONG,
// EventDeserializer.CompatibilityMode.CHAR_AND_BINARY_AS_BYTE_ARRAY
//);
client.setEventDeserializer(eventDeserializer);
this.parseClient = client;
this.queue = new ArrayBlockingQueue<>(1024);
this.conf = conf;
this.listeners = ArrayListMultimap.create();
this.dbTableCols = new ConcurrentHashMap<>();
this.consumer = Executors.newFixedThreadPool(consumerThreads);
}
/**
* 监听处理
*
* @param event
*/
@Override
public void onEvent(Event event) {
EventType eventType = event.getHeader().getEventType();
if (eventType == EventType.TABLE_MAP) {
TableMapEventData tableData = event.getData();
String db = tableData.getDatabase();
String table = tableData.getTable();
dbTable = getdbTable(db, table);
}
// 只处理添加删除更新三种操作
if (isWrite(eventType) || isUpdate(eventType) || isDelete(eventType)) {
if (isWrite(eventType)) {
WriteRowsEventData data = event.getData();
for (Serializable[] row : data.getRows()) {
if (dbTableCols.containsKey(dbTable)) {
BinLogItem item = BinLogItem.itemFromInsertOrDeleted(row, dbTableCols.get(dbTable), eventType);
item.setDbTable(dbTable);
queue.add(item);
}
}
}
if (isUpdate(eventType)) {
UpdateRowsEventData data = event.getData();
for (Map.Entry<Serializable[], Serializable[]> row : data.getRows()) {
if (dbTableCols.containsKey(dbTable)) {
BinLogItem item = BinLogItem.itemFromUpdate(row, dbTableCols.get(dbTable), eventType);
item.setDbTable(dbTable);
queue.add(item);
}
}
}
if (isDelete(eventType)) {
DeleteRowsEventData data = event.getData();
for (Serializable[] row : data.getRows()) {
if (dbTableCols.containsKey(dbTable)) {
BinLogItem item = BinLogItem.itemFromInsertOrDeleted(row, dbTableCols.get(dbTable), eventType);
item.setDbTable(dbTable);
queue.add(item);
}
}
}
}
}
/**
* 注册监听
*
* @param db 数据库
* @param table 操作表
* @param listener 监听器
* @throws Exception
*/
public void regListener(String db, String table, BinLogListener listener) throws Exception {
String dbTable = getdbTable(db, table);
// 获取字段集合
Map<String, Colum> cols = getColMap(conf, db, table);
// 保存字段信息
dbTableCols.put(dbTable, cols);
// 保存当前注册的listener
listeners.put(dbTable, listener);
}
/**
* 开启多线程消费
*
* @throws IOException
*/
public void parse() throws IOException {
parseClient.registerEventListener(this);
for (int i = 0; i < consumerThreads; i++) {
consumer.submit(() -> {
while (true) {
if (queue.size() > 0) {
try {
BinLogItem item = queue.take();
String dbtable = item.getDbTable();
listeners.get(dbtable).forEach(binLogListener -> binLogListener.onEvent(item));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Thread.sleep(BinLogConstants.queueSleep);
}
});
}
parseClient.connect();
}
}
TourBinLogListener.java
import cn.hutool.core.collection.CollectionUtil;
import com.ccn.entity.User;
import com.ccn.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* 乐游监听器
* SpringBoot启动成功后的执行业务线程操作
* CommandLineRunner去实现此操作
* 在有多个可被执行的业务时,通过使用 @Order 注解,设置各个线程的启动顺序(value值由小到大表示启动顺序)。
* 多个实现CommandLineRunner接口的类必须要设置启动顺序,不让程序启动会报错!
*
* @author zj
* @since 2022/10/09 18:07
**/
@Slf4j
@Component
@Order(value = 1)
public class TourBinLogListener implements CommandLineRunner {
@Resource
private BinLogConstants binLogConstants;
@Autowired
private UserMapper userMapper;
@Override
public void run(String... args) throws Exception {
log.info("初始化配置信息:" + binLogConstants.toString());
// 初始化配置信息
Conf conf = new Conf(binLogConstants.getHost(), binLogConstants.getPort(), binLogConstants.getUsername(), binLogConstants.getPasswd());
// 初始化监听器
MysqlBinLogListener mysqlBinLogListener = new MysqlBinLogListener(conf);
// 获取table集合
List<String> tableList = BinLogUtils.getListByStr(binLogConstants.getTable());
if (CollectionUtil.isEmpty(tableList)) {
return;
}
// 注册监听
tableList.forEach(table -> {
log.info("注册监听信息,注册DB:" + binLogConstants.getDb() + ",注册表:" + table);
try {
mysqlBinLogListener.regListener(binLogConstants.getDb(), table, item -> {
log.info("监听逻辑处理");
Map<String, Serializable> after = item.getAfter();
Map<String, Serializable> before = item.getBefore();
System.out.println("after---------" + after.isEmpty());
System.out.println("before---------" + before.isEmpty());
if (!after.isEmpty()){
List<User> users = userMapper.getList1();
System.out.println(users.get(0));
}
if (!before.isEmpty()){
List<User> users = userMapper.getList2();
System.out.println(users.get(0));
}
});
} catch (Exception e) {
log.error("BinLog监听异常:" + e);
}
});
// 多线程消费
mysqlBinLogListener.parse();
}
}
UserMapper.java
import com.ccn.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author zj
* @date 2022/10/09 16:51
*/
@Repository
public interface UserMapper {
List<User> selectList(User user);
@Insert("insert into user values(#{id},#{name},#{userNo},#{createTime})")
void add(User user);
@Delete("delete from user where id=#{id}")
void del(Long id);
@Select("select * from user limit 0,2 ")
List<User> getList1();
@Select("select * from user limit 1,3 ")
List<User> getList2();
}
User.java
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* @author zj
* @date 2022/10/09 16:54
*/
@Data
@TableName("user")
public class User {
@TableId(value = "id")
private Long id;
@TableField("name")
private String name;
@TableField("user_no")
private String userNo;
@TableField("create_time")
private Date createTime;
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", userNo='" + userNo + '\'' +
", createTime=" + createTime +
'}';
}
}
UserController.java
import com.ccn.entity.User;
import com.ccn.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
/**
* @author zj
* @date 2022/10/09 16:40
*/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@GetMapping("/add")
public String add(){
User user = new User();
user.setId(4L);
user.setName("aaa");
user.setUserNo("222");
user.setCreateTime(new Date());
userMapper.add(user);
return "成功";
}
@GetMapping("/del")
public String del(){
userMapper.del(4L);
return "成功";
}
}
运行结果