阿超
>
h2下update set字段重复处理拦截器
慷慨是友谊的精华——王尔德
今天发现Mybatis-Plus
在h2
下,同时使用UpdateWrapper
和entity
会出现
update 表名 set 字段1=xxx,字段1=xxx
这样的sql
,在mysql
下是正确的语法,h2
会抛出异常
所以写了个mybatis
拦截器,放在了streampark
里:
pr
地址:https://github.com/streamxhub/streampark/pull/1493
源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 package com.streamxhub.streamx.console.base.mybatis.interceptor;import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;import com.baomidou.mybatisplus.core.metadata.TableInfo;import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;import com.baomidou.mybatisplus.core.toolkit.Constants;import com.baomidou.mybatisplus.core.toolkit.PluginUtils;import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;import net.sf.jsqlparser.schema.Column;import net.sf.jsqlparser.statement.update.Update;import net.sf.jsqlparser.statement.update.UpdateSet;import org.apache.ibatis.binding.MapperMethod;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.ParameterMapping;import org.apache.ibatis.mapping.SqlCommandType;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Plugin;import org.apache.ibatis.plugin.Signature;import java.sql.Connection;import java.util.Iterator;import java.util.Map;import java.util.Objects;import java.util.Properties;import java.util.stream.Collectors;@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class H2SQLPrepareInterceptor extends JsqlParserSupport implements Interceptor { @Override public Object intercept (final Invocation invocation) throws Throwable { StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); BoundSql boundSql = statementHandler.getBoundSql(); PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(statementHandler); MappedStatement ms = mpSh.mappedStatement(); SqlCommandType sct = ms.getSqlCommandType(); if (sct == SqlCommandType.UPDATE) { PluginUtils.MPBoundSql mpBs = PluginUtils.mpBoundSql(boundSql); mpBs.sql(parserMulti(mpBs.sql(), boundSql)); } return invocation.proceed(); } @Override public Object plugin (final Object target) { return Plugin.wrap(target, this ); } @Override public void setProperties (final Properties properties) { } @Override protected void processUpdate (Update update, int index, String sql, Object obj) { if (obj instanceof BoundSql) { BoundSql boundSql = (BoundSql) obj; Object parameterObject = boundSql.getParameterObject(); if (parameterObject instanceof MapperMethod.ParamMap<?>) { MapperMethod.ParamMap<?> paramMap = (MapperMethod.ParamMap<?>) parameterObject; Object entity = paramMap.get(Constants.ENTITY); if (Objects.nonNull(entity) && paramMap.containsKey(Constants.WRAPPER)) { TableInfo tableInfo = TableInfoHelper.getTableInfo(entity.getClass()); Map<String, String> columnPropertyMap = tableInfo.getFieldList().stream().collect(Collectors.toMap(TableFieldInfo::getColumn, TableFieldInfo::getProperty)); Map<String, Long> columnNameCountMap = update.getUpdateSets().stream().flatMap(set -> set.getColumns().stream()) .collect(Collectors.groupingBy(Column::getColumnName, Collectors.counting())); columnNameCountMap.forEach((column, times) -> { for (long i = 1L ; i < times; ) { Iterator<UpdateSet> updateSetIterator = update.getUpdateSets().iterator(); while (((Iterator<?>) updateSetIterator).hasNext()) { UpdateSet updateSet = updateSetIterator.next(); if (updateSet.getColumns().stream().anyMatch(c -> c.getColumnName().equals(column))) { updateSetIterator.remove(); break ; } } Iterator<ParameterMapping> parameterMappingIterator = boundSql.getParameterMappings().iterator(); while (parameterMappingIterator.hasNext()) { ParameterMapping parameterMapping = parameterMappingIterator.next(); String property = columnPropertyMap.get(column); if (Objects.nonNull(property) && parameterMapping.getProperty().equals(Constants.ENTITY_DOT + property)) { parameterMappingIterator.remove(); break ; } } columnNameCountMap.put(column, times--); } }); } } } } }
解决思路本来是打算set
实体类里的属性为null
,但是没生效,因为已经生成sql
和占位符了
最后:
效果还是很不错的,原先不兼容的update(entity,updateWrapper)
设置重复属性,兼容了h2