“This is my 37th day of participating in the First Challenge 2022. For details: First Challenge 2022”

Customize Mapper

PorscheMappr inherits the Mapper<T> interface to obtain a set of methods that are not inherent in the Mapper<T> interface. BaseMapper<T>, ExampleMapper<T>, etc. These BaseMapper<T> inherit from the introduction of selectOne <T>. So we customize Mapper<T> according to actual needs.

6.1 Implementing a Customized Mapper

Create a new common package in the common-mapper project to store the customized mapper <T> and create CustMapper<T>

public interface CustMapper<T> extends SelectOneMapper<T> {}Copy the code

You can also choose to inherit multiple, such as SelectAllMapper<T>.

Configure custom CustMapper<T> in the Spring configuration file application.xml

<bean id="mapperScannerConfigurer" class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
    <! -- specify the package where the interface resides -->
    <property name="basePackage" value="com.citi.mapper"></property>
    <! Configure the custom CustMapper<T> interface
    <property name="properties">
        <value>
            mappers=com.citi.common.CustMapper
        </value>
    </property>
</bean>
Copy the code

Modify TeacherMapper inheritance to inherit the custom CustMapper<T> interface

public interface TeacherMapper extends CustMapper<Teacher> {}Copy the code

TeacherMapperTest added TeacherMapperTest to test inherited selectOne methods

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:application.xml")
public class TeacherMapperTest {

    @Resource
    private TeacherMapper teacherMapper;

    @Test
    public void selectOne(a){
        // construct the query condition
        Teacher record = new Teacher();
        record.setGrade("Class two, Three");
        record.setName("stark");
        Teacher teacher = teacherMapper.selectOne(record);
        System.out.println("The query output is:"+ teacher); }}Copy the code

Perform the testThe data obtained based on the query condition is successfully displayed

Plus: The custom Mapper and XxxMapper interfaces cannot be placed in the same package. As a result, the Spring container fails to create beans for the custom Mapper

7. Universal Mapper extension

Extension refers to the increase of the general Mapper does not have the function, the general Mapper provides a series of basic add, delete, change, query and condition query primary key query methods, but does not provide the method of batch operation, the official website gives the extension of the general Mapper example is extended the function of batch insertion.

7.1 Extended Batch Update

Custom Mapper extensions can refer to the official existing code.

Write our own BatchUpdateMapper<T> interface modeled after the official UpdateByPrimaryKeyMapper<T> interface

@RegisterMapper
public interface BatchUpdateMapper<T> {

    @UpdateProvider(type = BatchUpdateProvider.class, method = "dynamicSQL")
    void batchUpdate(List<T> tList);
}
Copy the code

Create a new BatchUpdateProvider under the Common packageImplement a custom BatchUpdateProvider, modeled after the official BaseUpdateProvider, by first declaring a constructor

public class BatchUpdateProvider extends MapperTemplate {

    / / the constructor
    public BatchUpdateProvider(Class
        mapperClass, MapperHelper mapperHelper) {
        super(mapperClass, mapperHelper); }}Copy the code

Write the following format into the Mapper XML file for batch UPDATE SQL statements. Connect to execute

<foreach item="record" collection="list" separator=";">
    UPDATE porsche
    <set>
    por_name = #{porsche.porName},
    por_price = #{porsche.porPrice},
    por_stock = #{porsche.porStock},
    </set>
    por_id = #{porsche.por_id}
</foreach>
Copy the code

This is the SQL statement we are concatenating. Add a method to the BatchUpdateProvider class, batchUpdate, which returns a String that is the SQL statement to execute

public String batchUpdate(MappedStatement ms){

    1. Create an SQL statement
    StringBuilder sql = new StringBuilder();
    // 2. Concatenate the beginning of the foreach tag
    sql.append("<foreach item="record" collection="list" separator=";">");

    // Get the entity-class objectClass<? > entityClass = getEntityClass(ms); String updateClause = SqlHelper.updateTable(entityClass,tableName(entityClass));// select * from table_name;
    sql.append(updateClause);

    // 4. Concatenate the start of the set tag
    sql.append("<set>");

    // Get a collection of field names
    Set<EntityColumn> columns = EntityHelper.getColumns(entityClass);

    // Declare the primary key field
    String idColumn = null;
    String idColumnHolder = null;

    // Iterate over the fields
    for (EntityColumn entityColumn : columns) {

        // Determine if it is the primary key. If it is the primary key, place it after the WHERE clause
        boolean isPrimaryKey = entityColumn.isId();
        System.out.println(isPrimaryKey);

        if (isPrimaryKey){
            idColumn = entityColumn.getColumn();
            System.out.println(idColumn);
            idColumnHolder = entityColumn.getColumnHolder("record");
        } else {

            // Returns a string similar to "(entity class). Properties, jdbcType = NUMERIC, typeHandler = MyTypeHandler)"
            // Get the field name and attribute name
            String column = entityColumn.getColumn();
            String columnHolder = entityColumn.getColumnHolder("record");
            Por_name = #{porsch.porname},
            sql.append(column).append("=").append(columnHolder).append(","); }}// 6. Concatenate the end of set tag
    sql.append("</set>");

    // 7. Join the WHERE clause
    sql.append("where ").append(idColumn).append("=").append(idColumnHolder);

    // 8. Join the end of the foreach tag
    sql.append("</foreach>");
    // 9. Return the SQL statement
    return sql.toString();
}
Copy the code

The steps in the code for stitching and batch updating SQL are as follows:

  1. Create a new SQL statement
  2. Concatenate the beginning of the foreach tag
  3. Splicing “UPDATE porsche”
  4. Concatenate the start of the set tag
  5. Splice_por_name = #{porsche.porname}
  6. Concatenate the end of the set tag
  7. Concatenate the WHERE clause
  8. Concatenate the end of the foreach tag
  9. Return SQL statement

Then let the custom CustMapper inherit from the custom BatchUpdateMapper

public interface CustMapper<T> extends SelectOneMapper<T>,BatchUpdateMapper<T> {}Copy the code

Because the TeacherMapper interface inherits CustMapper, all TeacherMapper interfaces automatically obtain the batchUpdate method, adding tests for batchUpdate to the TeacherMapperTest test class

@Test
public void batchUpdate(a){
    List<Teacher> teacherList = new ArrayList<>();
    for (int i = 7; i < 10; i++) {
        Teacher teacher = new Teacher();
        teacher.setId(i);
        teacher.setGrade("Five years" + i + "Class");
        teacher.setName("Ultron " + i);
        teacher.setAddress("New York");
        teacher.setBirthDate(new Date());
        teacherList.add(teacher);
    }
    teacherMapper.batchUpdate(teacherList);
}
Copy the code

Note before running the test because the update statement passes multiple SQL statements with “;” Jdbc_url = &allowMultiqueries =true

Perform the test

The Teacher entity class does not add @ID annotation to the ID attribute. That is to say, the general Mapper does not know that the field corresponding to the ID attribute is the primary key, so it does not make a correct judgment. Error statement causing output console. Add @ID annotations and @GeneratedValue annotations to the ID attribute

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
Copy the code

Run the test again

The database is modified successfully.

The customized batch update extension takes effect.