前一段用springboot寫了篇 springboot整合多數據源小博文,從三個數據庫裏面抓取合適的數據。存在另外一個數據庫裏面。在客戶生產環境運行了一段時間,感覺似乎很良好。
客戶覺得意猶未盡,又提了點需求,順便提了點bug,於是乎又改了改代碼。客戶居然提出一個問題,說有時候查不出數據來,過一會又好了,我在本地試了試,發現在本地竟然也存在這個問題。問題其實一直都有,只是似乎不影響什麼,所以便沒當一回事。
經過反覆測試,原來是往數據庫寫數據的時候卡住了,有點奇怪。大概過程是先把表裏面數據清除,然後再寫入,數據不到1000條,居然耗時差不多10秒,什麼springboot,什麼jpa太不靠譜了吧?
看代碼 ,Repository
package net.springboot.repository.sqlserver;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import net.springboot.entity.sqlserver.RealData;
public interface XXDataRepository extends JpaRepository<XXData, String>
{
}
調用代碼也是簡單明瞭
db.deleteAll();
db.saveAll(list); //組合list這裏就不寫了
其實說白了,沒有自己的代碼,都是springboot + jpa 框架實現的,框架難道有問題,這個一般不會吧。把SQL放出來看看。
原來這個樣子,刪除全表數據,居然是一條一條數據刪除,批量保存居然是先查詢一下,然後再插入,JPA難道不考慮效率的嗎?
問題找到了,怎麼解決了?刪除功能好辦,自己寫SQL嘛,簡單方便,翠花上川菜,代碼拿來。
@Transactional
@Modifying
@Query(value = "TRUNCATE TABLE table",nativeQuery = true)
int TruncateTable();
@Transactional
@Modifying
@Query(value = "delete from table",nativeQuery = true)
int deleteTable();
效果是立竿見影,刪除效率上來了。清空表裏數據一秒不到。不過,後來又仔細看了一下,jpa似乎還提供了另外一個刪除全部數據的方法 deleteAllInBatch,這個方法在刪除前似乎沒有查詢,懶得做測試了,習慣了自己寫SQL解決問題。
但是批量插入這個不好辦了,總不可能自己寫成一條一條插入啊,那還不如不改了。百度一下,網上說改一下配置文件即可。
spring.jpa.properties.hibernate.jdbc.batch_size=500
spring.jpa.properties.hibernate.jdbc.batch_versioned_data=true
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
但是好像效果不行,show sql 還是一樣,先查詢後插入,效率依然不行。想了很多,百度了很多,爲什麼了,爲什麼啊?JPA這玩意爲什麼會在插入前查詢一下了,查詢又是怎麼個查詢方式了?這個應該與主鍵ID有關係。所以改一下實體類,id統一爲uuid模式。
@Id
@GenericGenerator(name = "id-generator", strategy = "uuid")
@GeneratedValue(generator = "id-generator")
@Column(name = "pid")
public String pid;
效果明顯,問題立馬解決。但是有的系統主鍵ID是生成好的,有自己的規則,不可以隨便uuid,比如我這個系統就是,都是在各個系統裏面已經生成好了,而且還因爲業務需要不能改。沒辦法只有另加一個字段做爲@id 雖然沒啥實際意義,但是批量寫入數據的問題得到徹底解決,你好,我好,大家好。
不過話說回來,插入前查詢一下,這個功能是可以有,在大多數的業務場景也是很有用的。springboot的jpa就這樣,在系統中,具體怎麼用,碼農們各顯神通。
也算是趟過 springboot,jpa框架的兩個坑。
在此記錄而已,無須打賞。