Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Spring为2个数据库使用2个数据源_Java_Spring_Jpa_Datasource_Entitymanager - Fatal编程技术网

Java 使用Spring为2个数据库使用2个数据源

Java 使用Spring为2个数据库使用2个数据源,java,spring,jpa,datasource,entitymanager,Java,Spring,Jpa,Datasource,Entitymanager,我一直试图在Spring中解决使用2个具有相同模式的DBs的问题,但没有成功。我试图解决的问题是为一家位于两个不同城市的餐厅创建一个网页,因此我认为为每个城市使用一个单独的数据库将是最好的解决方案 我只从一个数据库中获取结果,另一个由于某种原因未使用。数据库被称为城市的BA和KE,我使用的是具有相同值的城市枚举 BAConfig.java @Configuration @PropertySources( {@PropertySource("classpath:jpa.properties

我一直试图在Spring中解决使用2个具有相同模式的DBs的问题,但没有成功。我试图解决的问题是为一家位于两个不同城市的餐厅创建一个网页,因此我认为为每个城市使用一个单独的数据库将是最好的解决方案

我只从一个数据库中获取结果,另一个由于某种原因未使用。数据库被称为城市的BA和KE,我使用的是具有相同值的城市枚举

BAConfig.java

@Configuration
@PropertySources(
    {@PropertySource("classpath:jpa.properties"),
            @PropertySource("classpath:jdbc.properties")})
@EnableTransactionManagement    // Enable use of the @Transactional annotation
@ComponentScan(basePackages = "dao")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class BAConfig {

@Autowired
private Environment environment;

@Bean(name="dataSourceBA")
public DataSource buildDataSource()
{
    HikariConfig hkcfg = new HikariConfig();
    hkcfg.setJdbcUrl(environment.getRequiredProperty("jdbc.urlBA"));
    hkcfg.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    hkcfg.setUsername(environment.getRequiredProperty("jdbc.username"));
    hkcfg.setPassword(environment.getRequiredProperty("jdbc.password"));
    HikariDataSource ds = new HikariDataSource(hkcfg);
    return ds;
}

public static LocalContainerEntityManagerFactoryBean entityManagerFactoryBuilder(DataSource ds)
{
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setDataSource(ds);
    emf.setJpaVendorAdapter(new EclipseLinkJpaVendorAdapter());
    emf.setPackagesToScan("model"); // Look for entities in this package

    Properties props = new Properties();
    props.setProperty("databasePlatform", "org.eclipse.persistence.platform.database.PostgreSQLPlatform");
    props.setProperty("generateDdl", "true");
    props.setProperty("showSql", "true");
    props.setProperty("eclipselink.weaving", "false");
    props.setProperty("eclipselink.ddl-generation", "create-tables");
    emf.setJpaProperties(props);
    return emf;
}

@Bean(name="BAEM")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSourceBA") DataSource ds) {
    return entityManagerFactoryBuilder(ds);
}


@Bean(name = "txManagerBA")
JpaTransactionManager transactionManager(@Qualifier("BAEM") EntityManagerFactory em) {
    JpaTransactionManager transactionManager = new JpaTransactionManager(em);
    return transactionManager;
}
}
@Configuration
@PropertySources(
    {@PropertySource("classpath:jpa.properties"),
            @PropertySource("classpath:jdbc.properties")})
@EnableTransactionManagement    // Enable use of the @Transactional annotation
@ComponentScan(basePackages = "dao")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class KEConfig {

@Autowired
private Environment environment;

@Bean("dataSourceKE")
public DataSource buildDataSource()
{
    HikariConfig hkcfg = new HikariConfig();
    hkcfg.setJdbcUrl(environment.getRequiredProperty("jdbc.urlKE"));
    hkcfg.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    hkcfg.setUsername(environment.getRequiredProperty("jdbc.username"));
    hkcfg.setPassword(environment.getRequiredProperty("jdbc.password"));
    HikariDataSource ds = new HikariDataSource(hkcfg);
    return ds;
}

@Bean(name="KEEM")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSourceKE")DataSource ds) {
    return BAConfig.entityManagerFactoryBuilder(ds);
}


@Bean(name = "txManagerKE")
JpaTransactionManager transactionManager(@Qualifier("KEEM") EntityManagerFactory em) {
    JpaTransactionManager transactionManager = new JpaTransactionManager(em);
    return transactionManager;
}
}
KEConfig.java

@Configuration
@PropertySources(
    {@PropertySource("classpath:jpa.properties"),
            @PropertySource("classpath:jdbc.properties")})
@EnableTransactionManagement    // Enable use of the @Transactional annotation
@ComponentScan(basePackages = "dao")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class BAConfig {

@Autowired
private Environment environment;

@Bean(name="dataSourceBA")
public DataSource buildDataSource()
{
    HikariConfig hkcfg = new HikariConfig();
    hkcfg.setJdbcUrl(environment.getRequiredProperty("jdbc.urlBA"));
    hkcfg.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    hkcfg.setUsername(environment.getRequiredProperty("jdbc.username"));
    hkcfg.setPassword(environment.getRequiredProperty("jdbc.password"));
    HikariDataSource ds = new HikariDataSource(hkcfg);
    return ds;
}

public static LocalContainerEntityManagerFactoryBean entityManagerFactoryBuilder(DataSource ds)
{
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setDataSource(ds);
    emf.setJpaVendorAdapter(new EclipseLinkJpaVendorAdapter());
    emf.setPackagesToScan("model"); // Look for entities in this package

    Properties props = new Properties();
    props.setProperty("databasePlatform", "org.eclipse.persistence.platform.database.PostgreSQLPlatform");
    props.setProperty("generateDdl", "true");
    props.setProperty("showSql", "true");
    props.setProperty("eclipselink.weaving", "false");
    props.setProperty("eclipselink.ddl-generation", "create-tables");
    emf.setJpaProperties(props);
    return emf;
}

@Bean(name="BAEM")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSourceBA") DataSource ds) {
    return entityManagerFactoryBuilder(ds);
}


@Bean(name = "txManagerBA")
JpaTransactionManager transactionManager(@Qualifier("BAEM") EntityManagerFactory em) {
    JpaTransactionManager transactionManager = new JpaTransactionManager(em);
    return transactionManager;
}
}
@Configuration
@PropertySources(
    {@PropertySource("classpath:jpa.properties"),
            @PropertySource("classpath:jdbc.properties")})
@EnableTransactionManagement    // Enable use of the @Transactional annotation
@ComponentScan(basePackages = "dao")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class KEConfig {

@Autowired
private Environment environment;

@Bean("dataSourceKE")
public DataSource buildDataSource()
{
    HikariConfig hkcfg = new HikariConfig();
    hkcfg.setJdbcUrl(environment.getRequiredProperty("jdbc.urlKE"));
    hkcfg.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
    hkcfg.setUsername(environment.getRequiredProperty("jdbc.username"));
    hkcfg.setPassword(environment.getRequiredProperty("jdbc.password"));
    HikariDataSource ds = new HikariDataSource(hkcfg);
    return ds;
}

@Bean(name="KEEM")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("dataSourceKE")DataSource ds) {
    return BAConfig.entityManagerFactoryBuilder(ds);
}


@Bean(name = "txManagerKE")
JpaTransactionManager transactionManager(@Qualifier("KEEM") EntityManagerFactory em) {
    JpaTransactionManager transactionManager = new JpaTransactionManager(em);
    return transactionManager;
}
}
它们都导入到MainConfig.java类中,并使用以下属性文件

jdbc.properties

jdbc.driverClassName=org.postgresql.Driver
jdbc.urlBA=jdbc:postgresql://localhost:5432/BambooBA
jdbc.urlKE=jdbc:postgresql://localhost:5432/BambooKE
这里是给定实体的rest控制器

ReservationsController.java

@RestController
@RequestMapping("/reservations")
public class ReservationsController {

@Autowired
private ReservationsService reservationsService;

@RequestMapping(value = "/getAll/{c}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<List<Reservations>> getAll(@PathVariable City c) {
    try {
        List<Reservations> reservations = new ArrayList<Reservations>();
        switch(c)
        {
            case BA: reservations = reservationsService.findAllBA(); break;
            case KE: reservations = reservationsService.findAllKE(); break;
        }
        return new ResponseEntity<List<Reservations>>(reservations, HttpStatus.OK);
    } catch (NoSuchElementException e)
    {
        return new ResponseEntity<List<Reservations>>(HttpStatus.NOT_FOUND);
    }
}
}
@RestController
@请求映射(“/reservations”)
公共类保留控制器{
@自动连线
私人预订服务预订服务;
@RequestMapping(value=“/getAll/{c}”,method=RequestMethod.GET,products=MediaType.APPLICATION\u JSON\u value)
公共响应getAll(@PathVariable City c){
试一试{
列表保留=新建ArrayList();
开关(c)
{
案例BA:reservations=reservationsService.findAllBA();break;
案例KE:reservations=reservationsService.findAllKE();break;
}
返回新的ResponseEntity(reservations,HttpStatus.OK);
}捕获(无接触元素例外e)
{
返回新的ResponseEntity(未找到HttpStatus.NOT_);
}
}
}
这里是预订服务,我一直在尝试提取虚拟数据(在两个DBs中,id都是1)

