java - 在 spring boot 中动态设置 hibernate.dialect 属性

标签 java spring hibernate spring-boot

我已经浏览了有关如何设置的可用示例和教程 hibernate.dialect属性正确,但没有找到适合我的情况的方法。

This教程最适合我,但它缺乏设置 hibernate.dialect 的能力动态属性,因为我有不同类型的数据库要连接:

  • MS SQL
  • 甲骨文
  • H2
  • MySQL

  • 由于方言不正确,我的 JPA(删除/更新)查询失败。

    以下是 @Configuration 的实现,完美运行,我如何才能设置 hibernate.dialect每个数据源在运行时动态?

    先感谢您。
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(
            basePackages = "com.example.multidb",
            entityManagerFactoryRef = "multiEntityManager",
            transactionManagerRef = "multiTransactionManager"
    )
    public class PersistenceConfiguration {
    
        private final String PACKAGE_SCAN = "com.example.multidb";    
    
        @Primary
        @Bean(name = "mainDataSource")
        @ConfigurationProperties("app.datasource.main")
        public DataSource mainDataSource() {
            return DataSourceBuilder.create().type(HikariDataSource.class).build();
        }    
    
        @Bean(name = "clientADataSource")
        @ConfigurationProperties("app.datasource.clienta")
        public DataSource clientADataSource() {
            return DataSourceBuilder.create().type(HikariDataSource.class).build();
        }
    
        @Bean(name = "clientBDataSource")
        @ConfigurationProperties("app.datasource.clientb")
        public DataSource clientBDataSource() {
            return DataSourceBuilder.create().type(HikariDataSource.class).build();
        }
    
        @Bean(name = "multiRoutingDataSource")
        public DataSource multiRoutingDataSource() {
            Map<Object, Object> targetDataSources = new HashMap<>();
    
            targetDataSources.put(DBTypeEnum.MAIN, mainDataSource());
            targetDataSources.put(DBTypeEnum.CLIENT_A, clientADataSource());
            targetDataSources.put(DBTypeEnum.CLIENT_B, clientBDataSource());
    
            MultiRoutingDataSource multiRoutingDataSource = new MultiRoutingDataSource();
    
            multiRoutingDataSource.setDefaultTargetDataSource(mainDataSource());
            multiRoutingDataSource.setTargetDataSources(targetDataSources);        
    
            return multiRoutingDataSource;
        }   
    
        @Bean(name = "multiEntityManager")
        public LocalContainerEntityManagerFactoryBean multiEntityManager() {
            LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    
            em.setDataSource(multiRoutingDataSource());
            em.setPackagesToScan(PACKAGE_SCAN);
    
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    
            em.setJpaVendorAdapter(vendorAdapter);
            em.setJpaProperties(hibernateProperties());        
    
            return em;
        }
    
        @Bean(name = "multiTransactionManager")
        public PlatformTransactionManager multiTransactionManager() {
            JpaTransactionManager transactionManager
                    = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(
                    multiEntityManager().getObject());        
    
            return transactionManager;
        }
    
        @Primary
        @Bean(name = "dbSessionFactory")
        public LocalSessionFactoryBean dbSessionFactory() {
            LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
    
            sessionFactoryBean.setDataSource(multiRoutingDataSource());
            sessionFactoryBean.setPackagesToScan(PACKAGE_SCAN);
            sessionFactoryBean.setHibernateProperties(hibernateProperties());
    
            return sessionFactoryBean;
        }
    
        private Properties hibernateProperties() {
            Properties properties = new Properties();
            properties.put("hibernate.show_sql", true);
            properties.put("hibernate.format_sql", true);        
    
            //set hibernate.dialect for each datasource
    
            return properties;
        }
    }
    

    最佳答案

    我已经为您创建了一个工作示例,我将在此处对其进行描述,但如果您想自己跳入代码 it's available at this GitHub repo .

    就我而言,我创建了两个数据源,一个用于 User另一个是 Item .

    这里的实体:

    package com.marcosbarbero.so.multiple.ds.entity.user;
    
    import lombok.Data;
    
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Data
    @Entity
    @Table(schema = "user")
    public class User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Integer id;
    
        private String name;
    
        @Column(unique = true, nullable = false)
        private String email;
    
        private int age;
    }
    
    

    package com.marcosbarbero.so.multiple.ds.entity.item;
    
    import lombok.Data;
    
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Data
    @Entity
    @Table(schema = "item")
    public class Item {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private int id;
    
        private String name;
    }
    
    

    请注意,为每个域设置不同的包很重要。
    然后我创建了 Repositories
    package com.marcosbarbero.so.multiple.ds.repository.user;
    
    import com.marcosbarbero.so.multiple.ds.entity.user.User;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface UserRepository extends JpaRepository<User, Integer> {
    }
    
    

    package com.marcosbarbero.so.multiple.ds.repository.item;
    
    import com.marcosbarbero.so.multiple.ds.entity.item.Item;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    public interface ItemRepository extends JpaRepository<Item, Integer> {
    }
    
    

    repo 没有什么特别之处。让我们转到最后一部分,即配置。
  • 我创建了一个 @ConfigurationProperties类来具体化我的配置,请耐心等待,我知道命名不是最好的:)

  • package com.marcosbarbero.so.multiple.ds.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Component;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @Data
    @Component
    @ConfigurationProperties(prefix = "multi-datasource")
    public class MultipleDataSourceProperties {
    
        private UserDataSourceProperties user = new UserDataSourceProperties();
    
        private ItemDataSourceProperties item = new ItemDataSourceProperties();
    
        @Data
        public static class UserDataSourceProperties {
            private HibernateProperties hibernate = new HibernateProperties();
        }
    
        @Data
        public static class ItemDataSourceProperties {
            private HibernateProperties hibernate = new HibernateProperties();
        }
    
        @Data
        public static class HibernateProperties {
            private Map<String, String> properties = new HashMap<>();
        }
    
    }
    

    我们很快就会看到属性配置文件。
  • 现在让我们创建 DataSourceUser :

  • package com.marcosbarbero.so.multiple.ds.config;
    
    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    @EnableJpaRepositories(
            basePackages = "com.marcosbarbero.so.multiple.ds.repository.user",
            entityManagerFactoryRef = "userEntityManager",
            transactionManagerRef = "userTransactionManager"
    )
    public class UserDataSourceConfig {
    
        private final MultipleDataSourceProperties properties;
    
        public UserDataSourceConfig(MultipleDataSourceProperties properties) {
            this.properties = properties;
        }
    
        @Bean
        @Primary
        public LocalContainerEntityManagerFactoryBean userEntityManager() {
            LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
            em.setDataSource(userDataSource());
            em.setPackagesToScan("com.marcosbarbero.so.multiple.ds.entity.user");
    
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            em.setJpaVendorAdapter(vendorAdapter);
            em.setJpaPropertyMap(properties.getUser().getHibernate().getProperties());
    
            return em;
        }
    
        @Primary
        @Bean
        @ConfigurationProperties("multi-datasource.user")
        public DataSource userDataSource() {
            return DataSourceBuilder.create().type(HikariDataSource.class).build();
        }
    
        @Primary
        @Bean
        public PlatformTransactionManager userTransactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(userEntityManager().getObject());
            return transactionManager;
        }
    }
    

    这门课对你来说很重要的部分是em.setJpaPropertyMap(properties.getUser().getHibernate().getProperties());它从我们的 @ConfigurationProperties 获取用户的 Hibernate 配置属性。上面定义的类。
  • 现在让我们对 Item 做同样的事情:

  • package com.marcosbarbero.so.multiple.ds.config;
    
    import com.zaxxer.hikari.HikariDataSource;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.boot.jdbc.DataSourceBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Primary;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    import org.springframework.orm.jpa.JpaTransactionManager;
    import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
    import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import javax.sql.DataSource;
    
    @Configuration
    @EnableJpaRepositories(
            basePackages = "com.marcosbarbero.so.multiple.ds.repository.item",
            entityManagerFactoryRef = "itemEntityManager",
            transactionManagerRef = "itemTransactionManager"
    )
    public class ItemDataSourceConfig {
    
        private final MultipleDataSourceProperties properties;
    
        public ItemDataSourceConfig(MultipleDataSourceProperties properties) {
            this.properties = properties;
        }
    
        @Bean
        @Primary
        public LocalContainerEntityManagerFactoryBean itemEntityManager() {
            LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
            em.setDataSource(itemDataSource());
            em.setPackagesToScan("com.marcosbarbero.so.multiple.ds.entity.item");
    
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            em.setJpaVendorAdapter(vendorAdapter);
            em.setJpaPropertyMap(properties.getItem().getHibernate().getProperties());
    
            return em;
        }
    
        @Primary
        @Bean
        @ConfigurationProperties("multi-datasource.item")
        public DataSource itemDataSource() {
            return DataSourceBuilder.create().type(HikariDataSource.class).build();
        }
    
        @Primary
        @Bean
        public PlatformTransactionManager itemTransactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(itemEntityManager().getObject());
            return transactionManager;
        }
    }
    
  • application.properties
  • multi-datasource.item.jdbcUrl=jdbc:h2:mem:spring_jpa_item;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS ITEM
    multi-datasource.item.username=sa
    multi-datasource.item.password=sa
    
    multi-datasource.item.hibernate.properties.hibernate.hbm2ddl.auto=create-drop
    multi-datasource.item.hibernate.properties.hibernate.cache.use_second_level_cache=false
    multi-datasource.item.hibernate.properties.hibernate.cache.use_query_cache=false
    multi-datasource.item.hibernate.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
    
    multi-datasource.user.jdbcUrl=jdbc:h2:mem:spring_jpa_user;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS USER
    multi-datasource.user.username=sa
    multi-datasource.user.password=sa
    
    multi-datasource.user.hibernate.properties.hibernate.hbm2ddl.auto=create-drop
    multi-datasource.user.hibernate.properties.hibernate.cache.use_second_level_cache=false
    multi-datasource.user.hibernate.properties.hibernate.cache.use_query_cache=false
    multi-datasource.user.hibernate.properties.hibernate.dialect=org.hibernate.dialect.OracleDialect
    
  • 一些单元测试

  • package com.marcosbarbero.so;
    
    import com.marcosbarbero.so.multiple.ds.entity.item.Item;
    import com.marcosbarbero.so.multiple.ds.entity.user.User;
    import com.marcosbarbero.so.multiple.ds.repository.item.ItemRepository;
    import com.marcosbarbero.so.multiple.ds.repository.user.UserRepository;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import static org.junit.jupiter.api.Assertions.assertNotNull;
    
    @SpringBootTest
    public class JPAMultipleDBTest {
    
        @Autowired
        private UserRepository userRepository;
    
        @Autowired
        private ItemRepository itemRepository;
    
        @Test
        public void whenCreatingUser_thenCreated() {
            User user = new User();
            user.setName("John");
            user.setEmail("john@test.com");
            user.setAge(20);
            user = userRepository.save(user);
    
            assertNotNull(userRepository.findById(user.getId()));
        }
    
        @Test
        public void whenCreatingProduct_thenCreated() {
            Item item = new Item();
            item.setName("Book");
            item.setId(2);
            item = itemRepository.save(item);
    
            assertNotNull(itemRepository.findById(item.getId()));
        }
    }
    

    我认为还值得一提的是,为了让它一切正常,我禁用了 DataSourceAutoConfiguration ,就这么简单:

    @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
    

    再说一遍,这一切都是 available at this GitHub repo .

    关于java - 在 spring boot 中动态设置 hibernate.dialect 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60796798/

    相关文章:

    java - 如何删除 Liferay Social Office 公告中的公告条目常量

    java - Jackson:名称为 'defaultReference' 的多个反向引用属性

    spring - 下载 Spring 引用文档

    java - 默认情况下,如何为特定实体打开 hibernate 过滤器?

    java - 与java8兼容的最低 hibernate 版本

    java - 缺少 return 语句的错误

    java - spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults 有什么用?

    java - Spring 4.1.0.RELEASE 和 Hibernate 4.3.6.Final 的依赖关系问题

    java - 使用 hibernate 在 Postgres 上设置随机种子

    java - 如何在 JTable 中添加/删除选定的列?