Common Mapper Advanced Example: Why hasn't it been updated for a long time?

A few days ago I noticed someone was on GitHub three months ago Is this project no longer maintained? And then I looked at it Generic Mapper Content and time of last update:

Although PR was merged, there was no release. The release information for the last release is as follows:

That is, no new version has been released since January 28, 2019.In the early part of this project (within 1-2 years), due to frequent updates, the title of Version Emperor has been won again. Why have there been few changes recently?Are you really not maintaining it?

Of course not. In fact, I don't think there is any need to update since the submission below and the corresponding version 4.1.2.

Starting from the stability of core functions, a large number of common methods have been added, and now there are many PR without merging, which are basically the implementation of common methods.In the mid-term of the project, I personally responded to the ideas of most developers by adding as many generic methods as possible.Since I've been using generic Mapper myself, I've found some serious problems that affect my view of how to add generic methods.

I find that due to the large number of common Mapper methods, especially skilled users of Example, I overrely on them.There are still many things that plainly simple SQL can do, and several common methods are called back and forth to implement them.When using select to obtain a large amount of data, it is clear that only a few fields are needed, and it is not used directly without a selection.When the generic Mapper does not provide some methods, think of someone who can provide the methods you need.Universal Mapper is designed to allow developers to be lazy and spend more time on important things, but some people are also lazy where they shouldn't be.

Small projects with no performance requirements can be used without any consideration, but don't get used to it and know when they won't work.

This year after we had a baby, time was really low. Issue and pr barely had the energy to deal with it. Thanks to all developers who actively helped others in issue, and thanks to all pr submitters.Core implementations of the new version of Universal Mapper 5 have been around for more than a year (at Add LanguageDriver to ProviderSqlSource #1391 After PR), there is still not enough effort to improve the implementation of the underlying method, which is based on the latest versions of jdk8 and mybatis 3.5.x. This version will be easier to use, easier to expand, and will only provide a small number of generic methods as examples, which must be implemented by 2020 and can no longer be delayed.

The trend in the future is that generic Mapper only needs to provide a few necessary generic methods, and can extend the methods by itself when extracting the generic business logic from the business logic. This is a better generic method. Starting from the following, this paper introduces the implementation of a generic business logic in a real case.

Function of dragging up and down sorting of sibling data

Business scenarios are simple, where data that meets certain query criteria is sorted by a list of serial numbers, and there are functional requirements to move up and down or drag and drop sorting on UI operations, since nearly 10 tables are designed to simplify implementation by encapsulating ready-made methods for developers to use directly.Here's a simple design analysis.

Business Interface Design

/**
 * Move Node Order
 *
 * @param movingId Moved id
 * @param targetId Target id
 * @param isBefore Above target node true or below false
 * @return
 */
int move(Long movingId, Long targetId, boolean isBefore);

The overall design is for drag-and-drop sorting. Moving up and down is only two special cases of drag-and-drop sorting. The location of the drag-and-drop may be above or below the target node, and the interface is simply distinguished by true/false.

Drag Sort Operation Analysis


The four cases shown in the figure are analyzed and divided into the following four logic types:

  • Move down:
    • Figure 1: Move to the front:
      • (source, target)-1
      • source=target-1
      • target unchanged
    • Figure 2: Move back:
      • (source,target]-1
      • source=target
  • Move up:
    • Figure 3: Move to the front:
      • [target,source)+1
      • source=target
    • Figure 4: Move back:
      (target,source)+1
      source=target+1
      • target unchanged

Note: (is an open interval, does not contain the corresponding value, [is a closed interval, contains the corresponding value.

Dragging database operation design

To be as efficient as possible, methods like selectByPrimaryKey are not used here.For the above analysis, the sorting is divided into the following database operations.

  1. Get the sequence number for the id: Since only these two values are required, a generic method is provided to get only these two values.
  2. Update the sequence number of the target and source intervals, possibly + 1 or - 1 depending on the direction.
  3. Update the sequence number of the drag node, as only Figures 2 and 3 above need to be updated

After the above three operations, the sequence number is changed, that is, database operations need to be performed up to three times, and the sequence number is guaranteed to be consistent.

Design and Implementation of Universal Mapper Interface

Since you need to know the Sequence Number field in Model, first provide a comment to specify the Sequence Number field:

/**
 * Sequence Number
 */
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Seq {
}

Then there is the generic Mapper interface:

/**
 * Drag Sort Interface
 */
@RegisterMapper
public interface MoveMapper<T> {
    /**
     * 1. Gets the sequence number corresponding to a given ids
     *
     * @param ids
     * @return
     */
    @SelectProvider(type = MoveProvider.class, method = "dynamicSQL")
    List<SeqModel> getSeqs(@Param("ids") String ids);

    /**
     * 2. Move the node to adjust the order of the middle part, and adjacent nodes to adjust do not need to call the current method
     *
     * @param movingSeq  Move Node Sequence Number
     * @param targetSeq  Target Node Sequence Number
     * @param direction  position
     * @param conditions Additional Conditions
     * @return
     */
    @UpdateProvider(type = MoveProvider.class, method = "dynamicSQL")
    int move(@Param("movingSeq") Long movingSeq, @Param("targetSeq") Long targetSeq,
             @Param("direction") MoveDirection direction, @Param("conditions") Map<String, Object> conditions);

    /**
     * 3. Update Sequence Number Based on Primary Key
     *
     * @param id
     * @param seq
     * @return
     */
    @UpdateProvider(type = MoveProvider.class, method = "dynamicSQL")
    int updateSeqById(@Param("id") Long id, @Param("seq") Long seq);

}

SeqModel contains the id and sequence number fields:

public class SeqModel implements Serializable {
    private static final long serialVersionUID = 1L;
    private Long id;
    private Long seq;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Long getSeq() {
        return seq;
    }

    public void setSeq(Long seq) {
        this.seq = seq;
    }
}

There is also an enumeration representing the four cases shown in Figs. 1 to 4:

/**
 * Moving direction and position
 */
public enum MoveDirection {
    /**
     * Move down to the front (up) (source,target)-1 of the target node
     */
    DownBefore,
    /**
     * After moving down to the target node (below) (source,target]-1
     */
    DownAfter,
    /**
     * Move up to target node before (up) [target,source)+1
     */
    UpBefore,
    /**
     * After moving up to the target node (bottom) (target,source)+1
     */
    UpAfter
}

The implementation of specific SQL is in MoveProvider:

public class MoveProvider extends MapperTemplate {

    public MoveProvider(Class<?> mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper);
    }

    /**
     * Get Seq Sequence Number Column Name
     *
     * @param entityClass
     * @return
     */
    private String getSeqColumnName(Class<?> entityClass) {
        //Get all columns
        Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
        List<EntityColumn> seqColumns = columnList.stream().filter(column -> column.getEntityField().isAnnotationPresent(Seq.class)).collect(Collectors.toList());
        if (seqColumns.size() == 0) {
            throw new RuntimeException(entityClass.getCanonicalName() + " There is no class with @Seq Annotation Sequence Number Field");
        } else if (seqColumns.size() > 1) {
            throw new RuntimeException(entityClass.getCanonicalName() + " There are multiple bands in the class @Seq Annotation Sequence Number Field");
        }
        return seqColumns.get(0).getColumn();
    }

    /**
     * move
     *
     * @param ms
     * @return
     */
    public String move(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        //Get Seq Sequence Number Column Name
        String seqColumnName = getSeqColumnName(entityClass);
        //The following are the separate treatments in case 4
        sql.append("update ").append(tableName(entityClass))
                .append(" <choose>")
                .append(" <when test=\"direction == @io.mybatis.demo.custom.seq.MoveDirection@DownBefore\">")
                .append(" set " + seqColumnName + " = " + seqColumnName + " - 1 where " + seqColumnName + " &gt; #{movingSeq} and " + seqColumnName + " &lt; #{targetSeq}")
                .append(" </when>")
                .append(" <when test=\"direction == @io.mybatis.demo.custom.seq.MoveDirection@DownAfter\">")
                .append(" set " + seqColumnName + " = " + seqColumnName + " - 1 where " + seqColumnName + " &gt; #{movingSeq} and " + seqColumnName + " &lt;= #{targetSeq}")
                .append(" </when>")
                .append(" <when test=\"direction == @io.mybatis.demo.custom.seq.MoveDirection@UpBefore\">")
                .append(" set " + seqColumnName + " = " + seqColumnName + " + 1 where " + seqColumnName + " &gt;= #{targetSeq} and " + seqColumnName + " &lt; #{movingSeq}")
                .append(" </when>")
                .append(" <when test=\"direction == @io.mybatis.demo.custom.seq.MoveDirection@UpAfter\">")
                .append(" set " + seqColumnName + " = " + seqColumnName + " + 1 where " + seqColumnName + " &gt; #{targetSeq} and " + seqColumnName + " &lt; #{movingSeq}")
                .append(" </when>")
                .append(" </choose>");
        //Append other where conditions
        sql.append(" <foreach collection=\"conditions\" item=\"val\" index=\"colName\">");
        sql.append(" and ${colName} = #{val}");
        sql.append(" </foreach>");
        return sql.toString();
    }

    /**
     * Gets the serial number corresponding to the specified ids
     *
     * @param ms
     * @return
     */
    public String getSeqs(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        //Get Seq Sequence Number Column Name
        String seqColumnName = getSeqColumnName(entityClass);
        sql.append("select id, ").append(seqColumnName).append(" as seq from ").append(tableName(entityClass)).append(" where id in ( ${ids})");
        return sql.toString();
    }

    /**
     * Update Sequence Number Based on id
     *
     * @param ms
     * @return
     */
    public String updateSeqById(MappedStatement ms) {
        Class<?> entityClass = this.getEntityClass(ms);
        StringBuilder sql = new StringBuilder();
        //Get Seq Sequence Number Column Name
        String seqColumnName = getSeqColumnName(entityClass);
        sql.append("update ").append(tableName(entityClass)).append(" set ").append(seqColumnName).append(" = #{seq} where id = #{id}");
        return sql.toString();
    }

}

In the above implementation, as simple as possible according to the current overall design, for example, the above directly limits the primary key field to id, and additionally uses @Param ("conditions") Map < String, Object > conditions as other query criteria.The writing of ${ids} poses a risk of SQL injection, but this is an internal call that does not expose Dao's interface through the Service.

Now that there is a common approach, you can go one step further and encapsulate business logic.

Encapsulate business logic

According to the previous illustration, business logic is encapsulated directly here to make it easier to use.

Here, the Dao implementation is passed with the simplest static class, parameters (and abstract classes can also be designed, or interfaces implemented with the default method):

public class MoveMapperUtil {

    /**
     * Move the list up and down sequentially (there is no parent-child structure relationship)
     *
     * @param mapper     dao Instance, need to inherit MoveMapper
     * @param movingId   id of the moved node
     * @param targetId   Moving target id
     * @param direction  Location to move, above or below
     * @param conditions Additional criteria, such as name=1 and age=20, are appended to where query criteria
     * @param <M>
     * @return All order does not change when result 0, result 2 when adjacent nodes swap positions, otherwise >2
     */
    public static <M extends MoveMapper> int move(M mapper, Long movingId, Long targetId, Direction direction, Map<String, Object> conditions) {
        Assert.notNull(mapper);
        Assert.notNull(movingId);
        Assert.notNull(targetId);
        Assert.notNull(direction);
        //Number of rows affected by the move operation
        int resultCount = 0;
        //Gets the sequence number corresponding to two ID s
        List<SeqModel> seqs = mapper.getSeqs(movingId + "," + targetId);
        Assert.isTrue(seqs.size() == 2);
        Map<Long, Long> idSeqMap = seqs.stream().collect(Collectors.toMap(SeqModel::getId, SeqModel::getSeq));
        Long movingSeq = idSeqMap.get(movingId);
        Long targetSeq = idSeqMap.get(targetId);
        Assert.notNull(movingSeq);
        Assert.notNull(targetSeq);
        MoveDirection position = null;
        switch (direction) {
            case AFTER:
                position = movingSeq < targetSeq  /* true - Move down*/ ? MoveDirection.DownAfter : MoveDirection.UpAfter;
                break;
            case BEFORE:
                position = movingSeq < targetSeq  /*true - Move down*/ ? MoveDirection.DownBefore : MoveDirection.UpBefore;
                break;
            default:
        }
        Assert.notNull(position);
        //Update order within interval first, 0 or 1 data may be updated when adjacent nodes, and >=1 when not adjacent
        if (Math.abs(movingSeq - targetSeq) == 1) {
            //When neighboring nodes, there are only two situations where you need to swap locations, and the following SQL will only update the target order
            if (position == MoveDirection.DownAfter
                    || position == MoveDirection.UpBefore) {
                resultCount += mapper.move(movingSeq, targetSeq, position, conditions);
            }
        } else {//The order of intermediate stages must change when they are not adjacent
            resultCount += mapper.move(movingSeq, targetSeq, position, conditions);
        }
        //Update mobile nodes based on location
        Long newSeq = movingSeq;
        switch (position) {
            case DownBefore:
                newSeq = targetSeq - 1;
                break;
            case DownAfter:
            case UpBefore:
                newSeq = targetSeq;
                break;
            case UpAfter:
                newSeq = targetSeq + 1;
                break;
            default:
        }
        //Update when the order of moving nodes changes (exceptions, move down to the top of the next node, where location does not change)
        if (!newSeq.equals(movingSeq)) {
            resultCount += mapper.updateSeqById(movingId, newSeq);
        }
        return resultCount;
    }

}

Instead of isUpdate, the following enumeration is used:

public enum Direction {
    BEFORE,
    AFTER
}

This is where the whole implementation is done. Here is a demonstration with simple data.

test

test data

drop table user if exists;

create table user (
  id bigint primary key,
  sequence int,
  name varchar(32),
  py varchar(5)
);

insert into user(id, sequence, name, py) values(1, 1,'Bi Shuru','BSR');
insert into user(id, sequence, name, py) values(2, 2,'Cai Xingxi','CXX');
insert into user(id, sequence, name, py) values(3, 3,'Zeng Sanjie','ZSJ');
insert into user(id, sequence, name, py) values(4, 4,'Chang Yuan Qin','CYQ');
insert into user(id, sequence, name, py) values(5, 5,'Chen Dongfen','CDF');
insert into user(id, sequence, name, py) values(6, 6,'Chen Ningting','CNZ');
insert into user(id, sequence, name, py) values(7, 7,'Chen Rui','CR');
insert into user(id, sequence, name, py) values(8, 8,'Chen Wuxiao','CWX');
insert into user(id, sequence, name, py) values(9, 9,'Chen Xiaoli','CXL');
insert into user(id, sequence, name, py) values(10, 10,'Chen Tao','CT');

Corresponding Entities

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    private Long id;
    //The sequence number note is used here
    @Seq
    @Order
    private Integer sequence;
    private String name;
    private String py;
    //Omit setter and getter methods

UserMapper interface

public interface UserMapper extends Mapper<User>, MoveMapper<User> {

}

Service interface and Implementation

public interface UserService {
    /**
     * Get All
     *
     * @return
     */
    List<User> getAll();

    /**
     * Move Node Order
     *
     * @param movingId Moved id
     * @param targetId Target id
     * @param isBefore Above target node true or below false
     * @return
     */
    int move(Long movingId, Long targetId, boolean isBefore);
}

//-----------------

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserMapper userMapper;

    @Override
    public List<User> getAll() {
        return userMapper.selectAll();
    }

    @Override
    public int move(Long movingId, Long targetId, boolean isBefore) {
        return MoveMapperUtil.move(userMapper, movingId, targetId, 
                                   isBefore ? Direction.BEFORE: Direction.AFTER, Collections.emptyMap());
    }

}

Test Code

logger.info("----------Current Order----------");
userService.getAll();
logger.info("Move No. 3 behind No. 7");
userService.move(3L, 7L, false);
logger.info("----------Moved order----------");
userService.getAll();
logger.info("Move No. 4 to No. 8");
userService.move(4L, 8L, true);
logger.info("----------Moved order----------");
userService.getAll();
logger.info("Move No. 9 to front of No. 2");
userService.move(9L, 2L, true);
logger.info("----------Moved order----------");
userService.getAll();
logger.info("Move No. 10 behind No. 1");
userService.move(10L, 1L, false);
logger.info("----------Moved order----------");
userService.getAll();

You can see all the data from the detailed SQL log, so there is no result of the output query above.The order after the move is clearly seen in the SQL log where the output is executed.

SQL Log

Application              : ----------Current Order----------
UserMapper.selectAll     : ==>  Preparing: SELECT id,sequence,name,py FROM user ORDER BY sequence ASC 
UserMapper.selectAll     : ==> Parameters: 
UserMapper.selectAll     : <==    Columns: ID, SEQUENCE, NAME, PY
UserMapper.selectAll     : <==        Row: 1, 1, Bi Shuru, BSR
UserMapper.selectAll     : <==        Row: 2, 2, Cai Xingxi, CXX
UserMapper.selectAll     : <==        Row: 3, 3, Zeng Sanjie, ZSJ
UserMapper.selectAll     : <==        Row: 4, 4, Chang Yuan Qin, CYQ
UserMapper.selectAll     : <==        Row: 5, 5, Chen Dongfen, CDF
UserMapper.selectAll     : <==        Row: 6, 6, Chen Ningting, CNZ
UserMapper.selectAll     : <==        Row: 7, 7, Chen Rui, CR
UserMapper.selectAll     : <==        Row: 8, 8, Chen Wuxiao, CWX
UserMapper.selectAll     : <==        Row: 9, 9, Chen Xiaoli, CXL
UserMapper.selectAll     : <==        Row: 10, 10, Chen Tao, CT
UserMapper.selectAll     : <==      Total: 10
Application              : take 3 Move number to 7 Behind number
UserMapper.getSeqs       : ==>  Preparing: select id, sequence as seq from user where id in ( 3,7) 
UserMapper.getSeqs       : ==> Parameters: 
UserMapper.getSeqs       : <==    Columns: ID, SEQ
UserMapper.getSeqs       : <==        Row: 3, 3
UserMapper.getSeqs       : <==        Row: 7, 7
UserMapper.getSeqs       : <==      Total: 2
UserMapper.move          : ==>  Preparing: update user set sequence = sequence - 1 where sequence > ? and sequence <= ? 
UserMapper.move          : ==> Parameters: 3(Long), 7(Long)
UserMapper.move          : <==    Updates: 4
UserMapper.updateSeqById : ==>  Preparing: update user set sequence = ? where id = ? 
UserMapper.updateSeqById : ==> Parameters: 7(Long), 3(Long)
UserMapper.updateSeqById : <==    Updates: 1
Application              : ----------Moved order----------
UserMapper.selectAll     : ==>  Preparing: SELECT id,sequence,name,py FROM user ORDER BY sequence ASC 
UserMapper.selectAll     : ==> Parameters: 
UserMapper.selectAll     : <==    Columns: ID, SEQUENCE, NAME, PY
UserMapper.selectAll     : <==        Row: 1, 1, Bi Shuru, BSR
UserMapper.selectAll     : <==        Row: 2, 2, Cai Xingxi, CXX
UserMapper.selectAll     : <==        Row: 4, 3, Chang Yuan Qin, CYQ
UserMapper.selectAll     : <==        Row: 5, 4, Chen Dongfen, CDF
UserMapper.selectAll     : <==        Row: 6, 5, Chen Ningting, CNZ
UserMapper.selectAll     : <==        Row: 7, 6, Chen Rui, CR
UserMapper.selectAll     : <==        Row: 3, 7, Zeng Sanjie, ZSJ
UserMapper.selectAll     : <==        Row: 8, 8, Chen Wuxiao, CWX
UserMapper.selectAll     : <==        Row: 9, 9, Chen Xiaoli, CXL
UserMapper.selectAll     : <==        Row: 10, 10, Chen Tao, CT
UserMapper.selectAll     : <==      Total: 10
Application              : take 4 Move number to 8 Before number
UserMapper.getSeqs       : ==>  Preparing: select id, sequence as seq from user where id in ( 4,8) 
UserMapper.getSeqs       : ==> Parameters: 
UserMapper.getSeqs       : <==    Columns: ID, SEQ
UserMapper.getSeqs       : <==        Row: 4, 3
UserMapper.getSeqs       : <==        Row: 8, 8
UserMapper.getSeqs       : <==      Total: 2
UserMapper.move          : ==>  Preparing: update user set sequence = sequence - 1 where sequence > ? and sequence < ? 
UserMapper.move          : ==> Parameters: 3(Long), 8(Long)
UserMapper.move          : <==    Updates: 4
UserMapper.updateSeqById : ==>  Preparing: update user set sequence = ? where id = ? 
UserMapper.updateSeqById : ==> Parameters: 7(Long), 4(Long)
UserMapper.updateSeqById : <==    Updates: 1
Application              : ----------Moved order----------
UserMapper.selectAll     : ==>  Preparing: SELECT id,sequence,name,py FROM user ORDER BY sequence ASC 
UserMapper.selectAll     : ==> Parameters: 
UserMapper.selectAll     : <==    Columns: ID, SEQUENCE, NAME, PY
UserMapper.selectAll     : <==        Row: 1, 1, Bi Shuru, BSR
UserMapper.selectAll     : <==        Row: 2, 2, Cai Xingxi, CXX
UserMapper.selectAll     : <==        Row: 5, 3, Chen Dongfen, CDF
UserMapper.selectAll     : <==        Row: 6, 4, Chen Ningting, CNZ
UserMapper.selectAll     : <==        Row: 7, 5, Chen Rui, CR
UserMapper.selectAll     : <==        Row: 3, 6, Zeng Sanjie, ZSJ
UserMapper.selectAll     : <==        Row: 4, 7, Chang Yuan Qin, CYQ
UserMapper.selectAll     : <==        Row: 8, 8, Chen Wuxiao, CWX
UserMapper.selectAll     : <==        Row: 9, 9, Chen Xiaoli, CXL
UserMapper.selectAll     : <==        Row: 10, 10, Chen Tao, CT
UserMapper.selectAll     : <==      Total: 10
Application              : take 9 Move number to 2 Before number
UserMapper.getSeqs       : ==>  Preparing: select id, sequence as seq from user where id in ( 9,2) 
UserMapper.getSeqs       : ==> Parameters: 
UserMapper.getSeqs       : <==    Columns: ID, SEQ
UserMapper.getSeqs       : <==        Row: 2, 2
UserMapper.getSeqs       : <==        Row: 9, 9
UserMapper.getSeqs       : <==      Total: 2
UserMapper.move          : ==>  Preparing: update user set sequence = sequence + 1 where sequence >= ? and sequence < ? 
UserMapper.move          : ==> Parameters: 2(Long), 9(Long)
UserMapper.move          : <==    Updates: 7
UserMapper.updateSeqById : ==>  Preparing: update user set sequence = ? where id = ? 
UserMapper.updateSeqById : ==> Parameters: 2(Long), 9(Long)
UserMapper.updateSeqById : <==    Updates: 1
Application              : ----------Moved order----------
UserMapper.selectAll     : ==>  Preparing: SELECT id,sequence,name,py FROM user ORDER BY sequence ASC 
UserMapper.selectAll     : ==> Parameters: 
UserMapper.selectAll     : <==    Columns: ID, SEQUENCE, NAME, PY
UserMapper.selectAll     : <==        Row: 1, 1, Bi Shuru, BSR
UserMapper.selectAll     : <==        Row: 9, 2, Chen Xiaoli, CXL
UserMapper.selectAll     : <==        Row: 2, 3, Cai Xingxi, CXX
UserMapper.selectAll     : <==        Row: 5, 4, Chen Dongfen, CDF
UserMapper.selectAll     : <==        Row: 6, 5, Chen Ningting, CNZ
UserMapper.selectAll     : <==        Row: 7, 6, Chen Rui, CR
UserMapper.selectAll     : <==        Row: 3, 7, Zeng Sanjie, ZSJ
UserMapper.selectAll     : <==        Row: 4, 8, Chang Yuan Qin, CYQ
UserMapper.selectAll     : <==        Row: 8, 9, Chen Wuxiao, CWX
UserMapper.selectAll     : <==        Row: 10, 10, Chen Tao, CT
UserMapper.selectAll     : <==      Total: 10
Application              : take 10 Move number to 1 Behind number
UserMapper.getSeqs       : ==>  Preparing: select id, sequence as seq from user where id in ( 10,1) 
UserMapper.getSeqs       : ==> Parameters: 
UserMapper.getSeqs       : <==    Columns: ID, SEQ
UserMapper.getSeqs       : <==        Row: 1, 1
UserMapper.getSeqs       : <==        Row: 10, 10
UserMapper.getSeqs       : <==      Total: 2
UserMapper.move          : ==>  Preparing: update user set sequence = sequence + 1 where sequence > ? and sequence < ? 
UserMapper.move          : ==> Parameters: 1(Long), 10(Long)
UserMapper.move          : <==    Updates: 8
UserMapper.updateSeqById : ==>  Preparing: update user set sequence = ? where id = ? 
UserMapper.updateSeqById : ==> Parameters: 2(Long), 10(Long)
UserMapper.updateSeqById : <==    Updates: 1
Application              : ----------Moved order----------
UserMapper.selectAll     : ==>  Preparing: SELECT id,sequence,name,py FROM user ORDER BY sequence ASC 
UserMapper.selectAll     : ==> Parameters: 
UserMapper.selectAll     : <==    Columns: ID, SEQUENCE, NAME, PY
UserMapper.selectAll     : <==        Row: 1, 1, Bi Shuru, BSR
UserMapper.selectAll     : <==        Row: 10, 2, Chen Tao, CT
UserMapper.selectAll     : <==        Row: 9, 3, Chen Xiaoli, CXL
UserMapper.selectAll     : <==        Row: 2, 4, Cai Xingxi, CXX
UserMapper.selectAll     : <==        Row: 5, 5, Chen Dongfen, CDF
UserMapper.selectAll     : <==        Row: 6, 6, Chen Ningting, CNZ
UserMapper.selectAll     : <==        Row: 7, 7, Chen Rui, CR
UserMapper.selectAll     : <==        Row: 3, 8, Zeng Sanjie, ZSJ
UserMapper.selectAll     : <==        Row: 4, 9, Chang Yuan Qin, CYQ
UserMapper.selectAll     : <==        Row: 8, 10, Chen Wuxiao, CWX
UserMapper.selectAll     : <==      Total: 10

summary

Through this article, I hope the reader can get some benefit and design a common method according to his own needs, not just for laziness to limit himself to the existing common methods.A large and comprehensive general method is not necessarily suitable for you. Choose and design a common method to meet your needs.

Universal Mapper s are designed to be easy to extend, so it's certainly not necessary to update them frequently.

This article corresponds to the complete code: https://github.com/abel533/mapper-move-spring-boot

303 original articles were published, 1682 were awarded, 6.61 million visits were received+
His message board follow

Tags: SQL Mybatis Database github

Posted on Mon, 16 Mar 2020 17:32:58 -0700 by cemzafer