使用Mybatis-Plus問題解答

2023-06-06 15:01:23

我們使用一個新的框架難免會遇到各種問題,當然使用這款國產的優秀的Mybatis-Plus框架也不例外,下面我就給大家列舉一下使用Mybatis-Plus可能遇到的一些問題,並做一下一一的解答。

1:如何排除非表的欄位(這個問題一定要注意,我們Java中寫的Entity類的屬性是和表的欄位一一對應的,如果屬性在資料庫中沒有對應欄位程式就會出錯。當然表中可以有多的欄位)。

使用一些三種方法都可以:(開發中我們經常使用第三者方式)

使用 transient 修飾: 

private transient String noColumn; 

使用 static 修飾 :

private static String noColumn; 

使用 TableField 註解:

@TableField(exist=false)

private String noColumn;

2:出現 Invalid bound statement (not found) 異常 (這種一般是寫的mapper介面找不到對應的xml中的mapper中寫的sql)

不要懷疑,正視自己,這個異常肯定是你插入的姿勢不對……

  • 檢查是不是引入 jar 衝突

  • 檢查 Mapper.java 的掃描路徑

方法一:在 Configuration 類上使用註解 MapperScan

@Configuration
@MapperScan("com.yourpackage.*.mapper")
public class YourConfigClass{
  ...
}

方法二:在Configuration類裡面,設定MapperScannerConfigurer

@Bean
public MapperScannerConfigurer mapperScannerConfigurer(){
    MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
    //可以通過環境變數獲取你的mapper路徑,這樣mapper掃描可以通過組態檔設定了
    scannerConfigurer.setBasePackage("com.yourpackage.*.mapper");
    return scannerConfigurer;
}
  • 檢查是否指定了主鍵?如未指定,則會導致 selectById 相關 ID 無法操作,請用註解 @TableId 註解表 ID 主鍵。當然 @TableId 註解可以沒有!但是你的主鍵必須叫 id(忽略大小寫)

  • SqlSessionFactory不要使用原生的,請使用MybatisSqlSessionFactory

  • 檢查是否自定義了SqlInjector,是否複寫了getMethodList()方法,該方法裡是否注入了你需要的方法(可參考DefaultSqlInjector)

  • IDEA 預設的 build 步驟可能會引起 mapper 檔案無法正常編譯到對應的 resources 資料夾中,請檢查 build 之後相關資原始檔夾是否有對應的 xml 檔案,如果沒有,請調整 IDEA 的 build 設定,推薦調整為 Maven 或 Gradle 的 build。

3:自定義 SQL 無法執行

問題描述:指在 XML 中裡面自定義 SQL,卻無法呼叫。本功能同 MyBatis 一樣需要設定 XML 掃描路徑:

Spring MVC 設定

<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="typeAliasesPackage" value="xxx.entity" />
    <property name="mapperLocations" value="classpath*:/mybatis/*/*.xml"/>
    ...
</bean>

Spring Boot 設定

mybatis-plus:
  mapper-locations: classpath*:/mapper/**/*.xml

對於IDEA系列編輯器,XML 檔案是不能放在 java 資料夾中的,IDEA 預設不會編譯原始碼資料夾中的 XML 檔案,可以參照以下方式解決:

1:將組態檔放在 resource 資料夾中

2:對於 Maven 專案,可指定 POM 檔案的 resource

<build>
  <resources>
      <resource>
          <!-- xml放在java目錄下-->
          <directory>src/main/java</directory>
          <includes>
              <include>**/*.xml</include>
          </includes>
      </resource>
      <!--指定資源的位置(xml放在resources下,可以不用指定)-->
      <resource>
          <directory>src/main/resources</directory>
      </resource>
  </resources>
</build>

提示 注意!

Maven 多模組專案的掃描路徑需以 classpath*: 開頭 (即載入多個 jar 包下的 XML 檔案)

4:關於 Long 型主鍵填充不生效的問題

檢查是不是用了long而不是Long!

提示 

long型別預設值為 0,而 MP 只會判斷是否為 null

JavaScript 無法處理 Java 的長整型 Long 導致精度丟失,具體表現為主鍵最後兩位永遠為 0,解決思路:Long 轉為 String 返回。

FastJson 處理方式

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    FastJsonHttpMessageConverter fastJsonConverter = new FastJsonHttpMessageConverter();
    FastJsonConfig fjc = new FastJsonConfig();
    // 設定序列化策略
    fjc.setSerializerFeatures(SerializerFeature.BrowserCompatible);
    fastJsonConverter.setFastJsonConfig(fjc);
    converters.add(fastJsonConverter);
}

JackJson 處理方式

方式一

/ 註解
處理,這裡可以設定公共 baseEntity 處理
@JsonSerialize(using=ToStringSerializer.class)
public long getId() {
    return id;
}

方式二

/ 全域性設定序列化返回 JSON 處理
final ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);

5:插入或更新的欄位有 空字串 或者 null

FieldStrategy 有以下策略:

方式一:調整欄位驗證註解

根據具體情況,在需要更新的欄位中調整驗證註解,如驗證非空:

@TableField(strategy=FieldStrategy.NOT_EMPTY)

方式二:使用 UpdateWrapper (3.x)

使用以下方法來進行更新或插入操作:

//updateAllColumnById(entity) // 全部欄位更新: 3.0已經移除
mapper.update(
   new User().setName("mp").setAge(3),
   Wrappers.<User>lambdaUpdate()
           .set(User::getEmail, null) //把email設定成null
           .eq(User::getId, 2)
);
//也可以參考下面這種寫法
mapper.update(
    null,
    Wrappers.<User>lambdaUpdate()
       .set(User::getAge, 3)
       .set(User::getName, "mp")
       .set(User::getEmail, null) //把email設定成null
       .eq(User::getId, 2)
);

6:欄位型別為 bit、tinyint(1) 時對映為 boolean 型別

預設mysql驅動會把tinyint(1)欄位對映為boolean: 0=false, 非0=true。MyBatis 是不會自動處理該對映,如果不想把tinyint(1)對映為boolean型別:

修改型別tinyint(1)為tinyint(2)或者int。

需要修改請求連線新增引數 tinyInt1isBit=false,如下:

jdbc:mysql://127.0.0.1:3306/mp?tinyInt1isBit=false

7:MP 如何查指定的幾個欄位

EntityWrapper.sqlSelect 設定你想要查詢的欄位

//2.x
EntityWrapper<H2User> ew = new EntityWrapper<>();
ew.setSqlSelect("test_id as id, name, age");//只查詢3個欄位
List<H2User> list = userService.selectList(ew);
for(H2User u:list){
    Assert.assertNotNull(u.getId());
    Assert.assertNotNull(u.getName());
    Assert.assertNull(u.getPrice()); // 這個欄位沒有查詢出來
}

//3.x
mapper.selectList(
    Wrappers.<User>lambdaQuery()
    .select(User::getId, User::getName)
);
//或者使用QueryWrapper
mapper.selectList(
    new QueryWrapper<User>()
    .select("id","name")
);

8:Cause: org.apache.ibatis.type.TypeException:Error setting null for parameter #1 with JdbcType OTHER

設定 jdbcTypeForNull=NULL Spring Bean 設定方式:

MybatisConfiguration configuration = new MybatisConfiguration();
configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
configuration.setJdbcTypeForNull(JdbcType.NULL);
configuration.setMapUnderscoreToCamelCase(true);//開啟下劃線轉駝峰
sqlSessionFactory.setConfiguration(configuration);

yml 設定

mybatis-plus:
  configuration:
    jdbc-type-for-null: 'null'

9:通用 insertBatch 為什麼放在 service 層處理

SQL 長度有限制海量資料量單條 SQL 無法執行,就算可執行也容易引起記憶體洩露 JDBC 連線超時等

不同資料庫對於單條 SQL 批次語法不一樣不利於通用

目前的解決方案:迴圈預處理批次提交,雖然效能比單 SQL 慢但是可以解決以上問題。

10:啟動 mybatis 本身的 log 紀錄檔

# 方式一
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 

# 方式二 application.yml 中增加設定,指定 mapper 檔案所在的包
logging:
  level:
    com.baomidou.example.mapper: debug

這些問題都是摘自Mybatis-Plus的官方網站地址如下:

https://www.baomidou.com/pages/f84a74/

如果想看更多的問題請存取上面的網址,當然更多的問題也可以存取Mybatis-Plus的github地址那裡面有很多人提的issue。很多開發中遇到的問題都可以在issue裡面找到答案,我也是常常去看那裡的issue從裡面獲取答案獲取靈感。歡迎大家關注我的微信公眾號,繼續為大家推出好的文章。

晚霞和微風是真的很美。