六、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()))



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM