摘要: VMware Fusion Pro 可以帮助用户在 Mac 上安装 Windows、Linux 等多种操作系统,最重要的是无需重启电脑切换系统,可以和 MacOS 系统同时运行,就类似于 MacOS 安装了一个应用。对于家庭用户来说足够简单,对于 IT 专业人员,开发人员和企业来说足够强大。 VMw 阅读全文
posted @ 2024-07-26 18:31 Charles Zhang 阅读(2544) 评论(0) 推荐(0) 编辑

介绍

JPA(Java Persistence API)Java 持久化 API,是 Java 持久化的标准规范,Hibernate 是持久化规范的技术实现,而 Spring Data JPA 是在 Hibernate 基础上封装的一款框架。
第一次使用 Spring JPA 的时候,感觉这东西简直就是神器,几乎不需要写什么关于数据库访问的代码一个基本的 CURD 的功能就出来了。在这篇文章中,我们将介绍 Spring Boot 整合 JPA 使用多个数据源的方法。
开发环境:

  • Spring Boot 2.0.5
  • Spring Data JPA 2.0.5
  • MySQL 5.6
  • JDK 8
  • IDEA 2018.3
  • Windows 10

引入依赖

首先我们要 Spring Boot 引入 spring-boot-starter-data-jpa 依赖。

Maven 配置:

   <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>

Gradle 配置:

compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '2.0.5.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.5.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-devtools', version: '2.0.5.RELEASE'
compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'

配置数据源

Spring Boot 提供了使用 application.properties 或 application.yml 文件配置项目属性的方法。我比较习惯使用 application.yml 文件,所以这里我只列出 application.yml 文件的写法。

spring:
  datasource:
    product:
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3306/product?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
      username: root
      password: test123$
    customer:
      driver-class-name: com.mysql.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3306/customer?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&autoReconnect=true&useSSL=false&zeroDateTimeBehavior=convertToNull
      username: root
      password: test123$
  jpa:
    generate-ddl: true

配置好 application.yml 文件后分别在数据库创建 customer 和 product 数据库。

添加实体(Entity)类

客户实体:

package com.springboot.jpa.customer.models;

import javax.persistence.*;

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    @Column(unique = true, nullable = false)
    private String email;
    private String firstName;
    private String lastName;

    protected Customer() {
    }

    public Customer(String email, String firstName, String lastName) {
        this.email = email;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return String.format("Customer[id=%d, firstName='%s', lastName='%s',email='%s']", id, firstName, lastName, email);
    }

    public Integer getId() {
        return id;
    }

    public String getEmail() {
        return email;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }
}

产品实体:

package com.springboot.jpa.product.models;

import javax.persistence.*;

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column(nullable = false)
    private String code;
    private String name;
    private double price;


    protected Product() {
    }

    public Product(String code, String name, double price) {
        this.code = code;
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return String.format("Product[id=%d, code='%s', name='%s', price='%s']", id, code, name, price);
    }

    public int getId() {
        return id;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

添加数据仓库(Repository)类

客户 Repository:

package com.springboot.jpa.customer.repository;

import com.springboot.jpa.customer.models.Customer;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {
}

产品 Repository:

package com.springboot.jpa.product.repository;

import com.springboot.jpa.product.models.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}

添加配置(Config)类

客户配置:

package com.springboot.jpa.customer.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "customerEntityManagerFactory", transactionManagerRef = "customerTransactionManager", basePackages = {"com.springboot.jpa.customer.repository"})
public class CustomerConfig {

    @Primary
    @Bean(name = "customerDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.customer")
    public DataSource customerDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Primary
    @Bean(name = "customerEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("customerDataSource") DataSource dataSource) {
        return builder.dataSource(dataSource).packages("com.springboot.jpa.customer.models").persistenceUnit("customer").build();
    }

    @Primary
    @Bean(name = "customerTransactionManager")
    public PlatformTransactionManager customerTransactionManager(@Qualifier("customerEntityManagerFactory") EntityManagerFactory customerEntityManagerFactory) {
        return new JpaTransactionManager(customerEntityManagerFactory);
    }
}

产品配置:

package com.springboot.jpa.product.config;


import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "productEntityManagerFactory", transactionManagerRef = "productTransactionManager", basePackages = {"com.springboot.jpa.product.repository"}
)
public class ProductConfig {

    @Bean(name = "productDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.product")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "productEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(EntityManagerFactoryBuilder builder, @Qualifier("productDataSource") DataSource dataSource) {
        return builder.dataSource(dataSource).packages("com.springboot.jpa.product.models").persistenceUnit("product").build();
    }

    @Bean(name = "productTransactionManager")
    public PlatformTransactionManager productTransactionManager(@Qualifier("productEntityManagerFactory") EntityManagerFactory productEntityManagerFactory) {
        return new JpaTransactionManager(productEntityManagerFactory);
    }
}

项目结构:

src/main/java
- com.springboot.jpa
      - product
        - config
        - models
        - repository
      - customer
        - config
        - models
        - repository

添加测试类

客户测试类 CustomerDataSourcesTests:

package com.springboot.jpa;

import com.springboot.jpa.customer.repository.CustomerRepository;
import com.springboot.jpa.customer.models.Customer;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomerDataSourcesTests {

    @Autowired
    private CustomerRepository customerRepository;

    @Test
    @Transactional("customerTransactionManager")
    public void createCustomer() {

        Customer customer = new Customer("master@weilog.net", "Charles", "Zhang");
        customer = customerRepository.save(customer);
        assertNotNull(customerRepository.findById(customer.getId()));
        assertEquals(customerRepository.findById(customer.getId()).get().getEmail(), "master@weilog.net");
    }
}

产品测试类 ProductDataSourcesTests:

package com.springboot.jpa;

import com.springboot.jpa.product.models.Product;
import com.springboot.jpa.product.repository.ProductRepository;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import org.junit.Test;

import static org.junit.Assert.assertNotNull;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProductDataSourcesTests {

    @Autowired
    private ProductRepository productRepository;

    @Test
    @Transactional("productTransactionManager")
    public void createProduct() {
        Product product = new Product("10000", "Book", 80.0);
        product = productRepository.save(product);

        assertNotNull(productRepository.findById(product.getId()));
    }

}

测试

分别运行两个测试类通过后,查询数据库。
客户表:

mysql> SELECT * FROM customer;
+----+-------------------+-----------+----------+
| id | email             | firstName | lastName |
+----+-------------------+-----------+----------+
|  1 | master@weilog.net | Charles   | Zhang    |
+----+-------------------+-----------+----------+
1 row in set

产品表:

mysql> SELECT * FROM product;
+----+-------+------+-------+
| id | code  | name | price |
+----+-------+------+-------+
|  1 | 10000 | Book |    80 |
+----+-------+------+-------+
1 row in set

本文地址:Spring Boot 整合 JPA 使用多个数据源
项目地址:spring-boot-jpa

