首頁 Java java教程 SpringBoot實作Spring Data JPA整合的實例詳解

SpringBoot實作Spring Data JPA整合的實例詳解

May 04, 2017 am 10:39 AM
boot data jpa spring 讀寫分離

這篇文章主要介紹了SpringBoot整合Spring Data JPA及讀寫分離的相關知識,需要的朋友可以參考下

相關程式碼: github OSCchina

#JPA是什麼

JPA(Java Persistence API#)是Sun官方提出的Java持久化規範,它為Java開發人員提供了一種物件/關聯映射工具來管理Java應用中的關聯式資料.它包括以下幾個方面的內容:

#1.ORM映射支援xml和註解方式建立實體與表之間的映射.

2.Java持久化API 定義了一些常用的CRUD介面,我們只需直接呼叫,而不需要考慮底層JDBC和SQL的細節.

3.JPQL查詢語言這是持久化操作中很重要的一個方面,透過物件導向而非面向資料庫的查詢語言查詢數據,避免程式的SQL語句緊密耦合.

在工作中,我們都會用到ORM技術,比如Hibernate,JOOQ等,根據需求的不同,我們會採用不同的ORM框架,當我們需要更換ORM框架來滿足我們的需求時,由於不同ORM框架的實現,使用方式的區別以及各自為營,我們往往需要對代碼進行重構.JPA的出現就是為了解決這個問題,JPA充分吸收了現有一些ORM框架的優點,具有易於使用,伸縮性強等優點,為ORM技術提供了一套標準的接口用來整合不同的ORM框架.

Hibernate對JPA的實現

JPA本身並不做具體的實現,而只是定義了一些接口規範,讓其它ORM來具體的實現這些接口,就目前來說,對JPA規範實現最好的就是Hibernate了.這裡提一下Mybatis,Mybatis並沒有實現JPA規範,它本身也不能算做一個真正的ORM框架.

##Spring Data JPA是什麼

Spring Data JPA只是Spring Data框架的一個模組,可以極大的簡化JPA的使用,Spring Data JPA強大的地方還在於能夠簡化我們對持久層業務邏輯的開發,透過規範持久層方法的名稱,透過名稱來判斷需要實現什麼業務邏輯,我們機會可以在不寫一句sql,不做任何dao層邏輯的情況下完成我們絕大部分的開發,當然,對於一些複雜的,性能要求高的查詢,Spring Data JPA一樣支持我們使用原生的sql.

在這裡我們不過多的去介紹JPA以及Spring Data JPA,主要還是與SpringBoot集成的一些細節以及範例.

引入依賴

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
登入後複製

我們引入這個依賴後,發現也引入了Hibernate的套件,這是現在一種預設的做法,Hibernate已經被作為JPA規範的最好實現了,這裡就不介紹Druid資料來源的配置了,大家可以看另外一篇XXXX.

配置我們的資料來源以及JPA(Hibernate)

#配置模板
#https://docs.spring.io/spring-boot/docs/1.4.0.RELEASE/reference/html/common-application-properties.html
#数据源
spring.datasource.druid.write.url=jdbc:mysql://localhost:3306/jpa
spring.datasource.druid.write.username=root
spring.datasource.druid.write.password=1
spring.datasource.druid.write.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.read.url=jdbc:mysql://localhost:3306/jpa
spring.datasource.druid.read.username=root
spring.datasource.druid.read.password=1
spring.datasource.druid.read.driver-class-name=com.mysql.jdbc.Driver
#JPA (JpaBaseConfiguration, HibernateJpaAutoConfiguration)
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.database=mysql
spring.jpa.generate-ddl=true
#就是hibernate.hbm2ddl.auto,具体说明可以看README
spring.jpa.hibernate.ddl-auto=update
#通过方法名解析sql的策略,具体说明可以看README,这里就不配置了
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultComponentSafeNamingStrategy
spring.jpa.show-sql=true
#spring.jpa.properties.*
#spring.jpa.properties.hibernate.hbm2ddl.auto=update
#spring.jpa.properties.hibernate.show_sql=true
#spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
登入後複製

druid資料來源注入

@Configuration
public class DruidDataSourceConfig {
  /**
   * DataSource 配置
   * @return
   */
  @ConfigurationProperties(prefix = "spring.datasource.druid.read")
  @Bean(name = "readDruidDataSource")
  public DataSource readDruidDataSource() {
    return new DruidDataSource();
  }
  /**
   * DataSource 配置
   * @return
   */
  @ConfigurationProperties(prefix = "spring.datasource.druid.write")
  @Bean(name = "writeDruidDataSource")
  @Primary
  public DataSource writeDruidDataSource() {
    return new DruidDataSource();
  }
}
登入後複製

EntityManagerFactory實例注入

EntityManagerFactory類似Hibernate的SessionFactory,mybatis的SqlSessionFactory 總之,在執行操作之前,我們總是要取得一個EntityManager,這就類似Hibernate的Session, mybatis的sqlSession. 注入一個EntityFactoryy,一種是直接注入EntityFactorManagery,EntityManagerFactory有兩種方式另一種是透過LocalContainerEntityManagerFactoryBean來間接注入.雖然說這兩種方法都是基於LocalContainerEntityManagerFactoryBean的,但是在配置上還是有一些區別.

1.直接注入EntityManagerFactory

設定:透過spring.jpa.properties.*來設定Hibernate的

屬性#

spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.use-new-id-generator-mappings=true
@Configuration
@EnableJpaRepositories(value = "com.lc.springBoot.jpa.repository",
            entityManagerFactoryRef = "writeEntityManagerFactory",
            transactionManagerRef="writeTransactionManager")
public class WriteDataSourceConfig {
  @Autowired
  JpaProperties jpaProperties;
  @Autowired
  @Qualifier("writeDruidDataSource")
  private DataSource writeDruidDataSource;
  /**
   * EntityManagerFactory类似于Hibernate的SessionFactory,mybatis的SqlSessionFactory
   * 总之,在执行操作之前,我们总要获取一个EntityManager,这就类似于Hibernate的Session,
   * mybatis的sqlSession.
   * @return
   */
  @Bean(name = "writeEntityManagerFactory")
  @Primary
  public EntityManagerFactory writeEntityManagerFactory() {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.lc.springBoot.jpa.entity");
    factory.setDataSource(writeDruidDataSource);//数据源
    factory.setJpaPropertyMap(jpaProperties.getProperties());
    factory.afterPropertiesSet();//在完成了其它所有相关的配置加载以及属性设置后,才初始化
    return factory.getObject();
  }
  /**
   * 配置事物管理器
   * @return
   */
  @Bean(name = "writeTransactionManager")
  @Primary
  public PlatformTransactionManager writeTransactionManager() {
    JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
    jpaTransactionManager.setEntityManagerFactory(this.writeEntityManagerFactory());
    return jpaTransactionManager;
  }
}
登入後複製

2.先註入LocalContainerEntityManagerFactoryBean,再取得EntityManagerFactory

配置:

spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.database=mysql
spring.jpa.generate-ddl=true
#就是hibernate.hbm2ddl.auto,具体说明可以看README
spring.jpa.hibernate.ddl-auto=update
#通过方法名解析sql的策略,具体说明可以看README,这里就不配置了
spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultComponentSafeNamingStrategy
spring.jpa.show-sql=true
@Configuration
@EnableJpaRepositories(value = "com.lc.springBoot.jpa.repository",
    entityManagerFactoryRef = "writeEntityManagerFactory",
    transactionManagerRef = "writeTransactionManager")
public class WriteDataSourceConfig1 {
  @Autowired
  JpaProperties jpaProperties;
  @Autowired
  @Qualifier("writeDruidDataSource")
  private DataSource writeDruidDataSource;
  /**
   * 我们通过LocalContainerEntityManagerFactoryBean来获取EntityManagerFactory实例
   * @return
   */
  @Bean(name = "writeEntityManagerFactoryBean")
  @Primary
  public LocalContainerEntityManagerFactoryBean writeEntityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
    return builder
        .dataSource(writeDruidDataSource)
        .properties(jpaProperties.getProperties())
        .packages("com.lc.springBoot.jpa.entity") //设置实体类所在位置
        .persistenceUnit("writePersistenceUnit")
        .build();
    //.getObject();//不要在这里直接获取EntityManagerFactory
  }
  /**
   * EntityManagerFactory类似于Hibernate的SessionFactory,mybatis的SqlSessionFactory
   * 总之,在执行操作之前,我们总要获取一个EntityManager,这就类似于Hibernate的Session,
   * mybatis的sqlSession.
   * @param builder
   * @return
   */
  @Bean(name = "writeEntityManagerFactory")
  @Primary
  public EntityManagerFactory writeEntityManagerFactory(EntityManagerFactoryBuilder builder) {
    return this.writeEntityManagerFactoryBean(builder).getObject();
  }
  /**
   * 配置事物管理器
   * @return
   */
  @Bean(name = "writeTransactionManager")
  @Primary
  public PlatformTransactionManager writeTransactionManager(EntityManagerFactoryBuilder builder) {
    return new JpaTransactionManager(writeEntityManagerFactory(builder));
  }
}
登入後複製

對於這個配置

@Bean(name = "writeEntityManagerFactoryBean")
  @Primary
  public LocalContainerEntityManagerFactoryBean writeEntityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
    return builder
        .dataSource(writeDruidDataSource)
        .properties(jpaProperties.getProperties())
        .packages("com.lc.springBoot.jpa.entity") //设置实体类所在位置
        .persistenceUnit("writePersistenceUnit")
        .build();
    //.getObject();//不要在这里直接获取EntityManagerFactory
  }
登入後複製

getObject()方法可以取得到EntityManagerFactory的實例,看似跟第一種沒有什麼差別,但是我們不能直接用getObject() ,不然會取得不到,報空指標異常.

讀寫分離配置

自訂注入AbstractRoutingDataSource

@Configuration
public class DataSourceConfig {
  private final static String WRITE_DATASOURCE_KEY = "writeDruidDataSource";
  private final static String READ_DATASOURCE_KEY = "readDruidDataSource";
  /**
   * 注入AbstractRoutingDataSource
   * @param readDruidDataSource
   * @param writeDruidDataSource
   * @return
   * @throws Exception
   */
  @Bean
  public AbstractRoutingDataSource routingDataSource(
      @Qualifier(READ_DATASOURCE_KEY) DataSource readDruidDataSource,
      @Qualifier(WRITE_DATASOURCE_KEY) DataSource writeDruidDataSource
  ) throws Exception {
    DynamicDataSource dataSource = new DynamicDataSource();
    Map<Object, Object> targetDataSources = new HashMap();
    targetDataSources.put(WRITE_DATASOURCE_KEY, writeDruidDataSource);
    targetDataSources.put(READ_DATASOURCE_KEY, readDruidDataSource);
    dataSource.setTargetDataSources(targetDataSources);
    dataSource.setDefaultTargetDataSource(writeDruidDataSource);
    return dataSource;
  }
}
登入後複製

自訂註解

  @Target({ElementType.METHOD, ElementType.TYPE})
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  public @interface TargetDataSource {
    String dataSource() default "";//数据源
  }
登入後複製

使用ThreadLocal使資料來源與執行緒綁定

 public class DynamicDataSourceHolder {
    //使用ThreadLocal把数据源与当前线程绑定
    private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();
    public static void setDataSource(String dataSourceName) {
      dataSources.set(dataSourceName);
    }
    public static String getDataSource() {
      return (String) dataSources.get();
    }
    public static void clearDataSource() {
      dataSources.remove();
    }
  }
  public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
      //可以做一个简单的负载均衡策略
      String lookupKey = DynamicDataSourceHolder.getDataSource();
      System.out.println("------------lookupKey---------"+lookupKey);
      return lookupKey;
    }
  }
登入後複製

定義切面

@Aspect
  @Component
  public class DynamicDataSourceAspect {
    @Around("execution(public * com.lc.springBoot.jpa.service..*.*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
      MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
      Method targetMethod = methodSignature.getMethod();
      if (targetMethod.isAnnotationPresent(TargetDataSource.class)) {
        String targetDataSource = targetMethod.getAnnotation(TargetDataSource.class).dataSource();
        System.out.println("----------数据源是:" + targetDataSource + "------");
        DynamicDataSourceHolder.setDataSource(targetDataSource);
      }
      Object result = pjp.proceed();//执行方法
      DynamicDataSourceHolder.clearDataSource();
      return result;
    }
  }
登入後複製

以上是SpringBoot實作Spring Data JPA整合的實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
1 個月前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

Windows ISO檔太大BootCamp錯誤[修復] Windows ISO檔太大BootCamp錯誤[修復] Feb 19, 2024 pm 12:30 PM

如果在Mac電腦上使用BootCampAssistant時出現"TheWindowsISO檔案太大"的錯誤訊息,這可能是由於ISO檔案大小超過BootCampAssistant所支援的限制。解決這個問題的方法是使用其他工具來壓縮ISO檔案大小,以確保其在BootCampAssistant中能夠被處理。 BootCampAssistant是蘋果提供的一種方便的工具,用於在Mac電腦上安裝並運行Windows作業系統。它可以幫助使用者設定雙重開機系統,讓他們可以輕鬆地在啟動時選擇使用MacOS還是Wind

