mybatis-plusカスタムsqlテンプレート、カスタムバッチ更新または挿入
文書ディレクトリバックグラウンド 解決策 カスタムステップ 3.1はmapperに類似する定義である.xmlテンプレート 3.2 springboot起動時にカスタムsql を動的にロード 3.3独自のbaseMapperをカスタマイズし、公式のbaseMapper に置き換えます. 3.4独自のサービスをカスタマイズし、公式のサービスImpl に置き換えます.
4 を使用
背景
mybatis-plusはmybatisを強化しましたが、使用時には以下の問題も発生します.
1、主キーをカスタマイズする必要がある
2、連合主キーに従って一括更新できない、例えば以下のsql
3、mybatis-plusが持っているsaveOrUpdateBatchを使うと、性能もあまりよくない
解決策
カスタムテンプレートはmybatis-plus 3.0以上で、公式にはソリューションsql注入器が提供されています.
オフィシャルリファレンス:https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-deluxe
カスタムステップ
3.1類似mapperを定義する.xmlテンプレート
次のコードは、tableinfoに基づいてxml版のsqlを動的に生成することを行います.生成後は手動で書く必要はありません
insert into
3.2 springboot起動時にカスタムsqlを動的にロードする
3.3自分のbaseMapperをカスタマイズし、公式のbaseMapperを置き換える
3.4自分のサービスをカスタマイズし、公式のサービスImplに置き換える
4使用
ビジネスのサービスは、カスタムのBridgeBaseServices 1を継承します.公式のサービスインプラントを継承するのと同じように酸っぱいです
背景
mybatis-plusはmybatisを強化しましたが、使用時には以下の問題も発生します.
1、主キーをカスタマイズする必要がある
2、連合主キーに従って一括更新できない、例えば以下のsql
insert into `test` (`id`,`plan_id``) VALUES (1,2),(3,4)
ON DUPLICATE KEY UPDATE
id=values(id),plan_id=values(plan_id)
3、mybatis-plusが持っているsaveOrUpdateBatchを使うと、性能もあまりよくない
解決策
カスタムテンプレートはmybatis-plus 3.0以上で、公式にはソリューションsql注入器が提供されています.
オフィシャルリファレンス:https://gitee.com/baomidou/mybatis-plus-samples/tree/master/mybatis-plus-sample-deluxe
カスタムステップ
3.1類似mapperを定義する.xmlテンプレート
次のコードは、tableinfoに基づいてxml版のsqlを動的に生成することを行います.生成後は手動で書く必要はありません
insert into
test
( id
,`plan_id``) VALUES (1,2),(3,4) ON DUPLICATE KEY UPDATE id=values(id),plan_id=values(plan_id) import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.springframework.util.StringUtils;
public class MysqlInsertOrUpdateBath extends AbstractMethod {
@Override
public MappedStatement injectMappedStatement(Class> mapperClass, Class> modelClass, TableInfo tableInfo) {
final String sql = "insert into %s %s values %s ON DUPLICATE KEY UPDATE %s ";
final String tableName = tableInfo.getTableName();
final String filedSql = prepareFieldSql(tableInfo);
final String modelValuesSql = prepareModelValuesSql(tableInfo);
final String duplicateKeySql =prepareDuplicateKeySql(tableInfo);
final String sqlResult = String.format(sql, tableName, filedSql, modelValuesSql,duplicateKeySql);
SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
return this.addInsertMappedStatement(mapperClass, modelClass, "mysqlInsertOrUpdateBath", sqlSource, new NoKeyGenerator(), null, null);
}
/**
* ON DUPLICATE KEY UPDATE sql
* @param tableInfo
* @return
*/
private String prepareDuplicateKeySql(TableInfo tableInfo) {
final StringBuilder duplicateKeySql = new StringBuilder();
if(!StringUtils.isEmpty(tableInfo.getKeyColumn())) {
duplicateKeySql.append(tableInfo.getKeyColumn()).append("=(").append(tableInfo.getKeyColumn()).append("),");
}
tableInfo.getFieldList().forEach(x -> {
duplicateKeySql.append(x.getColumn())
.append("=(")
.append(x.getColumn())
.append("),");
});
duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());
return duplicateKeySql.toString();
}
/**
*
* @param tableInfo
* @return
*/
private String prepareDuplicateKeySql(TableInfo tableInfo) {
final StringBuilder duplicateKeySql = new StringBuilder();
if(!StringUtils.isEmpty(tableInfo.getKeyColumn())) {
duplicateKeySql.append(tableInfo.getKeyColumn()).append("=(").append(tableInfo.getKeyColumn()).append("),");
}
tableInfo.getFieldList().forEach(x -> {
duplicateKeySql.append(x.getColumn())
.append("=VALUES(")
.append(x.getColumn())
.append("),");
});
duplicateKeySql.delete(duplicateKeySql.length() - 1, duplicateKeySql.length());
return duplicateKeySql.toString();
}
private String prepareModelValuesSql(TableInfo tableInfo){
final StringBuilder valueSql = new StringBuilder();
valueSql.append("");
if(!StringUtils.isEmpty(tableInfo.getKeyProperty())) {
valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
}
tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
valueSql.delete(valueSql.length() - 1, valueSql.length());
valueSql.append(" ");
return valueSql.toString();
}
}
3.2 springboot起動時にカスタムsqlを動的にロードする
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class MysqlInjector extends DefaultSqlInjector {
@Override
public List getMethodList() {
List methodList = super.getMethodList();
methodList.add(new MysqlInsertOrUpdateBath());
return methodList;
}
}
3.3自分のbaseMapperをカスタマイズし、公式のbaseMapperを置き換える
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.List;
/**
* mapper
* @param
*/
public interface BridgeBaseMapper extends BaseMapper {
int mysqlInsertOrUpdateBath(List list);
}
3.4自分のサービスをカスタマイズし、公式のサービスImplに置き換える
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
public class BridgeBaseService1, T> extends ServiceImpl {
// mapper
@Transactional(rollbackFor = Exception.class)
@Override
public boolean saveOrUpdateBatch(Collection entityList, int batchSize){
Assert.notEmpty(entityList, "error: entityList must not be empty");
List objs = Lists.newArrayList(entityList);
List> partitions = Lists.partition(objs, batchSize);
for(List list:partitions) {
this.baseMapper.mysqlInsertOrUpdateBath(list);
}
return true;
}
}
4使用
ビジネスのサービスは、カスタムのBridgeBaseServices 1を継承します.公式のサービスインプラントを継承するのと同じように酸っぱいです