前言
在開始之前,不得不吐槽下,全網的Sharding-JDBC的資料太少了,而且大部分資料都是1.X的版本,那是很早的版本,現在Sharding-JDBC已經發展到4.X啦。還有就是大部分都停留在說概念的層面,來回講Sharding-JDBC的一些基礎概念,實戰的demo少之又少,這還有些demo根本跑不起來。我就想問一下,親們到底自己有沒有跑過啊?哎,我真的是太難了。
所以我就來寫個demo把,拋磚引玉下,希望各位大佬補充。如果有不想看搭建過程的,可以直接看最後的GitHub地址,拉取代碼測試下。
需求說明
本demo使用Sharding-JDBC完成對訂單表,訂單明細表的水平分庫水錶,首先我們需要注意人工創建兩個庫,分別是ds0和ds1,然後再在這兩個庫裏面各新建四個表t_order0,t_order1,t_order_item0,t_order_item1,具體的建表SQL語句參考項目中的sharding-tbl-ms.sql。
環境搭建
數據庫:MySQL 5.1
JDK:64位jdk1.8
應用框架:spring-boot-2.0.3 ,Mybatis 3.4
Sharding-JDBC:sharding-jdbc-spring-boot-starter 3.1.0.M1
分片配置
在application.properties配置文件中,如果不知道每項代表什麼,咱先不管,demo先跑起來再說,各個配置在接下來的文章逐一說明。
#兩個庫名 sharding.jdbc.datasource.names=ds0,ds1 #第一個庫的配置信息 sharding.jdbc.datasource.ds0.type=org.apache.commons.dbcp.BasicDataSource sharding.jdbc.datasource.ds0.driver-class-name=com.mysql.jdbc.Driver sharding.jdbc.datasource.ds0.url=jdbc:mysql://localhost:3306/ds0 sharding.jdbc.datasource.ds0.username=root sharding.jdbc.datasource.ds0.password=root #第一個庫的配置信息 sharding.jdbc.datasource.ds1.type=org.apache.commons.dbcp.BasicDataSourcesharding.jdbc.datasource.ds1.driver-class-name=com.mysql.jdbc.Driver sharding.jdbc.datasource.ds1.url=jdbc:mysql://localhost:3306/ds1 sharding.jdbc.datasource.ds1.username=root sharding.jdbc.datasource.ds1.password=root #訂單表的配置信息 sharding.jdbc.config.sharding.tables.t_order.actual-data-nodes=ds$->{0..1}.t_order$->{0..1} sharding.jdbc.config.sharding.tables.t_order.table-strategy.inline.sharding-column=order_id sharding.jdbc.config.sharding.tables.t_order.table-strategy.inline.algorithm-expression=t_order$->{order_id % 2} sharding.jdbc.config.sharding.tables.t_order.key-generator-column-name=order_id #訂單明細表的配置信息 sharding.jdbc.config.sharding.tables.t_order_item.actual-data-nodes=ds$->{0..1}.t_order_item$->{0..1} sharding.jdbc.config.sharding.tables.t_order_item.table-strategy.inline.sharding-column=order_id sharding.jdbc.config.sharding.tables.t_order_item.table-strategy.inline.algorithm-expression=t_order_item$->{order_id % 2} sharding.jdbc.config.sharding.tables.t_order_item.key-generator-column-name=order_item_id #訂單表和訂單明細表的綁定關係 sharding.jdbc.config.sharding.binding-tables=t_order,t_order_item sharding.jdbc.config.sharding.broadcast-tables=t_config #默認配置 sharding.jdbc.config.sharding.default-database-strategy.inline.sharding-column=user_id sharding.jdbc.config.sharding.default-database-strategy.inline.algorithm-expression=ds$->{user_id % 2}
代碼編寫
爲了減少篇幅,代碼只是簡單貼了些,這部分代碼其實就是spring-boot和mybatis整合的,這部分明白的直接跳過即可。
定義實體(Order和OrderItem)
public class Order implements Serializable { private static final long serialVersionUID = 661434701950670670L; private long orderId; private int userId; private String status; private List<OrderItem> items=new ArrayList<>(); //setter和getter方法 ..... @Override public String toString() { return String.format("order_id: %s, user_id: %s, status: %s", orderId, userId, status); } }
public class OrderItem implements Serializable { private static final long serialVersionUID = 263434701950670170L; private long orderItemId; private long orderId; private int userId; private String status; //setter和getter方法 ..... @Override public String toString() { return String.format("order_item_id:%s, order_id: %s, user_id: %s, status: %s", orderItemId, orderId, userId, status); } }
mapper映射(OrderMapper.xml和OrderItemMapper.xml)
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.forezp.sharedingjdbcmasterslavetables.repository.OrderRepository"> <resultMap id="baseResultMap" type="com.forezp.sharedingjdbcmasterslavetables.entity.Order"> <result column="order_id" property="orderId" jdbcType="INTEGER"/> <result column="user_id" property="userId" jdbcType="INTEGER"/> <result column="status" property="status" jdbcType="VARCHAR"/> </resultMap> <resultMap type="Order" id="orderMap"> <id column="order_id" property="orderId"/> <result column="user_id" property="userId"/> <result column="status" property="status"/> <collection property="items" ofType="OrderItem"> <id column="order_item_id" property="orderItemId"/><!-- 這裏的column對應的是下面查詢的別名,而不是表字段名 --> <result column="user_id" property="userId"/><!-- property對應JavaBean中的屬性名 --> <result column="status" property="status"/> </collection> </resultMap> <insert id="addOrder" useGeneratedKeys="true" keyProperty="orderId"> INSERT INTO t_order (user_id, status) VALUES (#{userId,jdbcType=INTEGER}, #{status,jdbcType=VARCHAR}); </insert> <select id="list" resultMap="baseResultMap"> SELECT * FROM t_order; </select> <select id="get" resultMap="orderMap"> SELECT * FROM t_order,t_order_item where t_order.order_id=t_order_item.order_id and t_order.order_id=#{orderId,jdbcType=INTEGER}; </select> </mapper>
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.forezp.sharedingjdbcmasterslavetables.repository.OrderItemRepository"> <resultMap id="baseResultMap" type="com.forezp.sharedingjdbcmasterslavetables.entity.OrderItem"> <result column="order_item_id" property="orderItemId" jdbcType="INTEGER"/> <result column="order_id" property="orderId" jdbcType="INTEGER"/> <result column="user_id" property="userId" jdbcType="INTEGER"/> <result column="status" property="status" jdbcType="VARCHAR"/> </resultMap> <insert id="addOrderItem" useGeneratedKeys="true" keyProperty="orderItemId"> INSERT INTO t_order_item (order_id,user_id, status) VALUES (#{orderId,jdbcType=INTEGER},#{userId,jdbcType=INTEGER}, #{status,jdbcType=VARCHAR}); </insert> </mapper>
dao(OrderRepository和OrderItemRepository)
@Mapper public interface OrderRepository { Long addOrder(Order order); List<Order> list(); Object get(Long id); }
@Mapper public interface OrderItemRepository { Integer addOrderItem(OrderItem orderitem); }
service接口(OrderServiceImpl)
@Service public class OrderServiceImpl implements OrderService { @Autowired OrderRepository orderRepository; @Autowired OrderItemRepository orderItemRepository; @Override public Long addOrder(Order order) { orderRepository.addOrder(order); OrderItem orderItem=new OrderItem(); orderItem.setOrderId(order.getOrderId()); orderItem.setUserId(order.getUserId()); orderItem.setStatus("insert"); orderItemRepository.addOrderItem(orderItem); return order.getOrderId(); } @Override public List<Order> list() { return orderRepository.list(); } @Override public Object get(Long id){ return orderRepository.get(id); } }
controller(OrderController)
@RestController public class OrderController { Logger logger= LoggerFactory.getLogger(OrderController.class); @Autowired private OrderService orderService; @GetMapping("/orders") public Object list() { return orderService.list(); } @GetMapping("/add") public Object add() { for(int i=100;i<150;i++) { Order order = new Order(); order.setUserId(i); order.setStatus("insert"); long resutl= orderService.addOrder(order); logger.info("insert:"+order.toString()+" result:"+resutl); } return "ok"; } @GetMapping("/get") public Object get() { return orderService.get(386632135886241793L); } }
最終測試
我們打開瀏覽器,輸入localhost:8080/add,即可返回ok,說明我們數據插入成功啦。
那我們先到數據庫裏面看看,發現數據被髮配在了ds0庫和ds1庫中,但是問題在於爲什麼都在t_order1表中,沒有在t_order0表中,也就是爲什麼在庫裏面沒有按order_id分表呢?其實問題不是在這,而是生成的訂單id爲什麼是都是奇數?哈哈哈,請聽下回分解。易中天上線啦。。
其他的查詢等方法也都寫了,大家可以自己試試哈。
GitHub地址
GitHub:
https://github.com/sunnysabor/script-java/tree/release/sharding_jdbc
注意
:
1.需要自己手動建庫,建表,具體的建表語句在sharding-tbl-ms.sql中。兩個庫都要執行一遍。
2.數據庫的連接配置參考本地的數據庫,注意修改配置中的賬號密碼。
結語
關注偶,領取超多學習資料哈。