posted @ 2019-08-08 17:45 Charles Zhang 阅读(3573) 评论(1) 推荐(1) 编辑
摘要: 公司项目中一部分文件放到了阿里云 OSS 上,其中有些音频文件是 amr 类型的,在后期使用的时候比较麻烦,所以需要转换成 mp3 的文件,方便以后使用。本来想使用 ffmpeg 处理,但由于文件都存放在阿里云 OSS 上,使用 ffmpeg 就需要把文件从远程下载下来,转码之后再重新传回阿里云上,还需要使用消息组件进行通知,而且转码对服务器的压力也会很大 阅读全文
posted @ 2019-08-06 14:42 Charles Zhang 阅读(768) 评论(0) 推荐(0) 编辑
摘要: CentOS 系统安装好 MySQL 后,默认情况下不支持用户通过非本机连接上数据库服务器,下面是解决方法 阅读全文
posted @ 2019-07-29 15:11 Charles Zhang 阅读(2644) 评论(0) 推荐(0) 编辑
摘要: Druid 是一个非常好用的数据库连接池,但是他的好并不止体现在作为一个连接池加快数据访问性能上和连接管理上,他带有一个强大的监控工具:Druid Monitor。不仅可以监控数据源和慢查询,还可以监控 Web 应用、URI 监控、Session 监控、Spring 监控 阅读全文
posted @ 2019-07-29 14:59 Charles Zhang 阅读(1571) 评论(0) 推荐(0) 编辑
摘要: 在项目开发中我们经常需要一些定时任务来处理一些特殊的任务,比如定时检查订单的状态、定时同步数据等等。在 Spring Boot 中使用 @Scheduled 注解创建定时任务非常简单,只需要两步操作就可以创建一个定时任务 阅读全文
posted @ 2019-07-26 10:06 Charles Zhang 阅读(469) 评论(0) 推荐(0) 编辑
摘要: Solr 是一种可供企业使用的、基于 Lucene 的搜索服务器,它支持层面搜索、命中醒目显示和多种输出格式。在这篇文章中,我将介绍 Solr 的部署和使用的基本操作,希望能让初次使用的朋友们少踩一些坑 阅读全文
posted @ 2019-06-21 07:31 Charles Zhang 阅读(1998) 评论(4) 推荐(1) 编辑
摘要: 适用于 Windows 的 Linux 子系统(英语:Windows Subsystem for Linux,简称 WSL)是一个为在 Windows 10 和 Windows Server 2019 上能够原生运行 Linux 二进制可执行文件(ELF 格式)的兼容层 阅读全文
posted @ 2019-05-16 10:54 Charles Zhang 阅读(23419) 评论(2) 推荐(1) 编辑
摘要: 最近几年 Electron 很火,公司也正好有个项目想做跨平台客户端,大家研究了一下就选择了 Electron,第一次做 js 的项目遇到了不少坑,不过也都一点点解决了。因为项目中需要对用户录音,HTML5 中的 API 又不支持调整麦克风音量,所以就对 Node js 操作 osx 系统麦克风、扬声器音量了解了一下 阅读全文
posted @ 2018-11-26 15:21 Charles Zhang 阅读(1625) 评论(0) 推荐(0) 编辑
摘要: 公司的一个项目需要开发跨平台,由于整个项目完全由我一个人开发,本人也是初次接触 Electron,开发过程中遇到了不少坑,同样的代码 Windows 下复制和粘贴没有问题,Mac 下复制和粘贴失效,在网上搜了一下都是菜单栏 相关的文章:https://www.jianshu.com/p/65eccd2b62f5,只好自己去 Electron Api 中找,随手一搜还真搜到了一个,不知道能否解决问题 阅读全文
posted @ 2018-11-26 15:17 Charles Zhang 阅读(2504) 评论(0) 推荐(1) 编辑
摘要: 本文介绍如何在 Ubuntu 16.04 服务器上安装 .NET Core 2.0 SDK、创建项目与发布,并使用 Nginx 部署 .NET Core 2.0 Web 项目。 阅读全文
posted @ 2017-12-21 18:18 Charles Zhang 阅读(1970) 评论(0) 推荐(1) 编辑
摘要: SSH 为 SecureShell 的缩写,由 IETF 的网络工作小组(NetworkWorkingGroup)所制定;SSH 是一种安全协议,主要用于给远程登录会话数据进行加密,保证数据传输的安全。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。 阅读全文
posted @ 2017-12-20 10:32 Charles Zhang 阅读(5257) 评论(0) 推荐(0) 编辑
摘要: 之前公司项目参考 NopCommerce 开发了一套系统,但是不支持 UnitOfWork,最近想开发新的项目,所以就基于原有的基础上又添加 UnitOfWork 支持,由于目前正在逐步完善中,所以可能存在各种问题,这里发出来仅供大家参考 阅读全文
posted @ 2017-05-16 20:16 Charles Zhang 阅读(2067) 评论(6) 推荐(1) 编辑
摘要: 最近公司做新项目,基于 Bootstrap、AngularJS 和 kendo 开发一套后台的管理系统,在项目中使用了大量的 JavaScript 文件,这两天 Visual Studio 2015 总是莫名奇妙的崩溃,崩溃之前内存使用率会一直上升,直到系统内存完全使用完,Visual Studio 的 JavaScript 代码支持会失效(没有高亮显示和格式化功能了),有的时候会提示错误信息或者 Visual Studio 自动重启。 阅读全文
posted @ 2016-03-23 17:48 Charles Zhang 阅读(1087) 评论(0) 推荐(1) 编辑
摘要: RPC,全称为 Remote Procedure Call,即远程过程调用,它是一个计算机通信协议。它允许像调用本地服务一样调用远程服务。它可以有不同的实现方式,而不需要了解底层网络技术的协议。 RPC 协议假定某些传输协议的存在,如 TCP 或 UDP,为通信程序之间携带信息数据。如 RMI(远程方法调用)、Hessian、Http invoker 等 阅读全文
posted @ 2015-11-17 20:26 Charles Zhang 阅读(479) 评论(0) 推荐(0) 编辑
摘要: 最近在研究 ASP.NET MVC 模型绑定,发现 DefaultModelBinder 有一个弊端,就是无法实现对浏览器请求参数的自定义,最初的想法是想为实体模型的属性设置特性(Attribute),然后通过取得设置的特性值对属性进行赋值,研究了好久 MVC 源码之后发现可以通过重写 DefaultModelBinder 的 BindProperty 方法可以达到预期的目的。 阅读全文
posted @ 2015-06-30 14:05 Charles Zhang 阅读(4797) 评论(7) 推荐(2) 编辑
摘要: 布隆过滤器(Bloom Filter)是非常经典的,以空间换时间的算法。布隆过滤器由布隆在 1970 年提出。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难 阅读全文
posted @ 2015-03-18 16:13 Charles Zhang 阅读(3880) 评论(0) 推荐(0) 编辑
摘要: 本文主要介绍在 CentOS 7 系统下使用 yum 安装 Redis 的过程 阅读全文
posted @ 2015-01-21 15:23 Charles Zhang 阅读(2756) 评论(3) 推荐(3) 编辑
摘要: .NET Reference Source 发布了 beta 版,可以在线浏览 .NET Framework 4.5.1 的源代码,并且可以通过配置,在 Visual Studio 2013 中调试 .NET Framework 阅读全文
posted @ 2014-09-04 15:24 Charles Zhang 阅读(5393) 评论(2) 推荐(3) 编辑
摘要: 最近公司弄新项目需要用 ASP.NET MVC,就把 IDE 升级到了 Visual Studio 2013,在开发的时候发现有好多请求一个本地49925的端口 。很奇怪,一开始以为是 Visual Studio 2013 在创建项目的时候默认加进去的 JavaScript 文件或者是视图文件导致的,找了半天也没找到,经过在 FireBug 下查看代码发现 阅读全文
posted @ 2014-08-19 09:54 Charles Zhang 阅读(10445) 评论(10) 推荐(5) 编辑
点击右上角即可分享
微信分享提示