Chắc chắn, có thể thực hiện một cách rất dễ dàng nếu các schemata giống nhau. Và vì bạn đã tạo cả hai cơ sở dữ liệu với cùng một ánh xạ Hibernate nên chúng phải bằng nhau trong Entity
giác quan.
Bạn chỉ cần hai đơn vị liên tục Hibernate (nguồn dữ liệu). Nếu cả hai đều được định cấu hình đúng cách và bạn có EntityManager
cụ thể các trường hợp hữu ích, chỉ cần đi xuống Session
Hibernate cấp độ - theo như tôi biết JPA không hỗ trợ điều đó theo cách này (hãy sửa cho tôi nếu tôi sai) - và sao chép thực thể nguồn của bạn vào cơ sở dữ liệu mục tiêu của bạn.
Vì tôi thích làm việc với Spring, tôi sẽ sử dụng Spring Boot cho ví dụ sau. Ngoại trừ cấu hình, bước sao chép sẽ được thực hiện giống như vậy với bất kỳ ứng dụng Hibernate nào.
Tôi cũng đang sử dụng hai cơ sở dữ liệu PostgreSQL thay vì HSQLB chỉ để giữ cho nó đơn giản. Chỉ cần mở rộng phần cấu hình nếu cấu hình của bạn khác nhau, điểm khác biệt duy nhất giữa các đơn vị độ bền của tôi là url nguồn dữ liệu.
Vì vậy, trước tiên chúng ta cần một thực thể để kiểm tra bản sao:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class StorageEntry {
@Id
@GeneratedValue
private Long id;
private String someValue;
// imagine getters and setter here
}
Đây là (phiên bản YAML của) cấu hình của hai nguồn dữ liệu (xem url nguồn dữ liệu thứ hai được gọi là targetDatabaseUrl
), Tất cả các phần khác của cấu hình sẽ được sử dụng cho cả hai đơn vị duy trì:
spring:
datasource:
url: jdbc:postgresql://localhost/postgres
targetDatabaseUrl: jdbc:postgresql://localhost/postgres2
username: <username>
password: <password>
driver-class-name: org.postgresql.Driver
jpa:
database-platform: org.hibernate.dialect.PostgreSQLDialect
hibernate:
ddl-auto: create-drop
Phần tiếp theo là lớp cấu hình cho các nguồn dữ liệu:
import java.util.Properties;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
public class PersistenceConfig {
@Autowired
private JpaVendorAdapter jpaVendorAdapter;
@Value("${spring.datasource.url}")
private String databaseUrl;
@Value("${spring.datasource.targetDatabaseUrl}")
private String targetDatabaseUrl;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.jpa.database-platform}")
private String dialect;
@Value("${spring.jpa.hibernate.ddl-auto}")
private String ddlAuto;
@Bean
public EntityManager sourceEntityManager() {
return sourceEntityManagerFactory().createEntityManager();
}
@Bean
public EntityManager targetEntityManager() {
return targetEntityManagerFactory().createEntityManager();
}
@Bean
public EntityManagerFactory sourceEntityManagerFactory() {
return createEntityManagerFactory("source", databaseUrl);
}
@Bean
public EntityManagerFactory targetEntityManagerFactory() {
return createEntityManagerFactory("target", targetDatabaseUrl);
}
@Bean
public PlatformTransactionManager sourceTransactionManager() {
return new JpaTransactionManager(sourceEntityManagerFactory());
}
@Bean
public PlatformTransactionManager targetTransactionManager() {
return new JpaTransactionManager(targetEntityManagerFactory());
}
private EntityManagerFactory createEntityManagerFactory(final String persistenceUnitName,
final String databaseUrl) {
final LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
final DriverManagerDataSource dataSource = new DriverManagerDataSource(databaseUrl, username, password);
dataSource.setDriverClassName(driverClassName);
entityManagerFactory.setDataSource(dataSource);
entityManagerFactory.setJpaVendorAdapter(jpaVendorAdapter);
entityManagerFactory.setPackagesToScan("com.example.model");
entityManagerFactory.setPersistenceUnitName(persistenceUnitName);
final Properties properties = new Properties();
properties.setProperty("hibernate.dialect", dialect);
properties.setProperty("hibernate.hbm2ddl.auto", ddlAuto);
entityManagerFactory.setJpaProperties(properties);
entityManagerFactory.afterPropertiesSet();
return entityManagerFactory.getObject();
}
}
Giờ đây, bạn có thể sử dụng các trình quản lý thực thể khác nhau để chỉ cần đọc và ghi dữ liệu của mình từ nguồn dữ liệu này sang nguồn dữ liệu khác. Để cho thấy điều đó, đây là một trường hợp thử nghiệm nhỏ:
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.hibernate.ReplicationMode;
import org.hibernate.Session;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import com.example.model.StorageEntry;
@SpringBootTest
@RunWith(SpringRunner.class)
@Transactional(transactionManager = "targetTransactionManager")
public class ReplicationTests {
@PersistenceContext(unitName = "source")
private EntityManager sourceEntityManager;
@PersistenceContext(unitName = "target")
private EntityManager targetEntityManager;
@Test
public void copyEntityBetweenPersistenceUnits() {
final StorageEntry entityToCopy = new StorageEntry();
entityToCopy.setSomeValue("copyMe!");
sourceEntityManager.persist(entityToCopy);
final Long id = entityToCopy.getId();
final StorageEntry sourceEntity = sourceEntityManager.find(StorageEntry.class, id);
assertThat("Entity should exist in default schema!", sourceEntity, notNullValue());
StorageEntry targetEntity = targetEntityManager.find(StorageEntry.class, id);
assertThat("Target schema should not contain the entity, yet!", targetEntity, nullValue());
final Session hibernateSession = targetEntityManager.unwrap(Session.class);
hibernateSession.replicate(sourceEntity, ReplicationMode.OVERWRITE);
targetEntityManager.flush();
targetEntityManager.clear();
targetEntity = targetEntityManager.find(StorageEntry.class, id);
assertThat("Entity should be copied now!", targetEntity, notNullValue());
}
}
Cuối cùng, chọn một trong các các chế độ sao chép có thể có phù hợp với nhu cầu của bạn.
Đó là tất cả. Bạn thậm chí có thể sử dụng một giao dịch, chỉ cần quyết định cho một trong cả hai đơn vị bền vững và tận dụng trình quản lý giao dịch của nó giống như thử nghiệm với @Transactional(transactionManager = "targetTransactionManager")
.