Some background SpringBoot + pit Mybatis development experience

table of Contents

First, tell us about the first development framework, SpringBoot + Mybatis, SpringBoot integrated Tomcat therefore, no need to download Tomcat service running directly build a complete development package can be run jar, Mybatis-Plus to add conditions to the constructor EntityWrapper very easy to use, can be conditions need to query all the constructors put, the execution is good.

Second, following review some pit encountered in the development, want to refer to each other

   2.1 properties configuration file errors can not start

More typical is the address of the database is configured incorrectly, resulting in service does not start up, we need to check the connection, and second, it will display an error or sql injection is mapper and other errors that need extra attention.

 2.2 Mapper.xml file mapping error

As the field mapping errors occur because of database and Entity Mapper as a bridge, the field inspection is necessary, just a mistake, and the system may not run up.

2.3 Mybatis-Plus abnormal summary statement


/**
 * Copyright (c) 2011-2016, hubin ([email protected]).
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.baomidou.mybatisplus.service.impl;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.entity.TableInfo;
import com.baomidou.mybatisplus.enums.SqlMethod;
import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.mapper.BaseMapper;
import com.baomidou.mybatisplus.mapper.Condition;
import com.baomidou.mybatisplus.mapper.SqlHelper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.IService;
import com.baomidou.mybatisplus.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.toolkit.MapUtils;
import com.baomidou.mybatisplus.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.toolkit.StringUtils;
import com.baomidou.mybatisplus.toolkit.TableInfoHelper;

/**
 * <p>
 * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 , PK 是主键泛型 )
 * </p>
 *
 * @author hubin
 * @Date 2016-04-20
 */
public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {

    private static final Log logger = LogFactory.getLog(ServiceImpl.class);

    @Autowired
    protected M baseMapper;

    /**
     * <p>
     * 判断数据库操作是否成功
     * </p>
     * <p>
     * 注意!! 该方法为 Integer 判断,不可传入 int 基本类型
     * </p>
     *
     * @param result 数据库操作返回影响条数
     * @return boolean
     */
    protected static boolean retBool(Integer result) {
        return SqlHelper.retBool(result);
    }

    @SuppressWarnings("unchecked")
    protected Class<T> currentModelClass() {
        return ReflectionKit.getSuperClassGenricType(getClass(), 1);
    }

    /**
     * <p>
     * 批量操作 SqlSession
     * </p>
     */
    protected SqlSession sqlSessionBatch() {
        return SqlHelper.sqlSessionBatch(currentModelClass());
    }

    /**
     * 获取SqlStatement
     *
     * @param sqlMethod
     * @return
     */
    protected String sqlStatement(SqlMethod sqlMethod) {
        return SqlHelper.table(currentModelClass()).getSqlStatement(sqlMethod.getMethod());
    }

    @Transactional
    public boolean insert(T entity) {
        return retBool(baseMapper.insert(entity));
    }

    @Transactional
    public boolean insertAllColumn(T entity) {
        return retBool(baseMapper.insertAllColumn(entity));
    }

    @Transactional
    public boolean insertBatch(List<T> entityList) {
        return insertBatch(entityList, 30);
    }

    /**
     * 批量插入
     *
     * @param entityList
     * @param batchSize
     * @return
     */
    @Transactional
    public boolean insertBatch(List<T> entityList, int batchSize) {
        if (CollectionUtils.isEmpty(entityList)) {
            throw new IllegalArgumentException("Error: entityList must not be empty");
        }
        try (SqlSession batchSqlSession = sqlSessionBatch()) {
            int size = entityList.size();
            String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
            for (int i = 0; i < size; i++) {
                batchSqlSession.insert(sqlStatement, entityList.get(i));
                if (i >= 1 && i % batchSize == 0) {
                    batchSqlSession.flushStatements();
                }
            }
            batchSqlSession.flushStatements();
        } catch (Throwable e) {
            throw new MybatisPlusException("Error: Cannot execute insertBatch Method. Cause", e);
        }
        return true;
    }

    /**
     * <p>
     * TableId 注解存在更新记录,否插入一条记录
     * </p>
     *
     * @param entity 实体对象
     * @return boolean
     */
    @Transactional
    public boolean insertOrUpdate(T entity) {
        if (null != entity) {
            Class<?> cls = entity.getClass();
            TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
            if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty())) {
                Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
                if (StringUtils.checkValNull(idVal)) {
                    return insert(entity);
                } else {
                    /*
                     * 更新成功直接返回,失败执行插入逻辑
					 */
                    return updateById(entity) || insert(entity);
                }
            } else {
                throw new MybatisPlusException("Error:  Can not execute. Could not find @TableId.");
            }
        }
        return false;
    }

    @Transactional
    public boolean insertOrUpdateAllColumn(T entity) {
        if (null != entity) {
            Class<?> cls = entity.getClass();
            TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
            if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty())) {
                Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
                if (StringUtils.checkValNull(idVal)) {
                    return insertAllColumn(entity);
                } else {
                    /*
                     * 更新成功直接返回,失败执行插入逻辑
					 */
                    return updateAllColumnById(entity) || insertAllColumn(entity);
                }
            } else {
                throw new MybatisPlusException("Error:  Can not execute. Could not find @TableId.");
            }
        }
        return false;
    }

    @Transactional
    public boolean insertOrUpdateBatch(List<T> entityList) {
        return insertOrUpdateBatch(entityList, 30);
    }

    @Transactional
    public boolean insertOrUpdateBatch(List<T> entityList, int batchSize) {
        return insertOrUpdateBatch(entityList, batchSize, true);
    }

    @Transactional
    public boolean insertOrUpdateAllColumnBatch(List<T> entityList) {
        return insertOrUpdateBatch(entityList, 30, false);
    }

    @Transactional
    public boolean insertOrUpdateAllColumnBatch(List<T> entityList, int batchSize) {
        return insertOrUpdateBatch(entityList, batchSize, false);
    }

    /**
     * 批量插入修改
     *
     * @param entityList 实体对象列表
     * @param batchSize  批量刷新个数
     * @param selective  是否滤掉空字段
     * @return boolean
     */
    private boolean insertOrUpdateBatch(List<T> entityList, int batchSize, boolean selective) {
        if (CollectionUtils.isEmpty(entityList)) {
            throw new IllegalArgumentException("Error: entityList must not be empty");
        }
        try (SqlSession batchSqlSession = sqlSessionBatch()) {
            int size = entityList.size();
            for (int i = 0; i < size; i++) {
                if (selective) {
                    insertOrUpdate(entityList.get(i));
                } else {
                    insertOrUpdateAllColumn(entityList.get(i));
                }
                if (i >= 1 && i % batchSize == 0) {
                    batchSqlSession.flushStatements();
                }
            }
            batchSqlSession.flushStatements();
        } catch (Throwable e) {
            throw new MybatisPlusException("Error: Cannot execute insertOrUpdateBatch Method. Cause", e);
        }
        return true;
    }

    @Transactional
    public boolean deleteById(Serializable id) {
        return retBool(baseMapper.deleteById(id));
    }

    @Transactional
    public boolean deleteByMap(Map<String, Object> columnMap) {
        if (MapUtils.isEmpty(columnMap)) {
            throw new MybatisPlusException("deleteByMap columnMap is empty.");
        }
        return retBool(baseMapper.deleteByMap(columnMap));
    }

    @Transactional
    public boolean delete(Wrapper<T> wrapper) {
        return retBool(baseMapper.delete(wrapper));
    }

    @Transactional
    public boolean deleteBatchIds(List<? extends Serializable> idList) {
        return retBool(baseMapper.deleteBatchIds(idList));
    }

    @Transactional
    public boolean updateById(T entity) {
        return retBool(baseMapper.updateById(entity));
    }

    @Transactional
    public boolean updateAllColumnById(T entity) {
        return retBool(baseMapper.updateAllColumnById(entity));
    }

    @Transactional
    public boolean update(T entity, Wrapper<T> wrapper) {
        return retBool(baseMapper.update(entity, wrapper));
    }

    @Transactional
    public boolean updateBatchById(List<T> entityList) {
        return updateBatchById(entityList, 30);
    }

    @Transactional
    public boolean updateBatchById(List<T> entityList, int batchSize) {
        return updateBatchById(entityList, batchSize, true);
    }

    @Transactional
    public boolean updateAllColumnBatchById(List<T> entityList) {
        return updateAllColumnBatchById(entityList, 30);
    }

    @Transactional
    public boolean updateAllColumnBatchById(List<T> entityList, int batchSize) {
        return updateBatchById(entityList, batchSize, false);
    }

    /**
     * 根据主键ID进行批量修改
     *
     * @param entityList 实体对象列表
     * @param batchSize  批量刷新个数
     * @param selective  是否滤掉空字段
     * @return boolean
     */
    private boolean updateBatchById(List<T> entityList, int batchSize, boolean selective) {
        if (CollectionUtils.isEmpty(entityList)) {
            throw new IllegalArgumentException("Error: entityList must not be empty");
        }
        try (SqlSession batchSqlSession = sqlSessionBatch()) {
            int size = entityList.size();
            SqlMethod sqlMethod = selective ? SqlMethod.UPDATE_BY_ID : SqlMethod.UPDATE_ALL_COLUMN_BY_ID;
            String sqlStatement = sqlStatement(sqlMethod);
            for (int i = 0; i < size; i++) {
                MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
                param.put("et", entityList.get(i));
                batchSqlSession.update(sqlStatement, param);
                if (i >= 1 && i % batchSize == 0) {
                    batchSqlSession.flushStatements();
                }
            }
            batchSqlSession.flushStatements();
        } catch (Throwable e) {
            throw new MybatisPlusException("Error: Cannot execute updateBatchById Method. Cause", e);
        }
        return true;
    }

    public T selectById(Serializable id) {
        return baseMapper.selectById(id);
    }

    public List<T> selectBatchIds(List<? extends Serializable> idList) {
        return baseMapper.selectBatchIds(idList);
    }

    public List<T> selectByMap(Map<String, Object> columnMap) {
        return baseMapper.selectByMap(columnMap);
    }

    public T selectOne(Wrapper<T> wrapper) {
        return SqlHelper.getObject(baseMapper.selectList(wrapper));
    }

    public Map<String, Object> selectMap(Wrapper<T> wrapper) {
        return SqlHelper.getObject(baseMapper.selectMaps(wrapper));
    }

    public Object selectObj(Wrapper<T> wrapper) {
        return SqlHelper.getObject(baseMapper.selectObjs(wrapper));
    }

    public int selectCount(Wrapper<T> wrapper) {
        return SqlHelper.retCount(baseMapper.selectCount(wrapper));
    }

    public List<T> selectList(Wrapper<T> wrapper) {
        return baseMapper.selectList(wrapper);
    }

    @SuppressWarnings("unchecked")
    public Page<T> selectPage(Page<T> page) {
        return selectPage(page, Condition.EMPTY);
    }

    public List<Map<String, Object>> selectMaps(Wrapper<T> wrapper) {
        return baseMapper.selectMaps(wrapper);
    }

    public List<Object> selectObjs(Wrapper<T> wrapper) {
        return baseMapper.selectObjs(wrapper);
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    public Page<Map<String, Object>> selectMapsPage(Page page, Wrapper<T> wrapper) {
        SqlHelper.fillWrapper(page, wrapper);
        page.setRecords(baseMapper.selectMapsPage(page, wrapper));
        return page;
    }

    public Page<T> selectPage(Page<T> page, Wrapper<T> wrapper) {
        SqlHelper.fillWrapper(page, wrapper);
        page.setRecords(baseMapper.selectPage(page, wrapper));
        return page;
    }
}

 

mybatisplus provide CRUD interfaces and implementation class, on the map, we need only to extend, and the physical condition on the line, but configured to be aware of the following Preparation Method Laid

  (1)

@Transactional
public boolean updateById(T entity) {
    return retBool(baseMapper.updateById(entity));
}

Incoming entity class data table must have an ID column, otherwise it will directly update error, so this method development and less common, but with

@Transactional
public boolean update(T entity, Wrapper<T> wrapper) {
    return retBool(baseMapper.update(entity, wrapper));
}

(2)

@Transactional
public boolean deleteById(Serializable id) {
    return retBool(baseMapper.deleteById(id));
}
This method is the same, there must be the job ID column.

(3)

/**
 * 批量插入
 *
 * @param entityList
 * @param batchSize
 * @return
 */
@Transactional
public boolean insertBatch(List<T> entityList, int batchSize) {
    if (CollectionUtils.isEmpty(entityList)) {
        throw new IllegalArgumentException("Error: entityList must not be empty");
    }
    try (SqlSession batchSqlSession = sqlSessionBatch()) {
        int size = entityList.size();
        String sqlStatement = sqlStatement(SqlMethod.INSERT_ONE);
        for (int i = 0; i < size; i++) {
            batchSqlSession.insert(sqlStatement, entityList.get(i));
            if (i >= 1 && i % batchSize == 0) {
                batchSqlSession.flushStatements();
            }
        }
        batchSqlSession.flushStatements();
    } catch (Throwable e) {
        throw new MybatisPlusException("Error: Cannot execute insertBatch Method. Cause", e);
    }
    return true;
}

, We can see that this approach, when an incoming null or empty set when parameters illegal direct throw an exception, it must be inserted before the bulk of the collection emptying judgment.

(4)

public Page<T> selectPage(Page<T> page, Wrapper<T> wrapper) {
    SqlHelper.fillWrapper(page, wrapper);
    page.setRecords(baseMapper.selectPage(page, wrapper));
    return page;
}

Mabits paging query is a good method, it is convenient to help us check out the current page number and the total collection of front-end query page shows very convenient, but be careful, you must create a page filter is valid

package com.yxytech.parkingcloud.efss.config;

import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        paginationInterceptor.setLocalPage(true);// 开启 PageHelper 的支持

        return paginationInterceptor;
    }
}

2.4 SQL statement abnormalities

Mybatis development does not require you to write SQL statements, but when it comes to multi-table related query time, only to write SQL by himself, his EntityWrapper (condition constructor) do not support, so there will be the following:

(1) written in the form of notes in Mybatis Service interface:

public interface IBlackFileStatusVersionService extends IBaseService<BlackFileStatusVersion> {
    @Select("TRUNCATE TABLE U03_StatusList_Version")
    void deleteAll();

    BlackFileStatusVersion constructBlackVersion(String key, String issuerVersion, int dif, int recordCount, String zipFilePath);

    boolean insert2DB(CardStatuVersion version, String fileName);
}

Above: Empty table data, special attention statement is correct enough, preferably after a successful test execution database, and then paste the code

(2) to write complex SQL statements in xxxMapper.xml file (recommended)

This approach may need to pass parameters: @Param

public interface XXXInfoStateMapper{
​​​​​​​ List<XXXinfo> selectListByPage(@Param("start") long start, @Param("end") long end);
}

<select id="selectListByPage" resultType="com.XXX.XXX.front.entity.XXXiNFO">
        SELECT *
        from xxx_TRAN_ZH t1
        inner join xxx_PROCESS_STATE t2 on t1.MID = t2.MID
        where TRANS_SERIAL_SN is not null
        and t2.PROCESS_RESULT = -2 and t1.MID &gt;= #{start} and t1.MID &lt; #{end} and t1.ENT_OccurTime > '2018-01-01 00:00:00'
    </select>

This query is also very easy wrong, it is best to write performed to re-glue in the database. Parameters {#} way incoming xml

2.5 SpringBoot interface


@RestController
@RequestMapping("/front")
public class XXXFrontController extends BaseController {
}

Long before the project appeared debugging, HTTP request interface is not received, and later found the problem @RestController, @ Controller can return to view parser can parse Html, jsp page, but @RestController equivalent @Controller and @ResponseBody combination body, the returned results interface method return value. General items are returned in json format, now rarely the page jump through the server configuration, but also very bad for the development of multi-degree of freedom of movement, it is recommended that you still use @RestController comment.

Finally, in development will encounter various problems, we will try to add up, thank you.

 

 


Published 19 original articles · won praise 19 · views 30000 +

Guess you like

Origin blog.csdn.net/baidu_30084597/article/details/100778756