[Java] Spring啟動多個數據源


Answers

我幾天前面臨同樣的問題,我遵循下面提到的鏈接,我可以克服這個問題

http://www.baeldung.com/spring-data-jpa-multiple-databases

Question

我很新的春季啟動,我想為我的項目創建一個多個數據源。 這是我目前的情況。 我有兩個包為多個數據庫的實體。 我們說

com.test.entity.db.mysql ; for entities that belong to MySql
com.test.entity.db.h2 ; for entities that belong to H2 Databases

所以,目前我有兩個實體類

UserMySql.java

@Entity
@Table(name="usermysql")
public class UserMysql{

    @Id
    @GeneratedValue
    public int id;

    public String name;

}

UserH2.java

@Entity
@Table(name="userh2")
public class Userh2 {

    @Id
    @GeneratedValue
    public int id;

    public String name;
}

我想實現一個配置,如果我從UserMySql創建用戶,它將被保存到MySql數據庫,如果我從UserH2創建用戶,它將被保存到H2數據庫。 所以,我也有兩個DBConfig,比方說MySqlDbConfig和H2DbConfig。

(com.test.model是我將放置我的Repositories類的包,它將在下面定義)

MySqlDbConfig.java

@Configuration
@EnableJpaRepositories(
    basePackages="com.test.model",
    entityManagerFactoryRef = "mysqlEntityManager")
public class MySqlDBConfig {

@Bean
@Primary
@ConfigurationProperties(prefix="datasource.test.mysql")
public DataSource mysqlDataSource(){
    return DataSourceBuilder
            .create()
            .build();
}

@Bean(name="mysqlEntityManager")
public LocalContainerEntityManagerFactoryBean mySqlEntityManagerFactory(
        EntityManagerFactoryBuilder builder){       
    return builder.dataSource(mysqlDataSource())                
            .packages("com.test.entity.db.mysql")
            .build();
}   

}

H2DbConfig.java

@Configuration
@EnableJpaRepositories(
    entityManagerFactoryRef = "h2EntityManager")
public class H2DbConfig {

@Bean
@ConfigurationProperties(prefix="datasource.test.h2")
public DataSource h2DataSource(){
    return DataSourceBuilder
            .create()
            .driverClassName("org.h2.Driver")
            .build();
}

@Bean(name="h2EntityManager")
public LocalContainerEntityManagerFactoryBean h2EntityManagerFactory(
        EntityManagerFactoryBuilder builder){
    return builder.dataSource(h2DataSource())
            .packages("com.test.entity.db.h2")
            .build();
}
}

我的application.properties文件

#DataSource settings for mysql
datasource.test.mysql.jdbcUrl = jdbc:mysql://127.0.0.1:3306/test
datasource.test.mysql.username = root
datasource.test.mysql.password = root
datasource.test.mysql.driverClassName = com.mysql.jdbc.Driver

#DataSource settings for H2
datasource.test.h2.jdbcUrl = jdbc:h2:~/test
datasource.test.h2.username = sa

# DataSource settings: set here configurations for the database connection
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/test
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.validation-query=SELECT 1


# Specify the DBMS
spring.jpa.database = MYSQL

# Show or not log for each sql query
spring.jpa.show-sql = true

# Hibernate settings are prefixed with spring.jpa.hibernate.*
spring.jpa.hibernate.ddl-auto = update
spring.jpa.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.naming_strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.hibernate.show_sql = true
spring.jpa.hibernate.format_sql = true

server.port=8080
endpoints.shutdown.enabled=false

然後對於我有UserMySqlDao和UserH2Dao

UserMySqlDao.java

@Transactional 
@Repository
public interface UserMysqlDao extends CrudRepository<UserMysql, Integer>{

    public UserMysql findByName(String name);
}

UserH2Dao.java

@Transactional
@Repositories
public interface UserH2Dao extends CrudRepository<Userh2, Integer>{

    public Userh2 findByName(String name);
}

最後,我有一個UserController作為端點來訪問我的服務

UserController.java

@Controller 
@RequestMapping("/user")
public class UserController {


@Autowired
private UserMysqlDao userMysqlDao;

@Autowired
private UserH2Dao userH2Dao;

@RequestMapping("/createM")
@ResponseBody
public String createUserMySql(String name){
    UserMysql user = new UserMysql();
    try{            
        user.name = name;
        userMysqlDao.save(user);
        return "Success creating user with Id: "+user.id;
    }catch(Exception ex){
        return "Error creating the user: " + ex.toString();
    }
}

@RequestMapping("/createH")
@ResponseBody
public String createUserH2(String name){
    Userh2 user = new Userh2();
    try{
        user.name = name;
        userH2Dao.save(user);
        return "Success creating user with Id: "+user.id;
    }catch(Exception ex){
        return "Error creating the user: " + ex.toString();
    }
}   
}

Application.java

@Configuration
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
@EntityScan(basePackages="com.test.entity.db")
@ComponentScan
public class Application {

public static void main(String[] args) {
    System.out.println("Entering spring boot");
    ApplicationContext ctx = SpringApplication.run(Application.class, args);

    System.out.println("Let's inspect the beans provided by Spring Boot:");
    String[] beanNames = ctx.getBeanDefinitionNames();
    Arrays.sort(beanNames);
    for (String beanName : beanNames) {
        System.out.print(beanName);
        System.out.print(" ");
    }

    System.out.println("");
}

}

有了這個配置我的Spring引導運行良好,但是當我訪問

http://localhost/user/createM?name=myname it writes an exception

Error creating the user: org.springframework.dao.InvalidDataAccessResourceUsageException:   could not execute statement; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute statement

我一直在搜索,還沒有解決方案。 任何想法為什麼會發生這種例外 這是實現多個數據源來實現我上面的情況的最好方法嗎? 如果需要,我可以完全重構。

謝謝







使用多個數據源或實現讀寫分離。 您必須具有支持動態數據源選擇的AbstractRoutingDataSource類的知識。

這是我的datasource.yaml ,我弄清楚如何解決這種情況。 你可以參考這個項目spring-boot +石英 。 希望這會幫助你。

dbServer:
  default: localhost:3306
  read: localhost:3306
  write: localhost:3306
datasource:
  default:
    type: com.zaxxer.hikari.HikariDataSource
    pool-name: default
    continue-on-error: false
    jdbc-url: jdbc:mysql://${dbServer.default}/schedule_job?useSSL=true&verifyServerCertificate=false&useUnicode=true&characterEncoding=utf8
    username: root
    password: lh1234
    connection-timeout: 30000
    connection-test-query: SELECT 1
    maximum-pool-size: 5
    minimum-idle: 2
    idle-timeout: 600000
    destroy-method: shutdown
    auto-commit: false
  read:
    type: com.zaxxer.hikari.HikariDataSource
    pool-name: read
    continue-on-error: false
    jdbc-url: jdbc:mysql://${dbServer.read}/schedule_job?useSSL=true&verifyServerCertificate=false&useUnicode=true&characterEncoding=utf8
    username: root
    password: lh1234
    connection-timeout: 30000
    connection-test-query: SELECT 1
    maximum-pool-size: 5
    minimum-idle: 2
    idle-timeout: 600000
    destroy-method: shutdown
    auto-commit: false
  write:
    type: com.zaxxer.hikari.HikariDataSource
    pool-name: write
    continue-on-error: false
    jdbc-url: jdbc:mysql://${dbServer.write}/schedule_job?useSSL=true&verifyServerCertificate=false&useUnicode=true&characterEncoding=utf8
    username: root
    password: lh1234
    connection-timeout: 30000
    connection-test-query: SELECT 1
    maximum-pool-size: 5
    minimum-idle: 2
    idle-timeout: 600000
    destroy-method: shutdown
    auto-commit: false



感謝所有的幫助,但它似乎並不復雜, 幾乎所有的事情都由SpringBoot在內部處理。

在我的情況下, 我想使用Mysql和Mongodb ,解決方案是使用EnableMongoRepositoriesEnableJpaRepositories註釋到我的應用程序類。

@SpringBootApplication
@EnableTransactionManagement
@EnableMongoRepositories(includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository))
@EnableJpaRepositories(excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MongoRepository))
class TestApplication { ...

注意:所有的mysql實體都必須擴展JpaRepository ,mongo必須擴展MongoRepository

數據源配置與Spring文檔一樣簡單:

//mysql db config
spring.datasource.url= jdbc:mysql://localhost:3306/tangio
spring.datasource.username=test
spring.datasource.password=test

#mongodb config
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=tangio
spring.data.mongodb.username=tangio
spring.data.mongodb.password=tangio
spring.data.mongodb.repositories.enabled=true