最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

springboot jpa分庫分表項目實現(xiàn)過程詳解

 更新時間:2020年01月16日 09:35:26   作者:森林木馬  
這篇文章主要介紹了springboot jpa分庫分表項目實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

這篇文章主要介紹了springboot jpa分庫分表項目實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

分庫分表場景

關(guān)系型數(shù)據(jù)庫本身比較容易成為系統(tǒng)瓶頸,單機存儲容量、連接數(shù)、處理能力都有限。當單表的數(shù)據(jù)量達到1000W或100G以后,由于查詢維度較多,即使添加從庫、優(yōu)化索引,做很多操作時性能仍下降嚴重。此時就要考慮對其進行切分了,切分的目的就在于減少數(shù)據(jù)庫的負擔,縮短查詢時間。

分庫分表用于應(yīng)對當前互聯(lián)網(wǎng)常見的兩個場景——大數(shù)據(jù)量和高并發(fā)。通常分為垂直拆分和水平拆分兩種。

垂直拆分是根據(jù)業(yè)務(wù)將一個庫(表)拆分為多個庫(表)。如:將經(jīng)常和不常訪問的字段拆分至不同的庫或表中。由于與業(yè)務(wù)關(guān)系密切,目前的分庫分表產(chǎn)品均使用水平拆分方式。

水平拆分則是根據(jù)分片算法將一個庫(表)拆分為多個庫(表)。如:按照ID的最后一位以3取余,尾數(shù)是1的放入第1個庫(表),尾數(shù)是2的放入第2個庫(表)等。

單純的分表雖然可以解決數(shù)據(jù)量過大導(dǎo)致檢索變慢的問題,但無法解決過多并發(fā)請求訪問同一個庫,導(dǎo)致數(shù)據(jù)庫響應(yīng)變慢的問題。所以通常水平拆分都至少要采用分庫的方式,用于一并解決大數(shù)據(jù)量和高并發(fā)的問題。這也是部分開源的分片數(shù)據(jù)庫中間件只支持分庫的原因。

但分表也有不可替代的適用場景。最常見的分表需求是事務(wù)問題。同在一個庫則不需考慮分布式事務(wù),善于使用同庫不同表可有效避免分布式事務(wù)帶來的麻煩。目前強一致性的分布式事務(wù)由于性能問題,導(dǎo)致使用起來并不一定比不分庫分表快。目前采用最終一致性的柔性事務(wù)居多。分表的另一個存在的理由是,過多的數(shù)據(jù)庫實例不利于運維管理。綜上所述,最佳實踐是合理地配合使用分庫+分表。

Sharding-JDBC簡介

Sharding-JDBC是當當應(yīng)用框架ddframe中,從關(guān)系型數(shù)據(jù)庫模塊dd-rdb中分離出來的數(shù)據(jù)庫水平分片框架,實現(xiàn)透明化數(shù)據(jù)庫分庫分表訪問。Sharding-JDBC是繼dubbox和elastic-job之后,ddframe系列開源的第3個項目。

定位為輕量級Java框架,在Java的JDBC層提供的額外服務(wù)。 它使用客戶端直連數(shù)據(jù)庫,以jar包形式提供服務(wù),無需額外部署和依賴,可理解為增強版的JDBC驅(qū)動,完全兼容JDBC和各種ORM框架。

  • 適用于任何基于Java的ORM框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template或直接使用JDBC。
  • 基于任何第三方的數(shù)據(jù)庫連接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP等。
  • 支持任意實現(xiàn)JDBC規(guī)范的數(shù)據(jù)庫。目前支持MySQL,Oracle,SQLServer和PostgreSQL。
  • Sharding-JDBC分片策略靈活,可支持等號、between、in等多維度分片,也可支持多分片鍵。

SQL解析功能完善,支持聚合、分組、排序、limit、or等查詢,并支持Binding Table以及笛卡爾積表查詢。

項目實踐

數(shù)據(jù)準備

準備兩個數(shù)據(jù)庫。并在兩個庫中建好表, 建表sql如下:

DROP TABLE IF EXISTS `user_auth_0`;
CREATE TABLE `user_auth_0` (
 `user_id` bigint(20) NOT NULL,
 `add_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `email` varchar(16) DEFAULT NULL,
 `password` varchar(255) DEFAULT NULL,
 `phone` varchar(16) DEFAULT NULL,
 `remark` varchar(16) DEFAULT NULL,
 PRIMARY KEY (`user_id`),
 UNIQUE KEY `USER_AUTH_PHONE` (`phone`),
 UNIQUE KEY `USER_AUTH_EMAIL` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
 
 
DROP TABLE IF EXISTS `user_auth_1`;
CREATE TABLE `user_auth_1` (
 `user_id` bigint(20) NOT NULL,
 `add_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
 `email` varchar(16) DEFAULT NULL,
 `password` varchar(255) DEFAULT NULL,
 `phone` varchar(16) DEFAULT NULL,
 `remark` varchar(16) DEFAULT NULL,
 PRIMARY KEY (`user_id`),
 UNIQUE KEY `USER_AUTH_PHONE` (`phone`),
 UNIQUE KEY `USER_AUTH_EMAIL` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

POM配置

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- 引入jpa-->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <!-- 引入mysql-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <!-- druid -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.9</version>
    </dependency>
    <!-- sharding-jdbc -->
    <dependency>
      <groupId>com.dangdang</groupId>
      <artifactId>sharding-jdbc-core</artifactId>
      <version>1.5.4</version>
    </dependency>
    <!-- fastjson -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.51</version>
    </dependency>

application.yml配置

spring:
 jpa:
  properties:
   hibernate:
    dialect: org.hibernate.dialect.MySQL5InnoDBDialect
  show-sql: true
database0:
 driverClassName: com.mysql.jdbc.Driver
 url: jdbc:mysql://localhost:3306/mazhq?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
 username: root
 password: 123456
 databaseName: mazhq

database1:
 driverClassName: com.mysql.jdbc.Driver
 url: jdbc:mysql://localhost:3306/liugh?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
 username: root
 password: 123456
 databaseName: liugh

分庫分表最主要有幾個配置

1. 有多少個數(shù)據(jù)源 (2個:database0和database1)

@Data
@ConfigurationProperties(prefix = "database0")
@Component
public class Database0Config {
  private String url;
  private String username;
  private String password;
  private String driverClassName;
  private String databaseName;
 
  public DataSource createDataSource() {
    DruidDataSource result = new DruidDataSource();
    result.setDriverClassName(getDriverClassName());
    result.setUrl(getUrl());
    result.setUsername(getUsername());
    result.setPassword(getPassword());
    return result;
  }
}

2. 用什么列進行分庫以及分庫算法 (一般是用具體值對2取余判斷入哪個庫,我采用的是判斷值是否大于20)

@Component
public class DatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Long> {
  @Autowired
  private Database0Config database0Config;
  @Autowired
  private Database1Config database1Config;
  @Override
  public String doEqualSharding(Collection<String> collection, ShardingValue<Long> shardingValue) {
    Long value = shardingValue.getValue();
    if (value <= 20L) {
      return database0Config.getDatabaseName();
    } else {
      return database1Config.getDatabaseName();
    }
  }
 
  @Override
  public Collection<String> doInSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
    Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
    for (Long value : shardingValue.getValues()) {
      if (value <= 20L) {
        result.add(database0Config.getDatabaseName());
      } else {
        result.add(database1Config.getDatabaseName());
      }
    }
    return result;
  }
 
  @Override
  public Collection<String> doBetweenSharding(Collection<String> availableTargetNames, ShardingValue<Long> shardingValue) {
    Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
    Range<Long> range = shardingValue.getValueRange();
    for (Long value = range.lowerEndpoint(); value <= range.upperEndpoint(); value++) {
      if (value <= 20L) {
        result.add(database0Config.getDatabaseName());
      } else {
        result.add(database1Config.getDatabaseName());
      }
    }
    return result;
  }
}

3. 用什么列進行分表以及分表算法

@Component
public class TableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Long> {
  @Override
  public String doEqualSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
    for (String each : tableNames) {
      if (each.endsWith(shardingValue.getValue() % 2 + "")) {
        return each;
      }
    }
    throw new IllegalArgumentException();
  }
 
  @Override
  public Collection<String> doInSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
    Collection<String> result = new LinkedHashSet<>(tableNames.size());
    for (Long value : shardingValue.getValues()) {
      for (String tableName : tableNames) {
        if (tableName.endsWith(value % 2 + "")) {
          result.add(tableName);
        }
      }
    }
    return result;
  }
 
  @Override
  public Collection<String> doBetweenSharding(Collection<String> tableNames, ShardingValue<Long> shardingValue) {
    Collection<String> result = new LinkedHashSet<>(tableNames.size());
    Range<Long> range = shardingValue.getValueRange();
    for (Long i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
      for (String each : tableNames) {
        if (each.endsWith(i % 2 + "")) {
          result.add(each);
        }
      }
    }
    return result;
  }
}

4. 每張表的邏輯表名和所有物理表名和集成調(diào)用

@Configuration
public class DataSourceConfig {
  @Autowired
  private Database0Config database0Config;
 
  @Autowired
  private Database1Config database1Config;
 
  @Autowired
  private DatabaseShardingAlgorithm databaseShardingAlgorithm;
 
  @Autowired
  private TableShardingAlgorithm tableShardingAlgorithm;
 
  @Bean
  public DataSource getDataSource() throws SQLException {
    return buildDataSource();
  }
 
  private DataSource buildDataSource() throws SQLException {
    //分庫設(shè)置
    Map<String, DataSource> dataSourceMap = new HashMap<>(2);
    //添加兩個數(shù)據(jù)庫database0和database1
    dataSourceMap.put(database0Config.getDatabaseName(), database0Config.createDataSource());
    dataSourceMap.put(database1Config.getDatabaseName(), database1Config.createDataSource());
    //設(shè)置默認數(shù)據(jù)庫
    DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap, database0Config.getDatabaseName());
 
    //分表設(shè)置,大致思想就是將查詢虛擬表Goods根據(jù)一定規(guī)則映射到真實表中去
    TableRule orderTableRule = TableRule.builder("user_auth")
        .actualTables(Arrays.asList("user_auth_0", "user_auth_1"))
        .dataSourceRule(dataSourceRule)
        .build();
 
    //分庫分表策略
    ShardingRule shardingRule = ShardingRule.builder()
        .dataSourceRule(dataSourceRule)
        .tableRules(Arrays.asList(orderTableRule))
        .databaseShardingStrategy(new DatabaseShardingStrategy("user_id", databaseShardingAlgorithm))
        .tableShardingStrategy(new TableShardingStrategy("user_id", tableShardingAlgorithm)).build();
    DataSource dataSource = ShardingDataSourceFactory.createDataSource(shardingRule);
    return dataSource;
  }
  @Bean
  public KeyGenerator keyGenerator() {
    return new DefaultKeyGenerator();
  }

接口測試代碼

1、實體類

/**
 * @author mazhq
 * @date 2019/7/30 16:41
 */
@Entity
@Data
@Table(name = "USER_AUTH", uniqueConstraints = {@UniqueConstraint(name = "USER_AUTH_PHONE", columnNames = {"PHONE"}),
@UniqueConstraint(name = "USER_AUTH_EMAIL", columnNames = {"EMAIL"})})
public class UserAuthEntity implements Serializable {
  private static final long serialVersionUID = 7230052310725727465L;
  @Id
  private Long userId;
  @Column(name = "PHONE", length = 16)
  private String phone;
  @Column(name = "EMAIL", length = 16)
  private String email;
  private String password;
  @Column(name = "REMARK",length = 16)
  private String remark;
  @Column(name = "ADD_DATE", nullable = false, columnDefinition = "datetime default now()")
  private Date addDate;
}

2. Dao層

@Repository
public interface UserAuthDao extends JpaRepository<UserAuthEntity, Long> {
}

3. controller層

/**
 * @author mazhq
 * @Title: UserAuthController
 * @date 2019/8/1 17:18
 */
@RestController
@RequestMapping("/user")
public class UserAuthController {
  @Autowired
  private UserAuthDao userAuthDao;
 
  @PostMapping("/save")
  public String save(){
    for (int i=0;i<40;i++) {
      UserAuthEntity userAuthEntity = new UserAuthEntity();
      userAuthEntity.setUserId((long)i);
      userAuthEntity.setAddDate(new Date());
      userAuthEntity.setEmail("test"+i+"@163.com");
      userAuthEntity.setPassword("123456");
      userAuthEntity.setPhone("1388888888"+i);
      Random r = new Random();
      userAuthEntity.setRemark(""+r.nextInt(100));
      userAuthDao.save(userAuthEntity);
    }
    return "success";
  }
 
  @PostMapping("/select")
  public String select(){
    return JSONObject.toJSONString(userAuthDao.findAll(Sort.by(Sort.Order.desc("remark"))));
  }
}  

測試方式:

先調(diào)用:http://localhost:8080/user/save

再查詢:http://localhost:8080/user/select

git地址:sharding

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • IDEA啟動報錯Internal?error.?Please?refer?to?https://jb.gg/ide/critical-startup-errors解決辦法

    IDEA啟動報錯Internal?error.?Please?refer?to?https://jb.gg/i

    這篇文章主要介紹了IDEA啟動報錯Internal?error.?Please?refer?to?https://jb.gg/ide/critical-startup-errors解決辦法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • springboot調(diào)用支付寶第三方接口(沙箱環(huán)境)

    springboot調(diào)用支付寶第三方接口(沙箱環(huán)境)

    這篇文章主要介紹了springboot+調(diào)用支付寶第三方接口(沙箱環(huán)境),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • java token生成和校驗的實例代碼

    java token生成和校驗的實例代碼

    這篇文章主要介紹了java token生成和校驗的實例代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • 了解JAVA Future類

    了解JAVA Future類

    Future是并發(fā)編程中的一種設(shè)計模式,F(xiàn)uture它代表一個異步計算的結(jié)果,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,下面小編和大家來一起學(xué)習(xí)一下吧
    2019-06-06
  • java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.setXmlVersion問題解決方法

    java.lang.AbstractMethodError: org.apache.xerces.dom.Documen

    這篇文章主要介紹了java.lang.AbstractMethodError: org.apache.xerces.dom.DocumentImpl.setXmlVersion問題解決方法,導(dǎo)致本文問題的原因是缺少一個xerces.jar jar包,需要的朋友可以參考下
    2015-03-03
  • 解決 java.lang.NoSuchMethodError的錯誤

    解決 java.lang.NoSuchMethodError的錯誤

    這篇文章主要介紹了解決 java.lang.NoSuchMethodError的錯誤的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • RocketMQ中的消費者啟動流程解讀

    RocketMQ中的消費者啟動流程解讀

    這篇文章主要介紹了RocketMQ中的消費者啟動流程解讀,RocketMQ是一款高性能、高可靠性的分布式消息中間件,消費者是RocketMQ中的重要組成部分,消費者負責從消息隊列中獲取消息并進行處理,需要的朋友可以參考下
    2023-10-10
  • Caused?by:?java.lang.NumberFormatException:?For?input?string:?“port“(問題解決)

    Caused?by:?java.lang.NumberFormatException:?For?input?s

    這篇文章主要介紹了Caused?by:?java.lang.NumberFormatException:?For?input?string:?“port“,本文給大家分享完美解決方法,需要的朋友可以參考下
    2023-01-01
  • SSH框架網(wǎng)上商城項目第16戰(zhàn)之Hibernate二級緩存處理首頁熱門顯示

    SSH框架網(wǎng)上商城項目第16戰(zhàn)之Hibernate二級緩存處理首頁熱門顯示

    這篇文章主要介紹了SSH框架網(wǎng)上商城項目第16戰(zhàn)之Hibernate的二級緩存處理首頁的熱門顯示,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Java實現(xiàn)多選批量刪除功能(vue+Element)

    Java實現(xiàn)多選批量刪除功能(vue+Element)

    這篇文章主要為大家詳細介紹了Java實現(xiàn)多選批量刪除功能,包括前端vue實現(xiàn)代碼文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論

宾阳县| 满洲里市| 鹿泉市| 阳高县| 冕宁县| 霍城县| 民县| 静宁县| 娄底市| 子长县| 白山市| 永兴县| 无极县| 龙井市| 紫阳县| 吕梁市| 香格里拉县| 濮阳县| 丹江口市| 胶南市| 龙山县| 临江市| 湘西| 元氏县| 保靖县| 泊头市| 清河县| 宝坻区| 孝感市| 彭泽县| 区。| 蒙自县| 大新县| 荆门市| 库车县| 射洪县| 新乐市| 德化县| 唐山市| 芜湖县| 酉阳|