一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java中ShardingSphere 數(shù)據(jù)分片的實現(xiàn)

Java中ShardingSphere 數(shù)據(jù)分片的實現(xiàn)

2022-01-17 12:02胖虎。。 Java教程

其實很多人對分庫分表多少都有點恐懼,我們今天用ShardingSphere 給大家演示數(shù)據(jù)分片,具有一定的參考價值,感興趣的小伙伴們可以參考一下

 

前言

其實很多人對分庫分表多少都有點恐懼,其實我也是,總覺得這玩意是運維干的、數(shù)據(jù)量上來了或者sql過于復雜、一些數(shù)據(jù)分片的中間件支持的也不是很友好、配置繁瑣等多種問題。

我們今天用ShardingSphere 給大家演示數(shù)據(jù)分片,包括分庫分表、只分表不分庫進行說明。

下一節(jié)有時間的話在講講讀寫分離吧。

github地址:https://github.com/362460453/boot-sharding-JDBC

 

ShardingSphere介紹

ShardingSphere是一套開源的分布式數(shù)據(jù)庫中間件解決方案組成的生態(tài)圈,它由Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar(計劃中)這3款相互獨立的產(chǎn)品組成。 他們均提供標準化的數(shù)據(jù)分片、分布式事務(wù)和數(shù)據(jù)庫治理功能,可適用于如Java同構(gòu)、異構(gòu)語言、容器、云原生等各種多樣化的應(yīng)用場景。

ShardingSphere的功能能幫助我們做什么

  • 數(shù)據(jù)分片
  • 讀寫分離
  • 編排治理
  • 分布式事務(wù)

2016年初Sharding-JDBC被開源,這個產(chǎn)品是當當?shù)模尤肓薃pache 后改名為 ShardingSphere 。他是我們應(yīng)用和數(shù)據(jù)庫之間的中間層,雖代碼入侵性很強,但不會對現(xiàn)有業(yè)務(wù)邏輯進行改變。

更多文檔請點擊官網(wǎng):https://shardingsphere.apache.org/document/current/en/overview/

 

為什么不用mycat

大家如果去查相關(guān)資料會知道,mycat和ShardingSphere是同類型的中間件,主要的功能,數(shù)據(jù)分片和讀寫分離兩個都能去做,但是姿勢卻有很大的差別, 從字面意義上看Sharding 含義是分片、碎片的意思,所以不難理解ShardingSphere 對數(shù)據(jù)分片有很強對能力,對于99%對sql都是支持的,官網(wǎng)也有sql支持的相關(guān)內(nèi)容,大家詳細閱讀,只有 類似sum 這種函數(shù)不支持,而且對 ORM框架和常用數(shù)據(jù)庫基本都兼容,所以個人建議如果你們做數(shù)據(jù)分片,也就是是分庫分表對話,強烈建議選擇ShardingSphere,因為我私下也和一些朋友交流過,mycat 的數(shù)據(jù)分片對多表查詢不是很友好,而且用 mycat 要有很強的運維來做,還有一點就是mycat 都是靠xml配置的,沒有代碼入侵,所以這也算是他的優(yōu)點吧。如果你們只做讀寫分離對話,那么我建議用mycat,是沒問題的。

 

實踐前的準備工作

啟動你的mysql,創(chuàng)建兩個數(shù)據(jù)庫,分別叫 sharding_master 和 sharding_salve分別在這兩個數(shù)據(jù)庫執(zhí)行如下sql

CREATE TABLE IF NOT EXISTS `t_order_0` (
  `order_id` INT NOT NULL,
  `user_id`  INT NOT NULL,
  PRIMARY KEY (`order_id`)
);
CREATE TABLE IF NOT EXISTS `t_order_1` (
  `order_id` INT NOT NULL,
  `user_id`  INT NOT NULL,
  PRIMARY KEY (`order_id`)
);

做完以上兩步結(jié)果如下

Java中ShardingSphere 數(shù)據(jù)分片的實現(xiàn)

 

代碼案例

環(huán)境

工具 版本
jdk

1.8.0_144

springboot 2.0.4.RELEASE
sharding 1.3.1
mysql 5.7

創(chuàng)建一個springboot工程,我們使用 JdbcTemplate 框架,如果用mybatis也是無影響的。

pom引用依賴如下

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>
 
    <properties>
        <java.version>1.8</java.version>
        <druid.version>1.0.26</druid.version>
        <sharding.jdbc.core.version>1.3.3</sharding.jdbc.core.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.dangdang</groupId>
            <artifactId>sharding-jdbc-core</artifactId>
            <version>${sharding.jdbc.core.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>${druid.version}</version>
        </dependency>
    </dependencies>

application.yml 配置如下

server:
  port: 8050
sharding:
  jdbc: 
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/sharding_master?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false
    username: root
    password: 123456
    filters: stat
    maxActive: 100
    initialSize: 1
    maxWait: 15000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 30000
    minEvictableIdleTimeMillis: 180000
    validationQuery: SELECT "x"
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: false
    maxPoolPreparedStatementPerConnectionSize: 20
    removeAbandoned: true
    removeAbandonedTimeout: 600
    logAbandoned: false
    connectionInitSqls: 
    
    url0: jdbc:mysql://localhost:3306/sharding_master?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false
    username0: root
    password0: 123456
    
    url1: jdbc:mysql://localhost:3306/sharding_salve?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&failOverReadOnly=false
    username1: root
    password1: 123456

yml映射成Bean

@Data
@ConfigurationProperties(prefix="sharding.jdbc")
public class ShardDataSourceProperties {
	
	private String driverClassName;
	
	private String url;
	
	private String username;
	
	private String password;
	
	private String url0;
	
	private String username0;
	
	private String password0;
	
	private String url1;
	
	private String username1;
	
	private String password1;
	
	private String filters;
	
	private int maxActive;
	
	private int initialSize;
	
	private int maxWait;
	
	private int minIdle;
	
	private int timeBetweenEvictionRunsMillis;
	
	private int minEvictableIdleTimeMillis;
	
	private String validationQuery;
	
	private boolean testWhileIdle;
	
	private boolean testOnBorrow;
	
	private boolean testOnReturn;
	
	private boolean poolPreparedStatements;
	
	private int maxPoolPreparedStatementPerConnectionSize;
	
	private boolean removeAbandoned;
 
	private int removeAbandonedTimeout;
	
	private boolean logAbandoned;
	
	private List<String> connectionInitSqls;
//省略geter setter

分庫策略

//通過實現(xiàn)SingleKeyDatabaseShardingAlgorithm接口實現(xiàn)分庫
public class ModuloDatabaseShardingAlgorithm implements SingleKeyDatabaseShardingAlgorithm<Integer> {
 
	@Override
	public String doEqualSharding(Collection<String> availableTargetNames, ShardingValue<Integer> shardingValue) {
		for (String each : availableTargetNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new IllegalArgumentException();
	}
 
	@Override
	public Collection<String> doInSharding(Collection<String> availableTargetNames,
			ShardingValue<Integer> shardingValue) {
		Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
        for (Integer value : shardingValue.getValues()) {
            for (String targetName : availableTargetNames) {
                if (targetName.endsWith(value % 2 + "")) {
                    result.add(targetName);
                }
            }
        }
        return result;
	}
 
	@Override
	public Collection<String> doBetweenSharding(Collection<String> availableTargetNames,
			ShardingValue<Integer> shardingValue) {
		Collection<String> result = new LinkedHashSet<>(availableTargetNames.size());
        Range<Integer> range = (Range<Integer>) shardingValue.getValueRange();
        for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
            for (String each : availableTargetNames) {
                if (each.endsWith(i % 2 + "")) {
                    result.add(each);
                }
            }
        }
        return result;
	}
}

分表策略

public class ModuloTableShardingAlgorithm implements SingleKeyTableShardingAlgorithm<Integer> {
 
    /**
     * 對于分片字段的等值操作 都走這個方法。(包括 插入 更新)
     * 如:
     * <p>
     * select * from t_order from t_order where order_id = 11
     * └── SELECT *  FROM t_order_1 WHERE order_id = 11
     * select * from t_order from t_order where order_id = 44
     * └── SELECT *  FROM t_order_0 WHERE order_id = 44
     * </P>
     */
	@Override
    public String doEqualSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {
        for (String each : tableNames) {
            if (each.endsWith(shardingValue.getValue() % 2 + "")) {
                return each;
            }
        }
        throw new IllegalArgumentException();
    }
    
    /**
     * 對于分片字段的in操作,都走這個方法。
    *  select * from t_order from t_order where order_id in (11,44)  
    *          ├── SELECT *  FROM t_order_0 WHERE order_id IN (11,44) 
    *          └── SELECT *  FROM t_order_1 WHERE order_id IN (11,44) 
    *  select * from t_order from t_order where order_id in (11,13,15)  
    *          └── SELECT *  FROM t_order_1 WHERE order_id IN (11,13,15)  
    *  select * from t_order from t_order where order_id in (22,24,26)  
    *          └──SELECT *  FROM t_order_0 WHERE order_id IN (22,24,26) 
    */
	@Override
    public Collection<String> doInSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(tableNames.size());
        for (Integer value : shardingValue.getValues()) {
            for (String tableName : tableNames) {
                if (tableName.endsWith(value % 2 + "")) {
                    result.add(tableName);
                }
            }
        }
        return result;
    }
    
    /**
     * 對于分片字段的between操作都走這個方法。
    *  select * from t_order from t_order where order_id between 10 and 20 
    *          ├── SELECT *  FROM t_order_0 WHERE order_id BETWEEN 10 AND 20 
    *          └── SELECT *  FROM t_order_1 WHERE order_id BETWEEN 10 AND 20 
    */
	@Override
    public Collection<String> doBetweenSharding(final Collection<String> tableNames, final ShardingValue<Integer> shardingValue) {
        Collection<String> result = new LinkedHashSet<>(tableNames.size());
        Range<Integer> range = (Range<Integer>) shardingValue.getValueRange();
        for (Integer i = range.lowerEndpoint(); i <= range.upperEndpoint(); i++) {
            for (String each : tableNames) {
                if (each.endsWith(i % 2 + "")) {
                    result.add(each);
                }
            }
        }
        return result;
    } 
}

對特定表和庫,進行特定的分庫分表規(guī)則

簡單說,就是分庫按照了user_id的奇偶區(qū)分,分表按照order_id 的奇偶區(qū)分,

如果你有多個表進行分片,就寫多個TableRule,

配置兩個數(shù)據(jù)源,分別是我在yml里的配置,根據(jù)你的需求個性化配置就可以。

@Configuration
@EnableConfigurationProperties(ShardDataSourceProperties.class)
public class ShardDataSourceConfig {
 
	@Autowired
	private ShardDataSourceProperties shardDataSourceProperties;
 
	private DruidDataSource parentDs() throws SQLException {
		DruidDataSource ds = new DruidDataSource();
		ds.setDriverClassName(shardDataSourceProperties.getDriverClassName());
		ds.setUsername(shardDataSourceProperties.getUsername());
		ds.setUrl(shardDataSourceProperties.getUrl());
		ds.setPassword(shardDataSourceProperties.getPassword());
		ds.setFilters(shardDataSourceProperties.getFilters());
		ds.setMaxActive(shardDataSourceProperties.getMaxActive());
		ds.setInitialSize(shardDataSourceProperties.getInitialSize());
		ds.setMaxWait(shardDataSourceProperties.getMaxWait());
		ds.setMinIdle(shardDataSourceProperties.getMinIdle());
		ds.setTimeBetweenEvictionRunsMillis(shardDataSourceProperties.getTimeBetweenEvictionRunsMillis());
		ds.setMinEvictableIdleTimeMillis(shardDataSourceProperties.getMinEvictableIdleTimeMillis());
		ds.setValidationQuery(shardDataSourceProperties.getValidationQuery());
		ds.setTestWhileIdle(shardDataSourceProperties.isTestWhileIdle());
		ds.setTestOnBorrow(shardDataSourceProperties.isTestOnBorrow());
		ds.setTestOnReturn(shardDataSourceProperties.isTestOnReturn());
		ds.setPoolPreparedStatements(shardDataSourceProperties.isPoolPreparedStatements());
		ds.setMaxPoolPreparedStatementPerConnectionSize(
				shardDataSourceProperties.getMaxPoolPreparedStatementPerConnectionSize());
		ds.setRemoveAbandoned(shardDataSourceProperties.isRemoveAbandoned());
		ds.setRemoveAbandonedTimeout(shardDataSourceProperties.getRemoveAbandonedTimeout());
		ds.setLogAbandoned(shardDataSourceProperties.isLogAbandoned());
		ds.setConnectionInitSqls(shardDataSourceProperties.getConnectionInitSqls());
		return ds;
	}
 
	private DataSource ds0() throws SQLException {
		DruidDataSource ds = parentDs();
		ds.setUsername(shardDataSourceProperties.getUsername0());
		ds.setUrl(shardDataSourceProperties.getUrl0());
		ds.setPassword(shardDataSourceProperties.getPassword0());
		return ds;
	}
 
	private DataSource ds1() throws SQLException {
		DruidDataSource ds = parentDs();
		ds.setUsername(shardDataSourceProperties.getUsername1());
		ds.setUrl(shardDataSourceProperties.getUrl1());
		ds.setPassword(shardDataSourceProperties.getPassword1());
		return ds;
	}
 
	private DataSourceRule dataSourceRule() throws SQLException {
		Map<String, DataSource> dataSourceMap = new HashMap<>(2);
		dataSourceMap.put("ds_0", ds0());
		dataSourceMap.put("ds_1", ds1());
		DataSourceRule dataSourceRule = new DataSourceRule(dataSourceMap);
		return dataSourceRule;
	}
//對order對策略
	private TableRule orderTableRule() throws SQLException {
		TableRule orderTableRule = TableRule.builder("t_order").actualTables(Arrays.asList("t_order_0", "t_order_1"))
				.dataSourceRule(dataSourceRule()).build();
		return orderTableRule;
	}
 
//分庫分表策略
	private ShardingRule shardingRule() throws SQLException {
		ShardingRule shardingRule = ShardingRule.builder().dataSourceRule(dataSourceRule())
				.tableRules(Arrays.asList(orderTableRule(), orderItemTableRule()))
				.databaseShardingStrategy(
						new DatabaseShardingStrategy("user_id", new ModuloDatabaseShardingAlgorithm()))
				.tableShardingStrategy(new TableShardingStrategy("order_id", new ModuloTableShardingAlgorithm()))
				.build();
		return shardingRule;
	}
 
	@Bean
	public DataSource dataSource() throws SQLException {
		return ShardingDataSourceFactory.createDataSource(shardingRule());
	}
 
 
    @Bean
    public PlatformTransactionManager transactionManager() throws SQLException {
        return new DataSourceTransactionManager(dataSource());
    }
}

我們需要從controller調(diào)用接口進行對數(shù)據(jù)的增加和查詢

下面所有的類都是用來模擬請求進行測試

@RestController
@RequestMapping("/order")
public class OrderController {
    @Autowired
    private OrderDao orderDao;
 
    @RequestMapping(path = "/createOrder/{userId}/{orderId}", method = {RequestMethod.GET})
    public String createOrder(@PathVariable("userId") Integer userId, @PathVariable("orderId") Integer orderId) {
        Order order = new Order();
        order.setOrderId(orderId);
        order.setUserId(userId);
        orderDao.createOrder(order);
        return "success";
    }
 
    @RequestMapping(path = "/{userId}", method = {RequestMethod.GET})
    public List<Order> getOrderListByUserId(@PathVariable("userId") Integer userId) {
        return orderDao.getOrderListByUserId(userId);
    }
}
 
 
---------------------------------------------------
public interface OrderDao {
    List<Order> getOrderListByUserId(Integer userId);
 
    void createOrder(Order order);
}
---------------------------------------------------
@Service
public class OrderDaoImpl implements OrderDao {
    @Autowired
    JdbcTemplate jdbcTemplate;
 
 
    @Override
    public List<Order> getOrderListByUserId(Integer userId) {
 
        StringBuilder sqlBuilder = new StringBuilder();
        sqlBuilder
                .append("select order_id, user_id from t_order where user_id=? ");
        return jdbcTemplate.query(sqlBuilder.toString(), new Object[]{userId},
                new int[]{Types.INTEGER}, new BeanPropertyRowMapper<Order>(
                        Order.class));
    }
 
    @Override
    public void createOrder(Order order) {
        StringBuffer sb = new StringBuffer();
        sb.append("insert into t_order(user_id, order_id)");
        sb.append("values(");
        sb.append(order.getUserId()).append(",");
        sb.append(order.getOrderId());
        sb.append(")");
        jdbcTemplate.update(sb.toString());
 
    }
}
 
---------------------------------------------------
public class Order implements Serializable {
 
	private int userId;
 
	private int orderId;
 
---------------------------------------------------
@SpringBootApplication
public class Application {
	
	public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

測試

啟動項目,訪問:http://localhost:8050/order/createOrder/1/1

更換參數(shù)多次訪問,可以插入多條記錄,觀察你的數(shù)據(jù)庫入庫情況,已經(jīng)按照我們制定的分庫分表策略進行劃分了。

需要注意的是

shareding是不支持jdbctemplate的批量修改操作的。

表名前不要加上庫名,原生的情況加庫名,不加庫名其實是一樣的,但使用shareding的表就會報錯。

Java中ShardingSphere 數(shù)據(jù)分片的實現(xiàn)

如果想進行只分表不分庫的話

  • 注釋掉 ModuloDatabaseShardingAlgorithm 類
  • 還有ShardDataSourceConfig.shardingRule() 中的分庫策略那行代碼
  • 還有相關(guān)數(shù)據(jù)源配置改成 1 個

到此這篇關(guān)于Java中ShardingSphere 數(shù)據(jù)分片的實現(xiàn)的文章就介紹到這了,更多相關(guān)ShardingSphere 數(shù)據(jù)分片內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://blog.csdn.net/weixin_38003389/article/details/90518112

延伸 · 閱讀

精彩推薦
  • Java教程Java實現(xiàn)搶紅包功能

    Java實現(xiàn)搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現(xiàn)搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發(fā)現(xiàn)了對于集合操作轉(zhuǎn)換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關(guān)于Java8中S...

    阿杜7482021-02-04
  • Java教程xml與Java對象的轉(zhuǎn)換詳解

    xml與Java對象的轉(zhuǎn)換詳解

    這篇文章主要介紹了xml與Java對象的轉(zhuǎn)換詳解的相關(guān)資料,需要的朋友可以參考下...

    Java教程網(wǎng)2942020-09-17
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發(fā)項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經(jīng)有好久沒有升過級了。升級完畢重啟之后,突然發(fā)現(xiàn)好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數(shù)據(jù)的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關(guān)于小米推送Java代碼,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩(wěn)中求8032021-07-12
主站蜘蛛池模板: 国产在线视频在线观看 | 精品综合在线 | 男人午夜免费视频 | 91制片在线观看 | 99久久香蕉国产综合影院 | 99热这里有免费国产精品 | 国产福利一区二区在线精品 | 亚洲国产情侣一区二区三区 | blacked黑人| 国产在线乱子伦一区二区 | 国产未成女年一区二区 | 国产成人精品视频一区二区不卡 | 99久久精品国语对白 | 大象传媒2021秘密入口 | 天堂一区二区在线观看 | 好男人资源免费播放在线观看 | 美女扒开两腿露出尿口的视频 | 精品国产综合 | 亚洲午夜精品久久久久久成年 | 国产精品免费网站 | 九九99靖品| 国产精品模特hd在线 | 欧美日韩色图 | 亚洲 日韩 在线 国产 视频 | 久久中文字幕综合不卡一二区 | 国产一区二区三区高清视频 | 日本高清中文 | yy6080久久国产伦理 | 日韩成本大片35分钟免费播放 | 午夜小视频网站 | 国产一区二区在线观看美女 | 午夜一区二区福利视频在线 | 亚洲上最大成网人站4438 | 久久亚洲精品专区蓝色区 | yellow视频在线观看 | 日韩制服丝袜在线观看 | 国亚洲欧美日韩精品 | 无码AV免费精品一区二区三区 | 欧美a一片xxxx片与善交 | 国产成人亚洲精品91专区手机 | 91大神第九部红酒气质女 |