Java數據類型在JPA中是如何映射到Mysql數據庫(ex:5.7)

前兩天有位學弟問我問題,說他在使用JPA的過程當中遇到一個java類型和mysql類型映射問題,而且在使用TimeStamp 的時候出了錯。咱們這裏從源碼角度宏觀看一下是如何映射的,這裏jpa實現是 hibernatejava

start

這裏只分享一些重點的,其餘的非重點的跳過mysql

當咱們在jpa中save一個對象的時候,程序毋庸置疑先拿到一個數據庫鏈接,而後把sql語句懟過去。這sql語句是很好實現的,無非就是先判斷主鍵有沒有值,若是有值,就先select一下主鍵的值看是否有數據行,若是有,接下來就是update操做,沒有就是insert操做。若是主鍵爲空,就直接insert了。程序很容易實現後面的insert和update操做的預編譯模板化代碼生成,這裏模板化代碼就像這種 insert into tt (time1, time2, time3, time4) values (?, ?, ?, ?),有了模板化sql,接下來就是重點的綁定數據了,如何把java裏的對象轉成sql語句裏的值。有人說直接序列化?對於各類複雜的類型和註解映射,jpa怎麼處理的呢。sql

跳過一堆代理的代碼,咱們看重點數據庫

這裏咱們直接看首次執行的過程,由於我也是在測試用例裏執行,因此一切都得初始化。安全

這裏的作法是獲取實體對象的映射相關描述的實體用於持久化的,這裏先獲取工廠對象獲取到元模型,而後再獲取持久化描述對象多線程

獲取到持久化描述對象,而後進行save操做,併發

這裏展現一下 持久化描述對象的字段高併發

其實這個對象字段很是多,還有不少沒顯示,你們能夠自行參看 EntityPersister 接口,很明顯這個對象記錄了整個映射的信息,包括字段上的註解信息,有了它咱們就能夠進行映射。測試

這裏對每一個字段進行映射hibernate

debug的時候會發現,後面的對象都是泛型的

最終調用doBind,不一樣類型,使用不一樣的對象,咱們這裏debug的時候遇到的是TimeStamp類型對應的對象

好比

AbstractSingleColumnStandardBasicType<T> 實現類是 TimeStampType

BasicBinder<J> 實現類是TimeStampTypeDescriptor

這裏是對 TimeStampTypeDescriptor 對象的獲取 和 調用該對象的bind操做


意外發現!!!!!

單例模式


接下來就是重點的清晰的 類型轉換操做啦

到了這裏調用的就不是jpa的邏輯了

PreparedStatement 類是 import java.sql.PreparedStatement下的 ,到這時候 有可能就有小夥伴問了,爲何調來調去仍是調用了java的基礎包???

難道仍是基礎包作的轉換???

其實這裏的答案很簡單,確實調了基礎包,可是!調的是基礎包的接口,他的實如今哪呢,這就是傳說中的JDBC,這裏我使用的是mysql,因此調用的就是com.mysql.cj.jdbc下的 ClientPreparedStatement

這就是轉換代碼,由jdbc實現,因此這就是驅動爲何那麼重要,不一樣數據庫不一樣實現

這裏代碼就很簡單了,不過有沒有發現 轉換隻是把時間戳轉換爲了yyyy-MM-dd HH:mm:ss形式 插入到數據庫的,其實這裏就是mysql timestamp存儲的奧祕,你們能夠自行百度一下了解一下。

這裏使用了一個類讓我困惑,每一個學java的都應該會據說過 SimpleDateFormat這個類有高併發下多線程安全問題,那爲何,MySQL jdbc這麼大膽呢?

線程安全解決

這裏互斥變量就是 JdbcConnection

當獲取不到鏈接的時候,線程互斥會報出 Statement.AlreadyClosed

至於後面那個 getConnectionMutex()調用,這裏說出我我的猜測,找資料沒找到,看了debug內容,猜測是

同一個ClientPreparedQueryBindings 每次只能對應一個JdbcConnection對象,因此只有共用同一個JdbcConnection對象時纔會出現線程安全問題,因此這裏互斥變量爲 JdbcConnection,我的看法,你們當心點看

以上純屬我的理解,你們審視着看

相關文章
相關標籤/搜索