• 六、spring boot 1.5.4 配置多数据源


    spring boot 已经支持多数据源配置了,无需网上好多那些编写什么类的,特别麻烦,看看如下解决方案,官方的,放心!

    1.首先定义数据源配置

    #=====================multiple database config============================
    #ds1
    first.datasource.url=jdbc:mysql://localhost/test?characterEncoding=utf8&useSSL=true
    first.datasource.username=root
    first.datasource.password=123456
    first.datasource.driver-class-name=com.mysql.jdbc.Driver
    first.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
    first.datasource.max-wait=10000
    first.datasource.max-active=200
    first.datasource.test-on-borrow=true
    first.datasource.initial-size=10

    #ds2
    second.datasource.url=jdbc:mysql://localhost/test2?characterEncoding=utf8&useSSL=true
    second.datasource.username=root
    second.datasource.password=123456
    second.datasource.driver-class-name=com.mysql.jdbc.Driver
    second.datasource.type=org.apache.tomcat.jdbc.pool.DataSource
    second.datasource.max-wait=10000
    second.datasource.max-active=200
    second.datasource.test-on-borrow=true
    second.datasource.initial-size=10

    #=====================jpa config================================
    #实体类维护数据库表结构的具体行为:update/create/create-drop/validate/none
    spring.jpa.hibernate.ddl-auto=none
    #打印sql语句
    spring.jpa.show-sql=true

    #=============jackson serialize config =========================
    #格式化输出的json字符串
    spring.jackson.serialization.indent_output=true


    2.配置ds1的相关注入对象和启用jpa支持
    /**
     * Created by hdwang on 2017-06-16.
     * 第一个数据源配置
     * If you are using Spring Data, you need to configure @EnableJpaRepositories
     */
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = "com.hdwang.dao.datajpa.firstDs",entityManagerFactoryRef = "firstEntityManagerFactory",transactionManagerRef="firstTransactionManager")
    public class FirstDsConfig {
    
        /**
         * 数据源配置对象
         * Primary 表示默认的对象,Autowire可注入,不是默认的得明确名称注入
         * @return
         */
        @Bean
        @Primary
        @ConfigurationProperties("first.datasource")
        public DataSourceProperties firstDataSourceProperties() {
            return new DataSourceProperties();
        }
    
        /**
         * 数据源对象
         * @return
         */
        @Bean
        @Primary
        @ConfigurationProperties("first.datasource")
        public DataSource firstDataSource() {
            return firstDataSourceProperties().initializeDataSourceBuilder().build();
        }
    
        /**
         * 实体管理对象
         * @param builder 由spring注入这个对象,首先根据type注入(多个就取声明@Primary的对象),否则根据name注入
         * @return
         */
        @Bean
        @Primary
        public LocalContainerEntityManagerFactoryBean firstEntityManagerFactory(
                EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(firstDataSource())
                    .packages("com.hdwang.entity.dbFirst")
                    .persistenceUnit("firstDs")
                    .build();
        }
    
        /**
         * 事务管理对象
         * @return
         */
        @Bean(name = "firstTransactionManager")
        @Primary
        public PlatformTransactionManager transactionManager(EntityManagerFactory emf){
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(emf);
            return transactionManager;
        }
    
        @Bean
        @Primary
        public JdbcTemplate jdbcTemplate(){
            return new JdbcTemplate(firstDataSource());
        }
    
        @Bean
        @Primary
        public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager){
            return new TransactionTemplate(platformTransactionManager);
        }
    }
    相关知识点:
    1.使用@Bean可以创建一个bean对象交给spring容器管理
    2.@Bean创建的bean对象的名称默认为方法名,也可以指定
    3.@Bean方法参数表示,接收一个bean对象,默认按照type类型接收注入的对象,若要修改为byName方式,可以使用@Qualifier注解注入准确的对象
    4.@Primary表示该bean为此类型的默认bean,在其他地方引用的时候用@Autowired即可按照类型注入,不受同类型多个对象影响
    5.EnableJpaRepositories表示启用spring data jpa的支持,也就是jpa的新使用方式,注意basePackages指的是 @Repository接口的所在包位置,可配置多个
    其他注解就不清楚了!

    2.配置ds2的相关注入对象和启用jpa支持
    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(basePackages = "com.hdwang.dao.datajpa.secondDs", entityManagerFactoryRef = "secondEntityManagerFactory",transactionManagerRef = "secondTransactionManager")
    public class SecondDsConfig {
    
        @Bean
        @ConfigurationProperties("second.datasource")
        public DataSourceProperties secondDataSourceProperties() {
            return new DataSourceProperties();
        }
    
        @Bean
        @ConfigurationProperties("second.datasource")
        public DataSource secondDataSource() {
            return secondDataSourceProperties().initializeDataSourceBuilder().build();
        }
    
        /**
         * 实体管理对象
         * @param builder  由spring注入这个对象,首先根据type注入(多个就取声明@Primary的对象),否则根据name注入
         * @return
         */
        @Bean
        public LocalContainerEntityManagerFactoryBean secondEntityManagerFactory(
                EntityManagerFactoryBuilder builder) {
            return builder
                    .dataSource(secondDataSource())
                    .packages("com.hdwang.entity.dbSecond")
                    .persistenceUnit("secondDs")
                    .build();
        }
    
        /**
         * 事物管理对象
         * @param secondEntityManagerFactory 实体管理工厂对象(按照名称注入)
         * @return 平台事物管理器
         */
        @Bean(name = "secondTransactionManager")
        public PlatformTransactionManager transactionManager(@Qualifier("secondEntityManagerFactory")LocalContainerEntityManagerFactoryBean secondEntityManagerFactory){
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(secondEntityManagerFactory.getObject());
            return transactionManager;
        }
    
        @Bean(name="jdbcTemplate2")
        public JdbcTemplate jdbcTemplate(){
            return new JdbcTemplate(secondDataSource());
        }
    
        @Bean(name = "transactionTemplate2")
        public TransactionTemplate transactionTemplate(@Qualifier("secondTransactionManager")PlatformTransactionManager transactionManager){
            return new TransactionTemplate(transactionManager);
        }
    }

    3.Repository数据持久层

    package com.hdwang.dao.datajpa.firstDs;
    
    @Repository
    public interface UserRepository extends JpaRepository<User, Integer> {
        /**
         * spring data jpa 会自动注入实现(根据方法命名规范)
         * @return
         */
        User findByNumber(String number);
    
    
        @Modifying
        @Query("delete from User u where u.id = :id")
        void deleteUser(@Param("id")int id);
    }
    package com.hdwang.dao.datajpa.secondDs;
    
    @Repository
    public interface OrderRepository extends JpaRepository<Order, Integer> {
        /**
         * spring data jpa 会自动注入实现(根据方法命名规范)
         * @return
         */
        User findByNumber(String number);
    
    
        @Modifying
        @Query("delete from Order o where o.id = :id")
        void deleteUser(@Param("id") int id);
    }
    上面两个接口分属两个数据源,在@EnableJpaRepositories配置好后,这里就可以正确操作相应的数据源了


    4.Service服务层,注意事物(接口我就不贴了)
    @Service
    @Transactional("firstTransactionManager")
    public class UserServiceImpl implements UserService {
    
        @Autowired
        private UserRepository userRepository;
    
        @Override
        public User findById(int id) {
            return this.userRepository.findOne(id);
        }
    
        @Override
        public User findByNumber(String number) {
            return this.userRepository.findByNumber(number);
        }
    
        @Override
        public List<User> findAllUserByPage(int page,int size) {
            Pageable pageable = new PageRequest(page, size);
            Page<User> users =  this.userRepository.findAll(pageable);
            return users.getContent();
        }
    
        @Override
        public User updateUser(User user,boolean throwEx) {
            User userNew = this.userRepository.save(user);
            if(throwEx){
                throw new RuntimeException("throw a ex");
            }
            return userNew;
        }
    
        @Override
        public void deleteUser(int id) {
            this.userRepository.deleteUser(id);
        }
    }
    @Service
    @Transactional("secondTransactionManager")
    public class OrderServiceImpl implements OrderService {
    
        @Autowired
        private OrderRepository orderRepository;
    
    
        @Override
        public Order findById(int id) {
            return this.orderRepository.findOne(id);
        }
    
        @Override
        public Order updateOrder(Order order, boolean throwEx) {
            Order orderNew = this.orderRepository.save(order);
            if(throwEx){
                throw new RuntimeException("throw a ex");
            }
            return orderNew;
        }
    }


    知识扩展

    1.如果采用传统jpa方式,@EnableJpaRepositories无需配置,配置了也无影响。实现方式如下:

    ds1相关DaoImpl
    @PersistenceContext
    private EntityManager entityManager;

    ds2相关DaoImpl
    @PersistenceContext(unitName = "secondDs")
    private EntityManager entityManager;

    因为ds1的entityManger声明了@Primary,所以无需指明unitName,ds2必须指明。注入了准确的entityManager,就可以直接拿来操作数据库了。service层和上面一样的,@Transactional("xxxManager")指明事物管理器即可!


    2.采用jdbcTemplate方式,直接注入到Service层对象即可,so easy!
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Resource(name="jdbcTemplate2")
    private JdbcTemplate jdbcTemplate2;

    @Resource(name="transactionTemplate2")
    private TransactionTemplate transactionTemplate2;


    好了,spring boot 多数据源,完美解决! 而且三种数据库操作方法均支持,包括事物。已经经过实践证明了! 这是官方给出的最佳实践,只是官方文档没写细而已。

    项目源码:https://github.com/hdwang123/springboottest
    
    
    其它问题:
    1. jpa配置无法生效,实体属性无法自动转换成数据库字段名,例如 userName -> user_name
    解决办法:
    entityManagerFactoryBuiler中指明jpa配置
    builder.properties(new JpaProperties().getHibernateProperties(firstDataSource()))


  • 相关阅读:
    Linux进程理解与实践(四)wait函数处理僵尸进程
    Linux进程理解与实践(三)进程终止函数和exec函数族的使用
    system V信号量和Posix信号量
    Linux进程间通信方式--信号,管道,消息队列,信号量,共享内存
    linux 高并发socket通信模型
    信号集函数
    进程间通信使用信号
    使用消息队列
    改变域名,php
    php函数
  • 原文地址:https://www.cnblogs.com/hdwang/p/7041096.html
Copyright © 2020-2023  润新知