日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

springboot+jpa+mybatis 多数据源支持

發布時間:2025/4/16 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot+jpa+mybatis 多数据源支持 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

springboot+jpa+mybatis 多數據源支持


配置dataSource

import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary;import javax.sql.DataSource;/*** com.ehaoyao.paycenter.job.common.config* 數據源配置類* @author PF* @create 2018-05-10 16:17**/ @Configuration public class DataSourceConfig {@Bean(name = "payCenterDataSource")@Qualifier("payCenterDataSource")@Primary@ConfigurationProperties(prefix="spring.datasource.paycenter")public DataSource paycenterDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "erpDataSource")@Qualifier("erpDataSource")@ConfigurationProperties(prefix="spring.datasource.erp")public DataSource erpDataSource() {return DataSourceBuilder.create().build();} }

master數據源的sessionFactory、transactionManager等配置

package com.ehaoyao.paycenter.job.common.config;/*** 支付中心數據源配置類** @author PF* Created by dell on 2018-05-04.*/import com.alibaba.druid.pool.DruidDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;/*** com.ehaoyao.paycenter.job.common.config* 支付中心數據源配置類** @author PF* @create 2018-05-04 10:26**/ @Configuration @MapperScan(basePackages = "com.ehaoyao.paycenter.persistence.pay.mapper.paycenter",sqlSessionFactoryRef = "payCenterSqlSessionFactory") @EnableTransactionManagement public class PayCenterDataSourceConfig {static final String MAPPER_LOCATION = "classpath:mappings/com/ehaoyao/paycenter /persistence/pay/mapper/paycenter/*.xml";@Autowired@Qualifier("payCenterDataSource")private DataSource payCenterDataSource;@Bean(name = "payCenterTransactionManager")@Primarypublic DataSourceTransactionManager masterTransactionManager() {return new DataSourceTransactionManager(payCenterDataSource);}@Bean(name = "payCenterSqlSessionFactory")@Primarypublic SqlSessionFactory payCenterSqlSessionFactory(@Qualifier("payCenterDataSource") DataSource payCenterDataSource)throws Exception {final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(payCenterDataSource);sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(PayCenterDataSourceConfig.MAPPER_LOCATION));return sessionFactory.getObject();} }

配置slave數據源的sessionFactory、transactionManager等配置。

(其中需要注意的是,配置多數據源后,spring.jpa 這些配置,就不要寫在application里面了,沒法對應多個啊,所以需要寫在配置類中,如上getVendorProperties方法)
自己留著備查用的,master數據源用的mybatis,slave用的jpa(雖然用法很搞,但是主要為了記錄多數據源,及springboot下jpa配置相關)

package com.ehaoyao.paycenter.job.common.config;/*** ERP數據源配置類** @author PF* Created by dell on 2018-05-04.*/import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.persistence.EntityManager; import javax.sql.DataSource; import java.util.Map;/*** com.ehaoyao.paycenter.job.common.config* ERP數據源配置類* @author PF* @create 2018-05-04 10:27**/ @Configuration @EnableTransactionManagement @EnableJpaRepositories(entityManagerFactoryRef="erpEntityManagerFactory",transactionManagerRef="erpTransactionManager",basePackages= { "com.ehaoyao.paycenter.persistence.pay.Repository" }) public class ErpDataSourceConfig {@Autowired@Qualifier("erpDataSource")private DataSource erpDataSource;@Bean(name = "entityManager")public EntityManager entityManager(EntityManagerFactoryBuilder builder) {return erpEntityManagerFactory(builder).getObject().createEntityManager();}@Bean(name = "erpEntityManagerFactory")public LocalContainerEntityManagerFactoryBean erpEntityManagerFactory (EntityManagerFactoryBuilder builder) {return builder.dataSource(erpDataSource).properties(getVendorProperties(erpDataSource)).packages("com.ehaoyao.paycenter.persistence.pay.entity.erp").persistenceUnit("erpPersistenceUnit").build();}@Autowiredprivate JpaProperties jpaProperties;private Map getVendorProperties(DataSource dataSource) {map.put("hibernate.dialect","org.hibernate.dialect.H2Dialect");map.put("hibernate.hbm2ddl.auto","update");map.put("spring.jpa.show-sql","true");jpaProperties.setProperties(map);return jpaProperties.getHibernateProperties(dataSource);}@Bean(name = "erpTransactionManager")public PlatformTransactionManager transactionManagerPrimary (EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(erpEntityManagerFactory(builder).getObject());}}

踩坑爬坑

指定實體類包的位置

@Primary@Bean(name = "payCenterEntityManagerFactory")public LocalContainerEntityManagerFactoryBeanpayCenterEntityManagerFactory(EntityManagerFactoryBuilder builder) {return builder.dataSource(payCenterDataSource).properties(getVendorProperties(payCenterDataSource)).packages("com.ehaoyao.paycenter.persistence.pay.entity","com.ehaoyao.pay.common.model").persistenceUnit("payCenterPersistenceUnit").build();}

指定多個的話語法為packages("第一個","第二個") 。其中源碼如下: String... 為可變長參數

public EntityManagerFactoryBuilder.Builder packages(String... packagesToScan) {this.packagesToScan = packagesToScan;return this; }

JPA常用注解,及注意事項

  • 使用jpa的save新增數據后,有些數據庫設置了默認值的字段沒有生效,要使其生效可以在對應entity上增加 @DynamicInsert(true)
  • 不想持久化的字段,比如有些字段只是實體類中臨時存儲,或僅為前端展示用,不需要在自動生成的insert、select語句中包含改字段,可以在實體類的改字段上添加 @Transient注解
  • springboot jpa自帶的分頁起始頁為0 ,但是一般前端顯示的時候,都是從1開始的。主動-1,解決方法很low,不知道有沒有好的辦法。
    Pageable pageable = new PageRequest(param.getPageIndex()==0?0:param.getPageIndex()-1, param.getPageSize(), sort); //jpa自帶的分頁是從第0頁開始的,因此這里將傳過來的頁碼-1

  • 使用jpa在生產環境需要注意的配置
ddl-auto:create----每次運行該程序,沒有表格會新建表格,表內有數據會清空ddl-auto:create-drop----每次程序結束的時候會清空表ddl-auto:update----每次運行程序,沒有表格會新建表格,表內有數據不會清空,只會更新ddl-auto:validate----運行程序會校驗數據與數據庫的字段類型是否相同,不同會報錯

jpa支持時間范圍,及動態條件分頁查詢

之前的實例查詢雖然可以支持動態條件,而且使用方便,但是對于一個字段需要傳入多個參數的就不行了,比如 查詢某個時間范
圍內的數據。create between beginDate and endDate 。像這種需求,在真實案例中是很常見的。但是在網上找了一圈之
后,大多數是建議用@Query或者specification來實現。但要是這樣的話,我還不如用mybatis呢。。。。。(而且基本都是這
篇文章的轉載,
嚴重吐槽,百度前幾頁全是這個。。。。。原諒我已經不知道原作者是誰了,隨便貼了一個鏈接,反正都一樣。。)
之前實例查詢代碼如下:

@Overridepublic Page<RefundEntity> getDataList(RefundManEntity param) {ExampleMatcher exampleMatcher =ExampleMatcher.matching().withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING).withMatcher("createTime", ExampleMatcher.GenericPropertyMatchers.startsWith()).withMatcher("orderNume", ExampleMatcher.GenericPropertyMatchers.contains()).withMatcher("refundStatus", ExampleMatcher.GenericPropertyMatchers.contains());RefundEntity refundEntity=new RefundEntity();BeanUtils.copyProperties(param,refundEntity);Example<RefundEntity> example = Example.of(refundEntity, exampleMatcher);Sort sort = new Sort(Sort.Direction.DESC, "id");Pageable pageable = new PageRequest(param.getPageIndex()==0?0:param.getPageIndex()-1, param.getPageSize(), sort); //jpa自帶的分頁是從第0頁開始的,因此這里將傳過來的頁碼-1Page<RefundEntity> pages = refundManageRepository.findAll(example, pageable);return pages;}

我自己的low解決方案,代碼如下:

@Overridepublic Page<RefundEntity> getDataList(RefundManEntity param) {Specification<RefundEntity> querySpecifi = new Specification<RefundEntity>() {@Overridepublic Predicate toPredicate(Root<RefundEntity> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {List<Predicate> predicates = new ArrayList<>();if (StringUtils.isNotBlank(param.getBeginDate())) {//大于或等于傳入時間predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime"). as(String.class),param.getBeginDate()));}if (StringUtils.isNotBlank(param.getEndDate())) {//小于或等于傳入時間predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime").as(String.class), param.getEndDate()));}if (param != null) {Class<? extends RefundManEntity> clazz = param.getClass();Field[] fields = clazz.getDeclaredFields();for (Field tmpField : fields) {tmpField.setAccessible(true);try { //不為空的查詢參數才拼查詢條件,并且要去掉額外加上的時間范圍條件if (tmpField.get(param) != null && !tmpField.getName().equals("beginDate") && !tmpField.getName().equals("endDate")){//只拼字符串查詢條件的,因為目前只需要按照 訂單號、退款狀態來查詢if (tmpField.getType().equals(String.class) && StringUtil.isNotBlank((String)tmpField.get(param))){String name = tmpField.getName();predicates.add(criteriaBuilder.equal(root.get(name), tmpField.get(param)));}}} catch (IllegalAccessException e) {e.printStackTrace();}}}// and到一起的話所有條件就是且關系,or就是或關系return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));}};Sort sort = new Sort(Sort.Direction.DESC, "id");Pageable pageable = new PageRequest(param.getPageIndex() == 0 ? 0 : param.getPageIndex() - 1, param.getPageSize(), sort); //jpa自帶的分頁是從第0頁開始的,因此這里將傳過來的頁碼-1return refundManageRepository.findAll(querySpecifi, pageable);}
  • repository需要多加個繼承
public interface RefundManageRepository extends JpaRepository<RefundEntity,Integer> ,JpaSpecificationExecutor<RefundEntity>{ }
  • 配置主子表,一對多關系
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)@JoinColumn(name="order_id")private List<OrderDetail> orderDetails;
  • 主鍵id配置自動增長
PS:@GeneratedValue注解的strategy屬性提供四種值:–AUTO: 主鍵由程序控制,是默認選項,不設置即此項。–IDENTITY:主鍵由數據庫自動生成,即采用數據庫ID自增長的方式,Oracle不支持這種方式。–SEQUENCE:通過數據庫的序列產生主鍵,通過@SequenceGenerator 注解指定序列名,mysql不支持這種方式。–TABLE:通過特定的數據庫表產生主鍵,使用該策略可以使應用更易于數據庫移植。
  • A different object with the same identifier value was already associated with the session
    實體類中主鍵id字段配置為@GeneratedValue auto,但是數據庫中本身已經有數據了,就會報這個錯。
    從源碼可以看到,序列生成的方式為在數據庫中新增了一個hibernate_sequence 表,這個表中會存儲當前最大id

    把這個id改的比你已存在數據中最大id還大就可以了。

轉載于:https://www.cnblogs.com/falcon-fei/p/11060085.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的springboot+jpa+mybatis 多数据源支持的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。