ReservationsService.java

@Service
public class ReservationsService {

@Autowired
private ReservationsDao reservationsDao;

@Transactional("txManagerBA")
public List<Reservations> findAllBA() throws NoSuchElementException {
    reservationsDao.setEM(City.BA);
    List<Reservations> reservations = new ArrayList<Reservations>();
    reservations.add(reservationsDao.find(1));
    if(reservations.size() == 0)
    {
        throw new NoSuchElementException();
    }
    return reservations;
}

@Transactional("txManagerKE")
public List<Reservations> findAllKE() throws NoSuchElementException {
    reservationsDao.setEM(City.KE);
    List<Reservations> reservations = new ArrayList<Reservations>();
    reservations.add(reservationsDao.find(1));
    if(reservations.size() == 0)
    {
        throw new NoSuchElementException();
    }
    return reservations;
}
}
@服务
公共类保留服务{
@自动连线
私人预订SDAO预订SDAO;
@事务性(“txManagerBA”)
public List findAllBA()抛出NoTouchElementException{
保留Sao.setEM(City.BA);
列表保留=新建ArrayList();
添加(reservationsDao.find(1));
if(reservations.size()==0)
{
抛出新的NoTouchElementException();
}
返回预订;
}
@事务性(“txManagerKE”)
public List findAllKE()抛出NoTouchElementException{
保留Sao.setEM(City.KE);
列表保留=新建ArrayList();
添加(reservationsDao.find(1));
if(reservations.size()==0)
{
抛出新的NoTouchElementException();
}
返回预订;
}
}
这里是DAO超类(特定的DAO继承自这个类,并且只有一个超级构造函数)

BaseDao.java

public abstract class BaseDao<T>{

@PersistenceContext(unitName = "BAEM")
EntityManager emBA;

@PersistenceContext(unitName = "KEEM")
EntityManager emKE;

EntityManager em;

protected final Class<T> type;

protected BaseDao(Class<T> type) {
    this.type = type;
}

public void setEM(City c)
{
    switch(c) {
        case BA: em = emBA; break;
        case KE: em = emKE; break;
    }
}

public T find(Integer id) {
    return em.find(type, id);
}

public List<T> findAll() {
    return em.createQuery("SELECT e FROM " + type.getSimpleName() + " e", type).getResultList();
}
}
公共抽象类BaseDao{
@PersistenceContext(unitName=“BAEM”)
实体经理emBA;
@PersistenceContext(unitName=“KEEM”)
实体经理emKE;
实体管理器;
受保护的最终类类型;
受保护的BaseDao(类类型){
this.type=type;
}
公共空间中心(c城)
{
开关(c){
案例BA:em=emBA;中断;
案例KE:em=emKE;中断;
}
}
公共查找不到(整数id){
返回em.find(类型,id);
}
公共列表findAll(){
返回em.createQuery(“从”+type.getSimpleName()+“e”,type.getResultList()中选择e);
}
}
调试(在find()函数的BaseDAO中设置的断点)表明使用了正确的持久化单元来检索数据(当我一直向下移动到persistenceUnitInfo.nonJtaDataSource.jdbcUrl时,URL是正确的)


然而,无论请求如何,只有一个数据库正在使用。我也尝试过使用AbstractRoutingDataSource,但也遇到了同样的问题——数据库将在第一次请求时设置,然后只使用该数据库,而与请求无关。

以下是我们在spring4应用程序中使用的配置和Hikariol 当您有多个数据库数据源时,@Qualifier注释将非常有用,当与@autowire一起使用时,@Primary将成为默认数据源,当使用其他数据源时,将@Qualifier注释与@AutoWired一起使用

@Bean(destroyMethod = "close")
@Primary
@Qualifier("tspDataSource")
public DataSource dataSource() {

    HikariConfig config = new HikariConfig("/hikari-tsp.properties");
    config.addDataSourceProperty("cachePrepStmts", "true");
    config.addDataSourceProperty("prepStmtCacheSize", "250");
    config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
    final HikariDataSource ds = new HikariDataSource(config);
    return ds;
}
第二个呢

 @Bean(destroyMethod = "close")
    @Qualifier("fdxDataSource")
    public DataSource fdxDataSource() {
        HikariConfig config = new HikariConfig("/hikari-fdx.properties");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        final HikariDataSource ds = new HikariDataSource(config);
        return ds;
    }

我注释了数据源,将它们设置为final,并且在调试创建EntityManager bean的函数时,数据源是正确的,但是仍然只有一个数据源正在使用(与设置为primary的数据源无关).我也尝试过不将数据源用作bean,而是直接在创建EntityManager的函数中创建它们,但这也不起作用。