diff --git a/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyMapper.java b/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyMapper.java new file mode 100644 index 000000000..a5885e664 --- /dev/null +++ b/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyMapper.java @@ -0,0 +1,31 @@ +package tk.mybatis.mapper.additional.update.batch; + +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.UpdateProvider; +import tk.mybatis.mapper.annotation.RegisterMapper; +import tk.mybatis.mapper.weekend.Fn; + +import java.util.List; + +@RegisterMapper +public interface BatchUpdatePropertyByPrimaryKeyMapper { + + /** + * 多条数据更新同一字段为相同值 + * @param fn 字段名 + * @param value 更新的字段值 + * @param primaryKeys 数据主键集合 + * @return + */ + @UpdateProvider(type = BatchUpdatePropertyByPrimaryKeyProvider.class, method = "dynamicSQL") + int batchUpdateFieldByIdList(@Param("fn") Fn fn, @Param("value") Object value, @Param("idList") List primaryKeys); + + /** + * 多条数据更新多个字段为相同值 + * @param fieldValues 更新字段及更新值 + * @param primaryKeys 数据主键集合 + * @return + */ + @UpdateProvider(type = BatchUpdatePropertyByPrimaryKeyProvider.class, method = "dynamicSQL") + int batchUpdateFieldListByIdList(@Param("fieldList") List> fieldValues, @Param("idList") List primaryKeys); +} diff --git a/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyProvider.java b/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyProvider.java new file mode 100644 index 000000000..67481ca4d --- /dev/null +++ b/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyProvider.java @@ -0,0 +1,118 @@ +package tk.mybatis.mapper.additional.update.batch; + +import org.apache.ibatis.mapping.MappedStatement; +import tk.mybatis.mapper.MapperException; +import tk.mybatis.mapper.entity.EntityColumn; +import tk.mybatis.mapper.entity.EntityTable; +import tk.mybatis.mapper.mapperhelper.EntityHelper; +import tk.mybatis.mapper.mapperhelper.MapperHelper; +import tk.mybatis.mapper.mapperhelper.MapperTemplate; +import tk.mybatis.mapper.mapperhelper.SqlHelper; + +import java.util.List; +import java.util.Set; + +public class BatchUpdatePropertyByPrimaryKeyProvider extends MapperTemplate { + + public BatchUpdatePropertyByPrimaryKeyProvider(Class mapperClass, MapperHelper mapperHelper) { + super(mapperClass, mapperHelper); + } + + public String batchUpdateFieldByIdList(MappedStatement ms) { + Class entityClass = getEntityClass(ms); + StringBuilder sql = new StringBuilder(); + sql.append(SqlHelper.updateTable(entityClass, tableName(entityClass))); + appendSet(sql, entityClass); + appendWhereIdList(sql, entityClass, true); + return sql.toString(); + } + + public String batchUpdateFieldListByIdList(MappedStatement ms) { + Class entityClass = getEntityClass(ms); + StringBuilder sql = new StringBuilder(); + sql.append(SqlHelper.updateTable(entityClass, tableName(entityClass))); + appendFileListSet(sql, entityClass); + appendWhereIdList(sql, entityClass, true); + return sql.toString(); + } + + private void appendSet(StringBuilder sql, Class entityClass) { + sql.append(""); + //通过实体类名获取运行时属性对应的字段 + String ognl = new StringBuilder("${@") + .append(getProviderName()) + .append("@getColumnByProperty(@java.lang.Class@forName(\"") + .append(entityClass.getName()) + .append("\"), @tk.mybatis.mapper.weekend.reflection.Reflections@fnToFieldName(fn))}").toString(); + sql.append(ognl + " = #{value}\n"); + sql.append(""); + } + + private void appendWhereIdList(StringBuilder sql, Class entityClass, boolean useVersion) { + Set columnList = EntityHelper.getPKColumns(entityClass); + if (columnList.size() == 1) { + EntityColumn column = columnList.iterator().next(); + sql.append(""); + sql.append(""); + sql.append(""); + sql.append("#{id}"); + sql.append(""); + if (useVersion) { + sql.append(SqlHelper.whereVersion(entityClass)); + } + sql.append(""); + } else { + throw new MapperException("继承 BatchUpdatePropertyByPrimaryKeyMapper 方法的实体类[" + entityClass.getCanonicalName() + "]中必须只有一个带有 @Id 注解的字段"); + } + } + + private void appendFileListSet(StringBuilder sql, Class entityClass) { + sql.append(""); + sql.append(""); + //通过实体类名获取运行时属性对应的字段 + String ognl = "${@" + + getProviderName() + + "@getColumnByProperty(@java.lang.Class@forName(\"" + + entityClass.getName() + + "\"), @tk.mybatis.mapper.weekend.reflection.Reflections@fnToFieldName(field.fn))}"; + sql.append(ognl + " = #{field.value}\n"); + sql.append(""); + sql.append(""); + + } + + private String getProviderName() { + return BatchUpdatePropertyByPrimaryKeyProvider.class.getName(); + } + + /** + * 根据实体Class和属性名获取对应的表字段名 + * + * @param entityClass 实体Class对象 + * @param property 属性名 + * @return + */ + public static String getColumnByProperty(Class entityClass, String property) { + EntityTable entityTable = EntityHelper.getEntityTable(entityClass); + EntityColumn entityColumn = entityTable.getPropertyMap().get(property); + return entityColumn.getColumn(); + } + + /** + * 保证 idList 不能为空 + * + * @param list + * @param errorMsg + */ + public static void notEmpty(List list, String errorMsg){ + if(list == null || list.size() == 0){ + throw new MapperException(errorMsg); + } + } + + +} diff --git a/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/FieldValue.java b/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/FieldValue.java new file mode 100644 index 000000000..d89d25ffb --- /dev/null +++ b/extra/src/main/java/tk/mybatis/mapper/additional/update/batch/FieldValue.java @@ -0,0 +1,42 @@ +package tk.mybatis.mapper.additional.update.batch; + +import tk.mybatis.mapper.weekend.Fn; + +public class FieldValue { + + /** + * 字段名 + * 形式必须是 类::方法 + * e.g. Country::getCountryname + */ + private Fn fn; + + /** + * 更新的字段值 + */ + private Object value; + + public FieldValue(Fn fn, Object value) { + this.fn = fn; + this.value = value; + } + + public FieldValue() { + } + + public Fn getFn() { + return fn; + } + + public void setFn(Fn fn) { + this.fn = fn; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } +} diff --git a/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyTest.java b/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyTest.java new file mode 100644 index 000000000..547082c99 --- /dev/null +++ b/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/BatchUpdatePropertyByPrimaryKeyTest.java @@ -0,0 +1,104 @@ +package tk.mybatis.mapper.additional.update.batch; + +import org.apache.ibatis.session.SqlSession; +import org.junit.Assert; +import org.junit.Test; +import tk.mybatis.mapper.additional.BaseTest; +import tk.mybatis.mapper.additional.Country; + +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author goldhuang + * @Description: 验证批量更新 + * @date 2020-04-02 + */ +public class BatchUpdatePropertyByPrimaryKeyTest extends BaseTest { + + /** + * 获取 mybatis 配置 + * + * @return + */ + protected Reader getConfigFileAsReader() throws IOException { + URL url = getClass().getResource("mybatis-config.xml"); + return toReader(url); + } + + ; + + @Test + public void testBatchUpdateFieldByIdList() { + SqlSession sqlSession = getSqlSession(); + try { + tk.mybatis.mapper.additional.update.batch.CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + + //(1, 'Angola', 'AO', 1) + Country old1 = mapper.selectByPrimaryKey(1L); + //(2, 'Afghanistan', 'AF', 1) + Country old2 = mapper.selectByPrimaryKey(2L); + + int updateCount = mapper.batchUpdateFieldByIdList(Country::getCountryname, "Gold", Arrays.asList(old1.getId(), old2.getId())); + Assert.assertEquals(2, updateCount); + + old1 = mapper.selectByPrimaryKey(1L); + old2 = mapper.selectByPrimaryKey(2L); + + Assert.assertEquals(1L, old1.getId().longValue()); + Assert.assertEquals(2L, old2.getId().longValue()); + Assert.assertEquals("Gold", old1.getCountryname()); + Assert.assertEquals("Gold", old2.getCountryname()); + } finally { + sqlSession.close(); + } + } + + @Test(expected = Exception.class) + public void testBatchUpdateFieldByEmptyIdList() { + SqlSession sqlSession = getSqlSession(); + try { + tk.mybatis.mapper.additional.update.batch.CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.batchUpdateFieldByIdList(Country::getCountryname, "Gold", new ArrayList<>()); + } finally { + sqlSession.close(); + } + } + + @Test + public void batchUpdateFieldListByIdList() { + SqlSession sqlSession = getSqlSession(); + try { + tk.mybatis.mapper.additional.update.batch.CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + + //(1, 'Angola', 'AO', 1) + Country old1 = mapper.selectByPrimaryKey(1L); + //(2, 'Afghanistan', 'AF', 1) + Country old2 = mapper.selectByPrimaryKey(2L); + + List> fieldValues = new ArrayList<>(); + fieldValues.add(new FieldValue<>(Country::getCountrycode, "GD")); + fieldValues.add(new FieldValue<>(Country::getCountryname, "Gold")); + + int updateCount = mapper.batchUpdateFieldListByIdList(fieldValues, Arrays.asList(old1.getId(), old2.getId())); + Assert.assertEquals(2, updateCount); + + old1 = mapper.selectByPrimaryKey(1L); + old2 = mapper.selectByPrimaryKey(2L); + + Assert.assertEquals(1L, old1.getId().longValue()); + Assert.assertEquals(2L, old2.getId().longValue()); + Assert.assertEquals("Gold", old1.getCountryname()); + Assert.assertEquals("Gold", old2.getCountryname()); + Assert.assertEquals("GD", old1.getCountrycode()); + Assert.assertEquals("GD", old2.getCountrycode()); + } finally { + sqlSession.close(); + } + } + +} diff --git a/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/CountryMapper.java b/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/CountryMapper.java new file mode 100644 index 000000000..a68680546 --- /dev/null +++ b/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/CountryMapper.java @@ -0,0 +1,7 @@ +package tk.mybatis.mapper.additional.update.batch; + +import tk.mybatis.mapper.additional.Country; +import tk.mybatis.mapper.common.BaseMapper; + +public interface CountryMapper extends BaseMapper, BatchUpdatePropertyByPrimaryKeyMapper { +} diff --git a/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/mybatis-config.xml b/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/mybatis-config.xml new file mode 100644 index 000000000..a7367185f --- /dev/null +++ b/extra/src/test/java/tk/mybatis/mapper/additional/update/batch/mybatis-config.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +