最近做toB、toG業務,普遍要去適配各種國產資料庫,所以不得不用hibernate,過去這么多年一直都是用mybatis+mysql,現在重拾hibernate,專注跨資料庫,感興趣的加關注,
需求背景:
最近做一個資料庫備份還原功能,需要支持跨庫同步,比如mysql的資料及表結構整庫批量同步到SqlServer(雖然Navicat有此功能,但是Navicat不支持一些新的國產資料庫,況且,這個Navicat不能集成到專案里,用戶使用不方便),
功能分析:
1、需要同步表結構,不同的資料庫DDL陳述句不兼容性,但是,hibernate框架中,entity已經定義了表結構,hibernate會幫我們適配各種資料庫,所以不用備份表結構(sql: create table xxx ...),直接通過hibernate在資料庫生成表;
2、常見的資料備份是備份insert into table ... 這樣的sql陳述句,這樣做,備份檔案體積大,且不是批量插入,性能一般,特殊格式的欄位在不同資料庫還存在兼容問題,所以我們可以通過hibernate,只備份資料,將資料轉為json格式存盤,然后用hibernate將資料入庫,
實作思路:
1、通過entityManager獲取物體entity;
2、通過entity查詢對應表所有資料;
3、決議前端傳參,組裝新的資料庫鏈接;
4、根據資料庫鏈接和獲取到的物體,創建hibernate工廠(通過entity創建表);
5、再次通過遍歷物體,組裝批量insert sql(ps:hibernate批量插入性能很差,原則是還是saveOrUpdate);
6、從創建的hibernate工廠獲取sessionFactory,執行批量插入sql;
關鍵代碼:
1、通過批量jpa備份資料
@Resource private EntityManager entityManager; //注入entityManager // --------------------------------- // 通過entityManager獲取所有物體 Set<EntityType<?>> entityTypes = entityManager.getMetamodel().getEntities(); // 遍歷物體 entityTypes.parallelStream().forEach((EntityType<?> entity) -> { // 根據物體創建 JpaRepository SimpleJpaRepository simpleJpaRepository = new SimpleJpaRepository(entity.getJavaType(), entityManager); // 直接讀表資料 List<?> list = simpleJpaRepository.findAll();
// 可以將list轉為json存盤...以下省略... });
2、通過jpa手動創建表
private void initEntityManager() { Map<String, String> settings = new HashMap<>(); settings.put(AvailableSettings.DRIVER, "com.mysql.jdbc.Driver");
settings.put(AvailableSettings.DIALECT, "com.ut.msfw1a.common.core.hibernate.dialect.MsfwMySQLDialect");
settings.put(AvailableSettings.URL, "jdbc:mysql://127.0.0.1"); // 填入要還原的資料庫jdbc資訊 settings.put(AvailableSettings.USER, "root"); settings.put(AvailableSettings.PASS, "password"); settings.put(AvailableSettings.ORDER_INSERTS, "true"); settings.put(AvailableSettings.ORDER_UPDATES, "true"); settings.put(AvailableSettings.STATEMENT_BATCH_SIZE, "10000"); settings.put(AvailableSettings.SHOW_SQL, "false"); settings.put(AvailableSettings.BATCH_VERSIONED_DATA, "ture"); settings.put(AvailableSettings.HBM2DDL_AUTO, "update"); settings.put(AvailableSettings.PHYSICAL_NAMING_STRATEGY, "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");// 表命名規則 ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(settings).build(); MetadataSources metadataSources = new MetadataSources(serviceRegistry); entityTypes.forEach((EntityType<?> type) -> {//entityTpyes是備份的時候從entity中取到的 metadataSources.addAnnotatedClass(type.getJavaType()); // 添加要還原的entity }); Metadata metadata = metadataSources.getMetadataBuilder().build(); // 創建hibernate工廠,這一步,會自動生成表 SessionFactory sessionFactory = metadata.buildSessionFactory(); sessionFactory.openSession(); entityManager = sessionFactory.createEntityManager(); // 這樣就根據jdbc資訊創建了一個自己的entityManager }
3、還原資料
存資料的時候,json資料檔案用表名存盤
可以這樣根據表名獲取到對應的entity
Optional<EntityType<?>> entityTypeOptional = entityTypes.stream().filter(et -> et.getName().equals(tableName)).findFirst();
if (!entityTypeOptional.isPresent()) {
return;
}
EntityType<?> entityType = entityTypeOptional.get();
根據表名,和新創建的entityManager還原資料
SimpleJpaRepository simpleJpaRepository = new SimpleJpaRepository(entity.getJavaType(), entityManager);
simpleJpaRepository.batchSave(list)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545523.html
標籤:Java
