tk.mybatis通用工具采坑記


tk.mybatis通用工具pom

 <!--mybatis依賴-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.1</version>
</dependency>

<!--通用mapper-->
<dependency>
    <groupId>tk.mybatis</groupId>
    <artifactId>mapper-spring-boot-starter</artifactId>
    <version>1.1.5</version>
</dependency>
  • 我使用springboot搭建,所以引用的都是springboot封裝的組件

采坑點

批量插入數據,默認主鍵只支持id

  1. 繼承此工具MySqlMapper方法后
/**
 * 通用Mapper接口,MySql獨有的通用方法
 *
 * @param <T> 不能為空
 * @author liuzh
 */
public interface MySqlMapper<T> extends
        InsertListMapper<T>,
        InsertUseGeneratedKeysMapper<T> {

}
  • 可以看到存在可以批量插入類到數據庫的方法
  • 如果項目中途加入了此工具,那么恭喜,估計要踩很多坑~
  • 數據庫表主鍵不為id時,可以繼續看源碼
public interface InsertListMapper<T> {

    /**
     * 批量插入,支持批量插入的數據庫可以使用,例如MySQL,H2等,另外該接口限制實體包含`id`屬性並且必須為自增列
     *
     * @param recordList
     * @return
     */
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @InsertProvider(type = SpecialProvider.class, method = "dynamicSQL")
    int insertList(List<T> recordList);

    /**
     * ======如果主鍵不是id怎么用?==========
     * 假設主鍵的屬性名是uid,那么新建一個Mapper接口如下
     * <pre>
        public interface InsertUidListMapper<T> {
            @Options(useGeneratedKeys = true, keyProperty = "uid")
            @InsertProvider(type = SpecialProvider.class, method = "dynamicSQL")
            int insertList(List<T> recordList);
        }
     * 只要修改keyProperty = "uid"就可以
     *
     * 然后讓你自己的Mapper繼承InsertUidListMapper<T>即可
     *
     * </pre>
     */
}
  • 他留着坑還是很負責的把解決辦法留下了~~
  • 我是按網上通用的搭建方式搭建的目錄結構,也就是如下結構
/**
 * 繼承自己的MyMapper
 *
 */
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {
    //FIXME 特別注意,該接口不能被掃描到,否則會出錯
    //FIXME 最后在啟動類中通過MapperScan注解指定掃描的mapper路徑:
}
  • 因為InsertUidListMapper這種特殊寫的mapper和MyMapper是同一類,如果不同樣配置下會報如下錯誤
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error invoking SqlProvider method (tk.mybatis.mapper.provider.SpecialProvider.dynamicSQL).  Cause: java.lang.InstantiationException: tk.mybatis.mapper.provider.SpecialProvider
  • 這時候你要,在application.properties中,把InsertUidListMapper路徑配上去
mapper.mappers=com.tzxylao.manager.utils.MyMapper,com.tzxylao.manager.mapper_ext.InsertUidListMapper
  • 還有一點,光這樣匹配后還不夠,自己寫的類DpageConfigMapper,繼承InsertUidListMapper 這個類后,把DpageConfigMapper類放在Mapper目錄下,那么又會很糾結。系統啟動會掃描不到DpageConfigMapper這個類。。我竟然找不到默認掃描Mapper包的地方。。但是經驗告訴我,繼承了MyMapper的類都能被掃描到~~
  • 可是自己的類繼承的是InsertUidListMapper ,想要它被掃描,啟動類就要加上掃描包的地方。。我掃描了整個Mapper包
@EnableTransactionManagement  // 啟注解事務管理,等同於xml配置方式的
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAutoConfiguration
@MapperScan("com.tzxylao.manager.mapper")
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
}
  • 但這樣要注意,繼承類InsertUidListMapper ,不能再這個包里,否則會報該類不能被掃描錯誤~~
  • 就算把這個類移到了其他包,系統也可以正常運行了。。其實還是有點問題。。啟動的時候會出現類似的警告
Skipping MapperFactoryBean with name 'sysMenuMapper' and 'com.telchina.framework.sys.mapper.SysMenuMapper' mapperInterface. Bean already defined with the same name!

雖然不影響使用,但還是看着煩,他的意思就是這個類被掃了兩遍我就說哪里MyMapper類繼承的類都被莫名其妙掃了一遍。。自己再配置掃一遍就重復了

  • 解決辦法就是再建個子包,不繼承MyMapper的自定義Mapper都放子包,再單獨配置子包掃描
@EnableTransactionManagement  // 啟注解事務管理,等同於xml配置方式的
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableAutoConfiguration
@MapperScan("com.tzxylao.manager.mapper.ext")
public class Application extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(Application.class);
    }
}

把DpageConfigMapper類放ext子包里就行了。。

  • 上面步驟都解決了,插入還是不成功的,插入語句沒有主鍵,自己生成的主鍵插不進去?
  • 看源碼
 /**
 * 批量插入
 *
 * @param ms
 */
public String insertList(MappedStatement ms) {
    final Class<?> entityClass = getEntityClass(ms);
    //開始拼sql
    StringBuilder sql = new StringBuilder();
    sql.append(SqlHelper.insertIntoTable(entityClass, tableName(entityClass)));
    sql.append(SqlHelper.insertColumns(entityClass, true, false, false));
    sql.append(" VALUES ");
    sql.append("<foreach collection=\"list\" item=\"record\" separator=\",\" >");
    sql.append("<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">");
    //獲取全部列
    Set<EntityColumn> columnList = EntityHelper.getColumns(entityClass);
    //當某個列有主鍵策略時,不需要考慮他的屬性是否為空,因為如果為空,一定會根據主鍵策略給他生成一個值
    for (EntityColumn column : columnList) {
        if (!column.isId() && column.isInsertable()) {
            sql.append(column.getColumnHolder("record") + ",");
        }
    }
    sql.append("</trim>");
    sql.append("</foreach>");
    return sql.toString();
}
  • 可以看到,主鍵插入的地方,他有這樣的判斷!column.isId() && column.isInsertable(),所以,Bean類主鍵屬性上@Id去掉,就可以自己添加主鍵值了

總結

  • 總覺的我的解決方法很low,限制也太大~有熟悉tk.mybatis的大神講下別的思路嗎?


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM