SpringBootで実装したSpring Data JPA連携例を詳しく解説

Y2J
リリース: 2017-05-04 10:39:59
オリジナル
2981 人が閲覧しました

この記事では、Spring Data JPAの統合と読み書きの分離に関するSpringBootの関連知識を主に紹介しますので、必要な方は参考にしてください

関連コード: github OSCchina

JPAとは

JPA (Java Persistence ) API ) は、Sun によって正式に提案された Java 永続化仕様です。これは、Java アプリケーションでリレーショナル データを管理するための オブジェクト/関連付けマッピング ツールを提供します。

1.ORM マッピングは xml をサポートします。

2. Java 永続性 API は、基盤となる JDBC と SQL の詳細を考慮せずに直接呼び出すだけで済む、いくつかの一般的に使用される CRUD インターフェイスを定義します。

3.JPQL

Query 言語 これは永続化操作において非常に重要な側面であり、プログラムの SQL ステートメントの密結合を避けるために、データはデータベース指向のクエリ言語ではなく オブジェクト指向 を介してクエリされます。

仕事では皆 ORM を使用します。 Hibernate、JOOQ などのテクノロジーを使用します。異なる ORM フレームワークの実装のため、ニーズに合わせて ORM フレームワークを変更する必要がある場合は、異なる ORM

フレームワーク を使用します。使用時にそれぞれが独立して動作するため、多くの場合コードを再構築する必要があります。JPA の登場により、既存の ORM フレームワークの利点が完全に吸収され、使いやすさと強力なスケーラビリティが実現します。さまざまな ORM フレームワークを統合するための標準インターフェイスのセットです。

Hibernate の JPA 実装

JPA 自体は特定の実装を実装していませんが、現時点では、

他の ORM がこれらのインターフェイスを具体的に実装できるようにするだけです。 JPA 仕様の最良の実装は Hibernate です。ここで Mybatis について触れておきますが、Mybatis は JPA 仕様を実装しておらず、それ自体は実際の ORM フレームワークとは見なされません。 Data JPA は Spring Data フレームワークの単なるモジュールであり、JPA の使用を大幅に簡素化できます。Spring Data JPA の利点は、永続層のメソッドと名前を標準化することにより、永続層のビジネス ロジックの開発を簡素化できることです。名前を使用して、どのビジネス ロジックを実装する必要があるかを決定することで、SQL 文を記述したり、DAO レイヤー ロジックを実行したりせずに、開発のほとんどを完了することができます。もちろん、高パフォーマンスが必要な一部の複雑な For クエリについては、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 要するに前です。操作を実行するには、Hibernate の Session や mybatis の sqlSession と同様に、EntityManager を取得する必要があります。EntityManagerFactory を注入するには 2 つの方法があります。1 つは EntityManagerFactory を直接注入する方法、もう 1 つは LocalContainerEntityManagerFactoryBean を介して間接的に注入する方法です。 LocalContainerEntityManagerFactoryBean に基づいていますが、設定にはまだいくつかの違いがあります。

1. EntityManagerFactory を直接挿入します

設定: spring.jpa.properties を通じて Hibernate を設定します。* Attributes

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. ContainerEntityManagerFactoryBean、および次に、EntityManagerFactory を取得します

Configuration:

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() を直接使用することはできません。取得できず、null ポインター例外を報告します

読み取り/書き込み分離構成

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 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート