3

私は、異なる年の複数のデータベースを持つSpringブートプロジェクトを持っており、これらのデータベースは同じテーブルを持つので、唯一の違いは年(...、DB2016、DB2017)です。アプリケーションのコントローラでは、私は "異なる"年に属するデータを返す必要があります。さらに将来、他のデータベースも作成されます(たとえば、2018年には「DB2018」という名前のデータベースが存在します)。だから私の問題は、新しいデータソースと新しいリポジトリを毎年作成することなくデータベース間の接続を切り替える方法です。 私が投稿した別の質問(Spring Boot - Same repository and same entity for different databases)では、既存のデータベースごとに異なるデータソースと異なるリポジトリを作成するという回答がありましたが、この場合、現在のデータベースに基づいて現在の年のデータを返したいと考えています。より具体的には:Springブート - 接続を動的に変更します

SomeEntity.java

@Entity(name = "SOMETABLE") 
public class SomeEntity implements Serializable { 
@Id 
@Column(name="ID", nullable=false) 
private Integer id; 

@Column(name="NAME") 
private String name; 
} 

SomeRepository.java

public interface SomeRepository extends PagingAndSortingRepository<SomeEntity, Integer> { 
@Query(nativeQuery= true, value = "SELECT * FROM SOMETABLE WHERE NAME = ?1") 
List<SomeEntity> findByName(String name); 
} 

SomeController.java

@RequestMapping(value="/foo/{name}", method=RequestMethod.GET) 
public ResponseEntity<List<SomeEntity>> findByName(@PathVariable("name") String name) { 
List<SomeEntity> list = autowiredRepo.findByName(name); 
return new ResponseEntity<List<SomeEntity>>(list,HttpStatus.OK); 

} 

application.properties

spring.datasource.url=jdbc:postgresql://localhost:5432/DB 
spring.datasource.username=xxx 
spring.datasource.password=xxx 

現在の年が2017年であるのであれば、私はこのような何かしたい:

int currentyear = Calendar.getInstance().get(Calendar.YEAR); 
int oldestDbYear = 2014; 
List<SomeEntity> listToReturn = new LinkedList<SomeEntity>(); 
//the method getProperties is a custom method to get properties from a file 
String url = getProperties("application.properties", "spring.datasource.url"); 
props.setProperty("user", getProperties("application.properties","spring.datasource.username")); 
props.setProperty("password", getProperties("application.properties","spring.datasource.password")); 
for (int i = currentYear, i>oldestDbYear, i--) { 
//this is the connection that must be used by autowiredRepo Repository, but i don't know how to do this. 
//So the repository uses different connection for every year. 
Connection conn = getConnection(url+year,props); 
List<SomeEntity> list_of_specific_year = autowiredRepo.findByName(name); 
conn.close; 
listToReturn.addAll(list_of_specific_year); 
} 
return listToReturn; 

ホープeverithingをここにおそらくあなたのニーズに最も適しているものは、SpringのAbstractRoutingDataSourceある

答えて

1

明らかです。複数のデータソースを定義する必要がありますが、単一のリポジトリだけが必要です。実行時にプログラムでDataSource Beanを作成し、アプリケーションコンテキストに登録する方法が常に存在するため、複数のデータソースでは問題はありません。

AbstractRoutingDataSource@Beanを作成する際には基本的に@Configurationクラス内にMap<Object, DataSource>を登録しています。この場合、検索キーは年になります。

次に、AbstractRoutingDataSourceを実装し、determineCurrentLookupKey()メソッドを実装するクラスを作成する必要があります。データベース呼び出しが行われるたびに、現在のコンテキストでこのメソッドが呼び出され、返される値はDataSourceです。あなたの場合は、単にURLを@PathVariableとし、determineCurrentLookupKey()の実装がURLの@PathVariable(たとえば、コントローラ内に@GetMapping("/{year}/foo/bar/baz")のようなマッピングを持っています)を取得したいと思っているようです。

HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder 
      .getRequestAttributes()).getRequest(); 

    HashMap templateVariables = 
(HashMap)request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); 

    return templateVariables.get("year"); 

複数の異なるサーバー上で実行されている多くの事例があった製品のテストツールを書くとき、私はこのアプローチを使用して、私は私の@Controller秒から統一されたプログラミングモデルを望んでいたが、まだそれが正しいデータベースを打つことがしたかったですURL内のサーバー/デプロイの組み合わせ。魅力のように働いた。

Hibernateを使用している場合の欠点は、すべての接続が1つのSessionFactoryを経由することです。これは、Hibernateの第2レベルのキャッシングを理解できないことを意味しますが、

+0

ありがとうございました!最近の私は回避策を見つけましたが、私の解決策はオートワイヤリングの原則に従わないので、私はあなたのソリューションを試してみます – Mark

関連する問題