編程新範式,當Spring Boot遇上OpenAI 編程新範式,當Spring Boot遇上OpenAI Feb 01, 2024 pm 09:18 PM

2023年,AI技術已成為熱門話題,對各行業產生了巨大影響,程式設計領域尤其如此。人們越來越認識到AI技術的重要性,Spring社群也不例外。隨著GenAI(GeneralArtificialIntelligence)技術的不斷進步,簡化具備AI功能的應用程式的創建變得至關重要和迫切。在這個背景下,"SpringAI"應運而生,旨在簡化開發AI功能應用程式的過程,使其變得簡單直觀,避免不必要的複雜性。透過"SpringAI",開發者可以更輕鬆地建立具備AI功能的應用程序,將其變得更加易於使用和操作

jpa和mybatis哪個好 jpa和mybatis哪個好 Jan 15, 2024 pm 01:48 PM

選擇JPA還是MyBatis取決於具體需求和偏好。 JPA和MyBatis都是Java持久層框架,都提供了將Java物件與資料庫表進行對應的功能。如果需要一個成熟的、支援跨資料庫操作的框架,或者專案已經採用了JPA作為持久層解決方案,繼續使用JPA可能是一個更好的選擇。如果要更高的效能和更靈活的SQL編寫能力,或者正在尋找一個對資料庫依賴性較小的解決方案,MyBatis更適合。

利用Spring Boot以及Spring AI建構生成式人工智慧應用 利用Spring Boot以及Spring AI建構生成式人工智慧應用 Apr 28, 2024 am 11:46 AM

Spring+AI作為行業領導者,透過其強大、靈活的API和先進的功能,為各種行業提供了領先性的解決方案。在本專題中,我們將深入探討Spring+AI在各領域的應用範例,每個案例都將展示Spring+AI如何滿足特定需求,實現目標,並將這些LESSONSLEARNED擴展到更廣泛的應用。希望這個專題能對你有所啟發,更深入地理解和利用Spring+AI的無限可能。 Spring框架在軟體開發領域已經有超過20年的歷史,自SpringBoot1.0版本發布以來已有10年。現在,無人會質疑,Spring

spring編程式事務有哪些實作方式 spring編程式事務有哪些實作方式 Jan 08, 2024 am 10:23 AM

spring編程式事務的實作方式:1、使用TransactionTemplate;2、使用TransactionCallback和TransactionCallbackWithoutResult;3、使用Transactional註解;4、使用TransactionTemplate和@Transactional結合使用;5、自訂事務管理器。

比較分析JPA和MyBatis的功能和性能 比較分析JPA和MyBatis的功能和性能 Feb 19, 2024 pm 05:43 PM

JPA和MyBatis:功能與效能比較分析引言:在Java開發中,持久化框架扮演著非常重要的角色。常見的持久化框架包括JPA(JavaPersistenceAPI)和MyBatis。本文將對這兩個框架的功能和效能進行比較分析,並提供具體的程式碼範例。一、功能對比:JPA:JPA是JavaEE的一部分,提供了一個物件導向的資料持久化解決方案。它透過註解或X

Spring如何設定事務隔離級別 Spring如何設定事務隔離級別 Jan 26, 2024 pm 05:38 PM

Spring設定事務隔離等級的方法:1、使用@Transactional註解;2、在Spring設定檔中設定;3、使用PlatformTransactionManager;4、在Java配置類別中設定。詳細介紹:1、使用@Transactional註解,在需要進行事務管理的類別或方法上加入@Transactional註解,並在屬性中設定隔離等級;2、在Spring設定檔等等。

Java JPA 開源專案推薦:為你的專案注入新的活力 Java JPA 開源專案推薦:為你的專案注入新的活力 Feb 20, 2024 am 09:09 AM

在Java程式設計領域,JPA(JavaPersistenceapi)作為一種流行的持久化框架,為開發者提供了對關係型資料庫進行操作的便捷方式。透過使用JPA,開發者可以輕鬆地將Java物件持久化到資料庫中,並從資料庫中檢索數據,從而大大提高了應用程式的開發效率和維護性。本文精心挑選了10個高品質的JavaJPA開源項目,涵蓋了各種不同的功能和應用場景,旨在為開發者提供更多的靈感和解決方案,協助打造更有效率和可靠的應用程式。這些項目包括:SpringDataJPA:springDataJPA是Spr

See all articles