Hibernate | Spring JPA | MySQL 使用過程遇到的一些問題


1. 使用過程

  在項目中我使用Spring Boot 2.0.0.RELEASE開發並且集成了Spring JPA;我這里將Hibernate版本設置為5.1.2.Final,這里做修改主要是因為LocalDate跟數據庫映射時有些問題才做更換,其他基本沒什么大的問題;數據庫使用了MySQL
  

2. 背景

  使用MySQL,所以先對MySQL做一些了解,這里MySQL數據庫中有四種存儲引擎,主要介紹兩種,分別為MyISAMInnoDB,它們兩個的區別如下:

InnoDB MyISAM
訪問速度 相對慢
事務 支持 不支持
外鍵 支持 不支持
應用場景 需要事務提交、回滾功能應用 以查詢為主的應用

各種引擎簡要介紹
https://blog.csdn.net/qq_27028821/article/details/52267991

3. 遇到問題

3.1 不指定Hibernate數據庫方言,默認SQL生成方式

在不指定方言的情況下默認使用了MySQL5Dialect,這樣在打印create table命令時會在后面指定它的數據庫引擎為MyISAM,這樣生成的數據庫是不支持外鍵的,也是不支持事務性操作的。請注意是數據庫。

3.2 拋出異常Hibernate加入了@Transactional事務不會回滾

現在這里有個實體類:

@Entity
@Data
public class Test{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    private String name;
    
}

我們保存需要保存一個Test實例時發現拋出了一個異常數據庫居然保存成功,代碼如下:

Service:

    @Resource
    private TestDao testDao;

    @Transactional
    public void test(){
        Test test = new Test();
        test.setName("test");
        testDao.save(test);
        int a = 1 / 0;
    }

這里我們要看回去MySQL生成的方式,默認是使用了MyISAM這是不支持事務的,如果向數據庫保存了數據,那么事務回滾也是不管用的,所以,現在我們需要指定配置數據庫的方言,在Spring Boot中可在application.properties配置如下:

spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

如果是xml配置的可以這么配置

<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>

這樣我們重新運行生成的表可以有外鍵生成也可以支持數據庫事務,當然數據就可以回滾了
當然了,除了以上的解決方法之外,其實還有一個不怎么好的解決方法,那就是將Test中的id生成策略注解改為如下內容:

@Entity
@Data
public class Test{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    
    private String name;
    
}

對於這個為什么可以,請接着往下面看

主鍵生成策略參考
https://blog.csdn.net/lwt976647637/article/details/53352369

3.3 Hibernate使用Spring Test測試加入了@Transactional事務無論如何數據庫插入不成功

  這里使用上面修改成AUTO的實體類

  在測試類里面我們可以保存我們一個Test對象,測試代碼如下:

junit.Test

    @Test
    @Transactional
    public void test(){
        Test test = new Test();
        test.setName("test");
        testDao.save(test);
    }

上面沒有任何異常拋出,進度條也綠了,但是數據插入數據庫不成功,這時,可以看下控制台打印輸出的語句:

//....前面有很多,不寫出來了
transaction manager [org.springframework.orm.jpa.JpaTransactionManager@5e5ddfbc]; rollback [true]

這里我大膽的猜測就是Spring Test自動幫我們把事務回滾了,我們如果要看到把數據插入數據庫的話只是需要在test方法加入注解,如

    @Test
    @Transactional
    @Rollback(false) //設置事務不自動回滾
    public void test(){
        Test test = new Test();
        test.setName("test");
        testDao.save(test);
    }

3.4 Hibernate在使用MyISAM引擎也可以回滾?

  我在之前寫的會員管理系統中是沒有指定生成方言的,默認是使用了MyISAM,但是在Service中出現了異常還是可以回滾,怎么回事?
  這是因為我們在save之后Hibernate不會立馬執行SQL的,除非是事務提交了,我在事務提交之前拋出了異常,所以在Hibernate的緩存中的SQL是不會執行成功的,因此就用假的回滾現象,這不是數據庫提供的回滾功能。
  

3.5 Hibernate在使用生成策略是IDENTITY不能回滾事務,AUTO可以

  
  這是因為如果使用了IDENTITY是數據庫維護我們的主鍵,Hibernate為了獲取id是需要向數據庫插入數據才能獲得id的值的,所以會執行SQL,在使用MyISAM引擎的情況下是不能回滾事務的
  如果用了AUTO那么不需要數據庫維護,Hibernate自己維護是不需要向數據庫要主鍵的,那么不會立馬執行SQL就跟上一個問題一樣的結果。所以這里的生成策略使用uuid也是可以的,只要不是數據庫維護。
  
  

3.6 使用MyISAM引擎下有緩存的情況@Controller下使用事務回滾不成功,@Service下成功

  在Controller層使用@Transactional事務是不會回滾的,但是Service層就可以,如果把@Controller替換成@Component也是成功的。

4. 總結

   這里遇到大部分問題終其原因都是MySQL引擎使用或是沒有指定方言的原因吧,所以,沒有性能方面的要求或者是小白請使用InnoDB引擎。
   而對於我來說,這些異常手動catch算是學到了些東西,但是會遇到問題說明自己還是沒有了解它,不說了,好好學習。


免責聲明!

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



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