
app.myoss.cloud.mybatis.mapper.template.insert.impl.InsertMapperTemplate Maven / Gradle / Ivy
/*
* Copyright 2018-2018 https://github.com/myoss
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package app.myoss.cloud.mybatis.mapper.template.insert.impl;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.apache.ibatis.builder.xml.XMLStatementBuilder;
import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
import org.apache.ibatis.executor.keygen.KeyGenerator;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.mapping.StatementType;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.LanguageDriver;
import org.apache.ibatis.session.Configuration;
import app.myoss.cloud.mybatis.executor.keygen.SequenceKeyGenerator;
import app.myoss.cloud.mybatis.mapper.template.AbstractMapperTemplate;
import app.myoss.cloud.mybatis.mapper.template.insert.InsertAllColumnMapper;
import app.myoss.cloud.mybatis.mapper.template.insert.InsertBatchMapper;
import app.myoss.cloud.mybatis.mapper.template.insert.InsertMapper;
import app.myoss.cloud.mybatis.table.TableColumnInfo;
import app.myoss.cloud.mybatis.table.TableInfo;
import app.myoss.cloud.mybatis.table.TableMetaObject;
import app.myoss.cloud.mybatis.table.TableSequence;
import app.myoss.cloud.mybatis.table.annotation.FillRule;
import app.myoss.cloud.mybatis.table.annotation.GenerationType;
import app.myoss.cloud.mybatis.table.annotation.SequenceGenerator.Order;
/**
* 生成通用 insert MappedStatement 模版类
*
* @author Jerry.Chen
* @since 2018年4月29日 下午4:46:05
*/
public class InsertMapperTemplate extends AbstractMapperTemplate {
/**
* 生成 selectKey 序列,并增加到 {@link Configuration} 全局配置中
*
* @param id mappedStatement id
* @param sequence 数据库表"序列生成器"属性配置
* @param parameterTypeClass "实体类"的 class
* @param configuration Mybatis Global Configuration
* @param langDriver Mybatis langDriver
* @param parentId mappedStatement parent id
* @return 生成 selectKey 序列对象
* @see GenerationType#SELECT_KEY
* @see XMLStatementBuilder#parseSelectKeyNodes
*/
private SelectKeyGenerator addSelectKeyGenerator(String id, TableSequence sequence, Class> parameterTypeClass,
Configuration configuration, LanguageDriver langDriver,
String parentId) {
Class> resultTypeClass = sequence.getResultType()[0];
StatementType statementType = sequence.getStatementType();
String keyProperty = StringUtils.join(sequence.getKeyProperties(), ",");
String keyColumn = StringUtils.join(sequence.getKeyColumns(), ",");
boolean executeBefore = sequence.getOrder().equals(Order.BEFORE);
// 生成 selectKey sql
String selectSql = sequence.getSql();
StringBuilder sqlXml = new StringBuilder(150 + selectSql.length());
sqlXml.append("").append(selectSql).append(" ");
XPathParser xPathParser = new XPathParser(sqlXml.toString());
XNode nodeToHandle = xPathParser.evalNode("selectKey");
SqlSource sqlSource = langDriver.createSqlSource(configuration, nodeToHandle, parameterTypeClass);
SqlCommandType sqlCommandType = SqlCommandType.SELECT;
KeyGenerator keyGenerator = new NoKeyGenerator();
MapperBuilderAssistant builderAssistant = new MapperBuilderAssistant(configuration, parentId);
builderAssistant.setCurrentNamespace(StringUtils.substringBeforeLast(parentId, "."));
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, null, null, null,
parameterTypeClass, null, resultTypeClass, null, false, false, false, keyGenerator, keyProperty,
keyColumn, null, langDriver, null);
id = builderAssistant.applyCurrentNamespace(id, false);
MappedStatement keyStatement = configuration.getMappedStatement(id, false);
SelectKeyGenerator selectKeyGenerator = new SelectKeyGenerator(keyStatement, executeBefore);
configuration.addKeyGenerator(id, selectKeyGenerator);
return selectKeyGenerator;
}
/**
* 生成"序列生成器"
*
* @param tableInfo 数据库表结构信息
* @param metaObject Mybatis * @param metaObject Mybatis
* @param id mappedStatement id
* @param configuration Mybatis Global Configuration
* @return 序列生成策略
*/
private GenerationType addKeyGenerator(TableInfo tableInfo, MetaObject metaObject, String id,
Configuration configuration) {
TableSequence tableSequence = tableInfo.getTableSequence();
if (tableSequence == null) {
return null;
}
GenerationType strategy = tableSequence.getStrategy();
KeyGenerator keyGenerator;
if (strategy == GenerationType.USE_GENERATED_KEYS) {
keyGenerator = new Jdbc3KeyGenerator();
} else if (strategy == GenerationType.SELECT_KEY) {
String selectId = StringUtils.substringAfterLast(id, ".") + SelectKeyGenerator.SELECT_KEY_SUFFIX;
keyGenerator = addSelectKeyGenerator(selectId, tableSequence, tableInfo.getEntityClass(), configuration,
xmlLanguageDriver, id);
} else if (strategy == GenerationType.SEQUENCE_KEY) {
boolean executeBefore = tableSequence.getOrder().equals(Order.BEFORE);
keyGenerator = new SequenceKeyGenerator(tableInfo, id, executeBefore);
} else {
throw new UnsupportedOperationException("keyGenerator strategy " + strategy.getType() + " unsupported");
}
metaObject.setValue("keyGenerator", keyGenerator);
return strategy;
}
/**
* 创建新的记录,生成 insert 语句。
*
* 示例如下:
*
*
* INSERT INTO table_name (id, ...) VALUES (#{id}, ...)
*
*
* @param tableInfo 数据库表结构信息
* @param ms sql语句节点信息,会将生成的sql语句替换掉原有的 {@link MappedStatement#sqlSource}
* @return 生成的sql语句
* @see InsertAllColumnMapper#insertAllColumn(Object)
*/
public String insertAllColumn(TableInfo tableInfo, MappedStatement ms) {
MetaObject metaObject = SystemMetaObject.forObject(ms);
String id = ms.getId();
Configuration configuration = ms.getConfiguration();
// 生成"序列生成器"
addKeyGenerator(tableInfo, metaObject, id, configuration);
// 生成 sql 语句
StringBuilder builder = new StringBuilder(2048);
builder.append("INSERT INTO ").append(TableMetaObject.getTableName(tableInfo)).append(" (");
StringBuilder values = new StringBuilder(1024);
for (TableColumnInfo columnInfo : tableInfo.getColumns()) {
if (!columnInfo.isInsertable() || columnInfo.isAutoIncrement()) {
continue;
}
builder.append(columnInfo.getActualColumn()).append(", ");
values.append("#{").append(columnInfo.getProperty());
if (columnInfo.getJdbcType() != null) {
values.append(",jdbcType=BIGINT");
}
values.append("}, ");
}
values.deleteCharAt(values.length() - 2);
builder.deleteCharAt(builder.length() - 2).append(")\n");
builder.append(" VALUES (").append(values).append(")");
String sql = builder.toString();
// 替换 sqlSource 对象
SqlSource sqlSource = xmlLanguageDriver.createSqlSource(configuration, "",
null);
metaObject.setValue("sqlSource", sqlSource);
return sql;
}
/**
* 创建新的记录,生成 insert 语句。
*
* 示例如下:
*
*
* INSERT INTO table_name
* <trim prefix="(" suffix=")" suffixOverrides=",">
* <if test="id != null">
* id,
* </if>
* </trim>
* <trim prefix="values (" suffix=")" suffixOverrides=",">
* <if test="id != null">
* #{id},
* </if>
* </trim>
*
*
* @param tableInfo 数据库表结构信息
* @param ms sql语句节点信息,会将生成的sql语句替换掉原有的 {@link MappedStatement#sqlSource}
* @return 生成的sql语句
* @see InsertMapper#insert(Object)
*/
public String insert(TableInfo tableInfo, MappedStatement ms) {
MetaObject metaObject = SystemMetaObject.forObject(ms);
String id = ms.getId();
Configuration configuration = ms.getConfiguration();
// 生成"序列生成器"
GenerationType generationType = addKeyGenerator(tableInfo, metaObject, id, configuration);
// 生成 sql 语句
StringBuilder builder = new StringBuilder(4096);
builder.append("INSERT INTO ").append(TableMetaObject.getTableName(tableInfo)).append("\n");
builder.append("\n");
StringBuilder values = new StringBuilder(2048);
values.append("\n");
for (TableColumnInfo columnInfo : tableInfo.getColumns()) {
if (!columnInfo.isInsertable() || columnInfo.isAutoIncrement()) {
continue;
}
// 如果是主键字段(不是自动增长的主键)或者字段有自动填充的规则,不加 if 表达式判断
boolean fillInsert = (columnInfo.isPrimaryKey() && GenerationType.USE_GENERATED_KEYS != generationType)
|| columnInfo.haveFillRule(FillRule.INSERT);
if (!fillInsert) {
builder.append(" \n");
}
builder.append(" ").append(columnInfo.getActualColumn()).append(",\n");
if (!fillInsert) {
builder.append(" \n");
}
if (!fillInsert) {
values.append(" \n");
}
values.append(" #{").append(columnInfo.getProperty());
if (columnInfo.getJdbcType() != null) {
values.append(",jdbcType=BIGINT");
}
values.append("},\n");
if (!fillInsert) {
values.append(" \n");
}
}
builder.append(" \n").append(values).append(" \n");
String sql = builder.toString();
// 替换 sqlSource 对象
SqlSource sqlSource = xmlLanguageDriver.createSqlSource(configuration, "",
null);
metaObject.setValue("sqlSource", sqlSource);
return sql;
}
/**
* 批量创建新的记录,生成 insert 语句。
*
* 示例如下:
*
*
* INSERT INTO table_name (id, ...) VALUES
* <foreach collection="list" item="item" separator=",">
* (#{id}, ...)
* </foreach>
*
*
* @param tableInfo 数据库表结构信息
* @param ms sql语句节点信息,会将生成的sql语句替换掉原有的 {@link MappedStatement#sqlSource}
* @return 生成的sql语句
* @see InsertBatchMapper#insertBatch(List)
*/
public String insertBatch(TableInfo tableInfo, MappedStatement ms) {
MetaObject metaObject = SystemMetaObject.forObject(ms);
String id = ms.getId();
Configuration configuration = ms.getConfiguration();
// 生成"序列生成器"
addKeyGenerator(tableInfo, metaObject, id, configuration);
// 生成 sql 语句
StringBuilder builder = new StringBuilder(2048);
builder.append("INSERT INTO ").append(TableMetaObject.getTableName(tableInfo)).append(" (");
StringBuilder values = new StringBuilder(1024);
values.append("");
values.append("\n(");
for (TableColumnInfo columnInfo : tableInfo.getColumns()) {
if (!columnInfo.isInsertable() || columnInfo.isAutoIncrement()) {
continue;
}
builder.append(columnInfo.getActualColumn()).append(", ");
values.append("#{item.").append(columnInfo.getProperty());
if (columnInfo.getJdbcType() != null) {
values.append(",jdbcType=BIGINT");
}
values.append("}, ");
}
values.deleteCharAt(values.length() - 2).append(")\n ");
builder.deleteCharAt(builder.length() - 2).append(")\n");
builder.append(" values \n").append(values);
String sql = builder.toString();
// 替换 sqlSource 对象
SqlSource sqlSource = xmlLanguageDriver.createSqlSource(configuration, "",
null);
metaObject.setValue("sqlSource", sqlSource);
return sql;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy