sql >> Databasteknik >  >> RDS >> Mysql

Kopiera data mellan olika databaser (båda stöds jdbc)

Visst, det är möjligt på ett väldigt enkelt sätt om schemana är desamma. Och eftersom du skapade båda databaserna med samma Hibernate-mappning bör de vara lika i Entity mening.

Du behöver bara två vilolägesbeständighetsenheter (datakällor). Om båda är korrekt konfigurerade och du har den specifika EntityManager instanser praktiskt, bara gå ner till Hibernate Session nivå - så vitt jag vet stöder JPA inte det på detta sätt (rätta mig om jag har fel) - och replikera din källenhet till din måldatabas.

Eftersom jag gillar att arbeta med Spring kommer jag att använda Spring Boot för följande exempel. Förutom konfigurationen skulle replikeringssteget implementeras på samma sätt med alla vilolägesapplikationer.

Jag använder också två PostgreSQL-databaser istället för en HSQLB bara för att göra det enkelt. Förläng bara konfigurationsdelen om dina konfigurationer glider isär, den enda skillnaden mellan mina persistensenheter är datakällans webbadress.

Så först behöver vi en enhet för att testa replikeringen:

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

}

Detta är (YAML-versionen av) konfigurationen av de två datakällorna (se den andra datakällans webbadress som heter targetDatabaseUrl ), Alla andra delar av konfigurationen kommer att användas för båda persistensenheterna:

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

Nästa del är konfigurationsklassen för datakällorna:

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();
    }

}

Nu kan du använda olika enhetshanterare för att helt enkelt läsa och skriva dina data från en datakälla till en annan. För att visa att här är ett litet testfall:

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());
    }

}

Slutligen, välj en av möjliga replikeringslägen som passar dina behov.

Det är allt. Du kan till och med använda en transaktion, välj bara en av båda persistensenheterna och utnyttja dess transaktionshanterare som testet gör med @Transactional(transactionManager = "targetTransactionManager") .



  1. Password_verify i PHP

  2. Vad är SQL Server?

  3. flytta tabell från ett schema till ett annat schema?

  4. Oracle 18c Ny funktion:Onlinemodifiering av partitionering