Mybatis自动生成插件虽然功能强大,但是也略显笨重。我自己开发了一个自动生成的小工具,更加简单,更加轻量级。
一共只有几百行代码,想改的话,直接修改即可。根据自己的实际情况,可以进行灵活的二次开发。
Talk is cheap,show me the code.
自己写的,可以直接跑。如有问题,请联系,谢谢。
一,程序入口核心类:GenSqlXml.java
package cn.sephora.product.elasticsearch.service.impl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
/**
* 功能:根据mysql建表语句文件(XXX.sql),自动生成mapper文件(XXXMapper.xml)
* @date 2019/12/13
* @address shanghai
*
*/
public class GenSqlXml {
/**
* 源文件路径
*/
private static final String SOURCE_FILE_PATH = "D:\\sourcefile\\";
/**
* 源文件名称
*/
private static final String SOURCE_FILE_NAME = "table_create";
/**
* 源文件后缀
*/
private static final String SOURCE_FILE_SUFFIX = "sql";
/**
* 目标文件路径
*/
private static final String TARGET_FILE_PATH = "D:\\targetfile\\";
/**
* 目标文件名称
*/
private static final String TARGET_FILE_NAME = "SqlMapper";
/**
* 目标文件后缀
*/
private static final String TARGET_FILE_SUFFIX = "xml";
/**
* 换行符
*/
private static final String LINE_BREAK = "\r\n";
/**
* sqlxml文件的namespace
*/
private static final String NAMESPACE = "cn.xxx.xxx.dao.StoreActivityDao";
public static void main(String[] args) {
File fileObj = new File(SOURCE_FILE_PATH + SOURCE_FILE_NAME + "." + SOURCE_FILE_SUFFIX);
ParseSqlFile parseSqlFile = new ParseSqlFile();
TableInfo tableInfo = parseSqlFile.getFieldInfo(fileObj);
GenSqlXml genSqlXml = new GenSqlXml();
genSqlXml.genSqlXmlFile(tableInfo);
}
public void genSqlXmlFile(TableInfo tableInfo) {
genTargetSqlXmlFile(tableInfo);
}
private void genTargetSqlXmlFile(TableInfo tableInfo) {
FileOutputStream fos = null;
try {
File f1 = new File(TARGET_FILE_PATH + TARGET_FILE_NAME + "." + TARGET_FILE_SUFFIX);
if (!f1.exists()){
f1.getParentFile().mkdirs();
}
fos = new FileOutputStream(f1);
// 生成文件头
fos.write(("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + LINE_BREAK).getBytes());
fos.write(("<!DOCTYPE mapper" + LINE_BREAK).getBytes());
fos.write((" PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\"" + LINE_BREAK).getBytes());
fos.write((" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">" + LINE_BREAK).getBytes());
fos.write(("<mapper namespace=\"" + NAMESPACE + "\">" + LINE_BREAK).getBytes());
fos.write(LINE_BREAK.getBytes());
// 生成select语句
genSelet(fos, tableInfo);
// 生成insert语句
genInsert(fos, tableInfo);
// 生成update语句
genUpdate(fos, tableInfo);
// 生成delete语句
genDelete(fos, tableInfo);
// 生成文件尾部
fos.write(("</mapper>" + LINE_BREAK).getBytes());
} catch (IOException e) {
System.out.println("catch " + e);
} finally {
try {
fos.close();
} catch (IOException e) {
System.out.println("finally " + e);
}
}
}
/**
* 生成select语句
* @param fos
* @param tableInfo
*/
private void genSelet(FileOutputStream fos, TableInfo tableInfo){
List<FieldInfo> list = tableInfo.getFieldList();
String resultMapId = "BaseResultMap";
try {
// <resultMap>
fos.write((" <resultMap id=" + resultMapId + " type=\"cn.xxx.xxx.dao.model.MktResourceModel\">" + LINE_BREAK).getBytes());
fos.write((" <id column=\"" + tableInfo.getPrimaryKeyDB() + "\" property=\"" + tableInfo.getPrimaryKeyJava() + "\" jdbcType=\"" + tableInfo.getPrimaryKeyDataType().toUpperCase() + "\" />" + LINE_BREAK).getBytes());
for (FieldInfo fieldInfo : list) {
fos.write((" <result column=\"" + fieldInfo.getFieldNameDB() + "\" property=\"" + fieldInfo.getFieldNameJava() + "\" jdbcType=\"" + fieldInfo.getDataTypeMysql().toUpperCase() + "\" />" + LINE_BREAK).getBytes());
}
fos.write((" </resultMap>" + LINE_BREAK).getBytes());
fos.write(LINE_BREAK.getBytes());
// <sql>
StringBuffer fieldListDBStr = new StringBuffer();
fos.write((" <sql id=\"Base_Column_List\">" + LINE_BREAK).getBytes());
for (FieldInfo fieldInfo : list) {
fieldListDBStr.append(fieldInfo.getFieldNameDB()).append(",");
}
fos.write((" " + fieldListDBStr.substring(0, fieldListDBStr.lastIndexOf(",")).toString() + LINE_BREAK).getBytes());
fos.write((" </sql>" + LINE_BREAK).getBytes());
fos.write(LINE_BREAK.getBytes());
// <select>
fos.write((" <select id=\"selectByPrimaryKey\" resultMap=\"BaseResultMap\" parameterType=\"java.lang.String\">" + LINE_BREAK).getBytes());
fos.write((" select <include refid=\"" + resultMapId + "\" />" + LINE_BREAK).getBytes());
fos.write((" from " + tableInfo.getTableName() + LINE_BREAK).getBytes());
fos.write((" where " + tableInfo.getPrimaryKeyDB() + " = #{" + tableInfo.getPrimaryKeyJava() + ",jdbcType=" + tableInfo.getPrimaryKeyDataType().toUpperCase() + "}" + LINE_BREAK).getBytes());
fos.write((" </sql>" + LINE_BREAK).getBytes());
fos.write(LINE_BREAK.getBytes());
} catch (IOException e) {
System.out.println("genSelect IOException " + e);
}
}
/**
* 生成insert语句
* @param fos
* @param tableInfo
*/
private void genInsert(FileOutputStream fos, TableInfo tableInfo){
String tableName = tableInfo.getTableName();
String primaryKeyDB = tableInfo.getPrimaryKeyDB();
List<FieldInfo> list = tableInfo.getFieldList();
StringBuffer fieldListDBStr = new StringBuffer();
StringBuffer fieldListJavaStr = new StringBuffer();
for (FieldInfo fieldInfo : list) {
fieldListDBStr.append(fieldInfo.getFieldNameDB()).append(",");
fieldListJavaStr.append("#{").append(fieldInfo.getFieldNameJava()).append("},");
}
String fieldListDBStrFinal = fieldListDBStr.toString().substring(0, fieldListDBStr.toString().length() - 1);
String fieldListJavaStrFinal = fieldListJavaStr.toString().substring(0, fieldListJavaStr.toString().length() - 1);
try {
fos.write((" <insert id=\"insert\" parameterType=\"cn.xxx.xxx.dao.model.StoreModel\">" + LINE_BREAK).getBytes());
fos.write((" insert into " + tableName + " (" + fieldListDBStrFinal + ")" + LINE_BREAK).getBytes());
fos.write((" select " + " " + fieldListJavaStrFinal + LINE_BREAK).getBytes());
fos.write((" from dual" + LINE_BREAK).getBytes());
fos.write((" where not exists(select " + primaryKeyDB + " from " + tableName + " where " + primaryKeyDB + " = #{" + tableInfo.getPrimaryKeyJava() + "}" + LINE_BREAK).getBytes());
fos.write(("\t</insert>" + LINE_BREAK).getBytes());
fos.write(LINE_BREAK.getBytes());
} catch (IOException e) {
System.out.println("genInsert IOException " + e);
}
}
/**
* 生成update语句
* 注意:update语句,需要执行jdbcType
* @param fos
* @param tableInfo
*/
private void genUpdate(FileOutputStream fos, TableInfo tableInfo){
String tableName = tableInfo.getTableName();
String primaryKeyDB = tableInfo.getPrimaryKeyDB();
List<FieldInfo> list = tableInfo.getFieldList();
try {
fos.write((" <update id=\"updateByPrimaryKey\" parameterType=\"cn.xxx.xxx.dao.model.StoreActivityModel\">" + LINE_BREAK).getBytes());
fos.write((" update " + tableName + LINE_BREAK).getBytes());
fos.write((" <set>" + LINE_BREAK).getBytes());
for (FieldInfo fieldInfo : list) {
fos.write((" <if test=\"" + fieldInfo.getFieldNameJava() + " != null\">" + LINE_BREAK).getBytes());
fos.write((" " + fieldInfo.getFieldNameDB() + " = #{" + fieldInfo.getFieldNameJava() + ",jdbcType=" + fieldInfo.getDataTypeMysql().toUpperCase() + "}" + LINE_BREAK).getBytes());
fos.write((" </if>" + LINE_BREAK).getBytes());
}
fos.write((" </set>" + LINE_BREAK).getBytes());
fos.write((" where " + primaryKeyDB + " = #{" + tableInfo.getPrimaryKeyJava() + ",jdbcType=" + tableInfo.getPrimaryKeyDataType().toUpperCase() + "}" + LINE_BREAK).getBytes());
fos.write((" </update>" + LINE_BREAK).getBytes());
fos.write(LINE_BREAK.getBytes());
} catch (IOException e) {
System.out.println("genUpdate IOException " + e);
}
}
/**
* 生成delete语句
* @param fos
* @param tableInfo
*/
private void genDelete(FileOutputStream fos, TableInfo tableInfo){
try {
fos.write((" <delete id=\"deleteByPrimaryKey\" parameterType=\"String\">" + LINE_BREAK).getBytes());
fos.write((" delete from " + tableInfo.getTableName() + " where " + tableInfo.getPrimaryKeyDB() + " = #{" + tableInfo.getPrimaryKeyJava() + "}" + LINE_BREAK).getBytes());
fos.write((" </delete>" + LINE_BREAK).getBytes());
fos.write(LINE_BREAK.getBytes());
} catch (IOException e) {
System.out.println("genDelete IOException " + e);
}
}
}
二,建表语句文件解析类:ParseSqlFile.java
package cn.sephora.product.elasticsearch.service.impl;
import org.apache.commons.lang.StringUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @description 解析建表sql文件,生成对应的封装对象TableInfo
* @date 2019/12/13
* @address shanghai
*
*/
public class ParseSqlFile {
/**
* Mysql建表语句关键字
*/
private final static Map<String, String> MYSQL_KEY_WORD_MAP = new HashMap();
static {
MYSQL_KEY_WORD_MAP.put("ENGINE", "ENGINE");
MYSQL_KEY_WORD_MAP.put("CHARACTER", "CHARACTER");
MYSQL_KEY_WORD_MAP.put("COLLATE", "COLLATE");
}
/**
* 解析sql建表语句文件,得到FieldInfo集合
* @param fileObj
* @return
*/
public TableInfo getFieldInfo(File fileObj) {
BufferedReader reader = null;
InputStream in = null;
TableInfo tableInfo = new TableInfo();
List<FieldInfo> list = new ArrayList<>();
List<FieldInfo> listParsed = null;
try {
reader = new BufferedReader(new FileReader(fileObj));
in = new FileInputStream(fileObj);
String line = null;
int count = 0;
while((line = reader.readLine()) != null) {
// 第一行
if (line.toUpperCase().contains("CREATE TABLE")) {
tableInfo.setTableName(parseTableName(line));
continue;
}
// PRIMARY KEY 行
if (line.toUpperCase().contains("PRIMARY KEY")) {
tableInfo.setPrimaryKeyDB(line.substring(line.indexOf("(") + 1, line.indexOf(")")));
continue;
}
// 建表语句结束的右括号 行
if (line.trim().startsWith(")")) {
continue;
}
// 表备注信息
if (line.trim().toUpperCase().startsWith("COMMENT")) {
continue;
}
boolean keyWordFlag = false;
for (Map.Entry<String, String> entry : MYSQL_KEY_WORD_MAP.entrySet()) {
if (line.toUpperCase().contains(entry.getKey())) {
keyWordFlag = true;
break;
}
}
if (keyWordFlag){
continue;
}
// 递归处理,拿到字段名/字段类型/字段备注信息,然后存入ArrayList
parseFiledInfo(line, list);
}
listParsed = convertMysql2Java(list, tableInfo);
tableInfo.setFieldList(listParsed);
} catch (IOException e) {
System.out.println(" catch 分支 IOException " + e);
} finally {
try {
in.close();
} catch (IOException e){
System.out.println(" finally 分支 IOException " + e);
}
}
return tableInfo;
}
private String parseTableName(String line) {
return line.replaceFirst("CREATE", "").replaceFirst("TABLE", "").replaceFirst("\\(", "").trim().toLowerCase();
}
private List<FieldInfo> parseFiledInfo(String line, List<FieldInfo> list) {
// 去掉每行前面的空格
String lineWithoutFrontBlank = parLineFrontBlank(line);
// 字段名
String fieldNameDB = lineWithoutFrontBlank.substring(0, lineWithoutFrontBlank.indexOf(" "));
// 字段备注信息
String comment = lineWithoutFrontBlank.substring(lineWithoutFrontBlank.indexOf("'") + 1, lineWithoutFrontBlank.lastIndexOf("'"));
String lineNotStartsWithBlankAndFieldName = parLineFrontBlank(lineWithoutFrontBlank.substring(lineWithoutFrontBlank.indexOf(" ")));
// 字段数据类型
String dataTypeMysql = lineNotStartsWithBlankAndFieldName.substring(0, lineNotStartsWithBlankAndFieldName.indexOf(" "));
// 去掉数据类型后面的括号内容
if (dataTypeMysql.trim().endsWith(")")) {
dataTypeMysql = dataTypeMysql.substring(0, dataTypeMysql.indexOf("("));
}
FieldInfo fieldInfo = new FieldInfo(fieldNameDB, null, dataTypeMysql, null, comment);
list.add(fieldInfo);
return list;
}
/**
* 递归去掉每行前面的空格
* @param tempStr
* @return
*/
private String parLineFrontBlank(String tempStr) {
if (tempStr.startsWith(" ")) {
String newTempStr = tempStr.substring(1);
return parLineFrontBlank(newTempStr);
}
return tempStr;
}
private List<FieldInfo> convertMysql2Java(List<FieldInfo> list, TableInfo tableInfo) {
List<FieldInfo> listParsed = new ArrayList<>();
for (FieldInfo fieldInfo : list) {
// 如果该字段是主键
if (StringUtils.equals(fieldInfo.getFieldNameJava(), tableInfo.getPrimaryKeyJava())) {
tableInfo.setPrimaryKeyJava(mappingMysqlFieldName2Java(tableInfo.getPrimaryKeyDB()));
tableInfo.setPrimaryKeyDataType(fieldInfo.getDataTypeMysql());
}
// mysql字段转java字段
fieldInfo.setFieldNameJava(mappingMysqlFieldName2Java(fieldInfo.getFieldNameDB()));
// mysql字段类型 转 java 数据类型
fieldInfo.setDataTypeJava(mappingMysqlDataType2Java(fieldInfo.getDataTypeMysql()));
listParsed.add(fieldInfo);
}
return listParsed;
}
private String mappingMysqlDataType2Java(String dataTypeMysql) {
// 字符串
if (MysqlDataTypeConstants.MYSQL_DATA_TYPE_VARCHAR.containsValue(dataTypeMysql.toLowerCase())) {
return "String";
}
// 整形
if (MysqlDataTypeConstants.MYSQL_DATA_TYPE_INT.containsValue(dataTypeMysql.toLowerCase())) {
return "Integer";
}
// 长整形
if (MysqlDataTypeConstants.MYSQL_DATA_TYPE_LONG.containsValue(dataTypeMysql.toLowerCase())) {
return "Long";
}
// date
if (MysqlDataTypeConstants.MYSQL_DATA_TYPE_DATE.containsValue(dataTypeMysql.toLowerCase())) {
return "Date";
}
return dataTypeMysql;
}
/**
* Mysql字段名称转java字段名称
* @param filedName
* @return
*/
private String mappingMysqlFieldName2Java(String filedName) {
// 去掉数据类型后面的括号内容
if (!filedName.contains("_")) {
return filedName;
}
return parseUnderLine(filedName);
}
/**
* 递归处理Mysql字段名称中的下划线
*/
private String parseUnderLine(String filedName) {
int underLineIndex = filedName.indexOf("_");
String parsedFieldName = filedName.replaceFirst(filedName.substring(underLineIndex, underLineIndex + 2), filedName.substring(underLineIndex + 1, underLineIndex + 2).toUpperCase());
if (!parsedFieldName.contains("_")) {
return parsedFieldName;
}
return parseUnderLine(parsedFieldName);
}
}
三,建表语句中所有表字段封装实体类:FieldInfo.java
package cn.sephora.product.elasticsearch.service.impl;
/**
* @description 字段数据接口
* @date 2019/12/13
* @address shanghai
*
*/
public class FieldInfo {
/**
* 字段名(数据库字段格式)
*/
private String fieldNameDB;
/**
* 字段名(java驼峰格式)
*/
private String fieldNameJava;
/**
* mysql数据类型
*/
private String dataTypeMysql;
/**
* java数据类型
*/
private String dataTypeJava;
/**
* 字段conmment备注信息
*/
private String comment;
public FieldInfo(String fieldNameDB, String fieldNameJava, String dataTypeMysql, String dataTypeJava, String comment) {
this.fieldNameDB = fieldNameDB;
this.fieldNameJava = fieldNameJava;
this.dataTypeMysql = dataTypeMysql;
this.dataTypeJava = dataTypeJava;
this.comment = comment;
}
public String getFieldNameDB() {
return fieldNameDB;
}
public void setFieldNameDB(String fieldNameDB) {
this.fieldNameDB = fieldNameDB;
}
public String getFieldNameJava() {
return fieldNameJava;
}
public void setFieldNameJava(String fieldNameJava) {
this.fieldNameJava = fieldNameJava;
}
public String getDataTypeMysql() {
return dataTypeMysql;
}
public void setDataTypeMysql(String dataTypeMysql) {
this.dataTypeMysql = dataTypeMysql;
}
public String getDataTypeJava() {
return dataTypeJava;
}
public void setDataTypeJava(String dataTypeJava) {
this.dataTypeJava = dataTypeJava;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
四,建表语句对应实体类:TableInfo.java
package cn.sephora.product.elasticsearch.service.impl;
import java.util.List;
/**
* @description 解析建表sql生成的对象
* @date 2019/12/13
* @address shanghai
*
*/
public class TableInfo {
/**
* 表名
*/
private String tableName;
/**
* 主键(数据库字段名格式)
*/
private String primaryKeyDB;
/**
* 主键(java驼峰命名格式)
*/
private String primaryKeyJava;
/**
* 主键的数据类型
*/
private String primaryKeyDataType;
/**
* 表字段集合
*/
private List<FieldInfo> fieldList;
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getPrimaryKeyDB() {
return primaryKeyDB;
}
public void setPrimaryKeyDB(String primaryKeyDB) {
this.primaryKeyDB = primaryKeyDB;
}
public String getPrimaryKeyJava() {
return primaryKeyJava;
}
public void setPrimaryKeyJava(String primaryKeyJava) {
this.primaryKeyJava = primaryKeyJava;
}
public String getPrimaryKeyDataType() {
return primaryKeyDataType;
}
public void setPrimaryKeyDataType(String primaryKeyDataType) {
this.primaryKeyDataType = primaryKeyDataType;
}
public List<FieldInfo> getFieldList() {
return fieldList;
}
public void setFieldList(List<FieldInfo> fieldList) {
this.fieldList = fieldList;
}
}
五,常量定义类:MysqlDataTypeConstants.java
package cn.sephora.product.elasticsearch.service.impl;
import java.util.HashMap;
import java.util.Map;
/**
* @description 常量定义
* @date 2019/12/13
* @address shanghai
*
*/
public class MysqlDataTypeConstants {
/**
* Mysql数据类型之字符串
*/
public final static Map<String, String> MYSQL_DATA_TYPE_VARCHAR = new HashMap();
static {
MYSQL_DATA_TYPE_VARCHAR.put("varchar", "varchar");
MYSQL_DATA_TYPE_VARCHAR.put("json", "json");
MYSQL_DATA_TYPE_VARCHAR.put("char", "char");
}
/**
* Mysql数据类型之整形
*/
public final static Map<String, String> MYSQL_DATA_TYPE_INT = new HashMap();
static {
MYSQL_DATA_TYPE_INT.put("int", "int");
MYSQL_DATA_TYPE_INT.put("bit", "bit");
}
/**
* Mysql数据类型之长整形
*/
public final static Map<String, String> MYSQL_DATA_TYPE_LONG = new HashMap();
static {
MYSQL_DATA_TYPE_LONG.put("bigint", "bigint");
MYSQL_DATA_TYPE_LONG.put("long", "long");
}
/**
* Mysql数据类型之整形
*/
public final static Map<String, String> MYSQL_DATA_TYPE_DATE = new HashMap();
static {
MYSQL_DATA_TYPE_DATE.put("datetime", "datetime");
MYSQL_DATA_TYPE_DATE.put("timestamp", "timestamp");
}
}
六,sql文件模板:table_create.sql
注意,这个文件的路径是:D:\sourcefile,如果需要修改,请把源码中的对应路径也修改掉。
CREATE TABLE product_info (
product_id bigint COMMENT '产品编号' NOT NULL,
product_name varchar(128) COMMENT '产品名称' NOT NULL,
status varchar(20) COMMENT '产品状态 0-未上架 1-已上架 2-已下架 3-已删除',
create_time timestamp COMMENT '创建时间' NOT NULL,
update_time timestamp COMMENT '最后更新时间' NOT NULL,
PRIMARY KEY(activity_id) USING BTREE
)
COMMENT = '产品信息'
ENGINE = InnoDB
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;
七,运行生成的model文件示例SqlMapper.xml
默认生成文件的路径是:D:\targetfile,如果需要修改,请把源码中的对应路径也修改掉。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.xxx.xxx.dao.StoreActivityDao">
<resultMap id=BaseResultMap type="cn.xxx.xxx.dao.model.MktResourceModel">
<id column="activity_id" property="activityId" jdbcType="BIGINT" />
<result column="product_id" property="productId" jdbcType="BIGINT" />
<result column="product_name" property="productName" jdbcType="VARCHAR" />
<result column="status" property="status" jdbcType="VARCHAR" />
<result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
<result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
</resultMap>
<sql id="Base_Column_List">
product_id,product_name,status,create_time,update_time
</sql>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String">
select <include refid="BaseResultMap" />
from product_info
where activity_id = #{activityId,jdbcType=BIGINT}
</sql>
<insert id="insert" parameterType="cn.xxx.xxx.dao.model.StoreModel">
insert into product_info (product_id,product_name,status,create_time,update_time)
select #{productId},#{productName},#{status},#{createTime},#{updateTime}
from dual
where not exists(select activity_id from product_info where activity_id = #{activityId}
</insert>
<update id="updateByPrimaryKey" parameterType="cn.xxx.xxx.dao.model.StoreActivityModel">
update product_info
<set>
<if test="productId != null">
product_id = #{productId,jdbcType=BIGINT}
</if>
<if test="productName != null">
product_name = #{productName,jdbcType=VARCHAR}
</if>
<if test="status != null">
status = #{status,jdbcType=VARCHAR}
</if>
<if test="createTime != null">
create_time = #{createTime,jdbcType=TIMESTAMP}
</if>
<if test="updateTime != null">
update_time = #{updateTime,jdbcType=TIMESTAMP}
</if>
</set>
where activity_id = #{activityId,jdbcType=BIGINT}
</update>
<delete id="deleteByPrimaryKey" parameterType="String">
delete from product_info where activity_id = #{activityId}
</delete>
</mapper>
来源:CSDN
作者:春秋战国程序猿
链接:https://blog.csdn.net/reggergdsg/article/details/103530766