ORM框架对分表分库的实现

 

AntData ORM框架是我维护的一个开源ORM框架

https://github.com/yuzd/AntData.ORM

该框架是在Linq2db这个优秀的linq转sql引擎基础上进行改造而来的。

分离了linq2sql引擎和db执行逻辑。

画一个图的话 应该是这样的:

ORM框架对分表分库的实现_第1张图片

分表分库功能设计

框架内置目前使用比较多的两种分片模式:

  • 取模 (mod)
  • 范围 (range)

为了让框架更容易扩展

  • 开放分片策略的接口 当有自定义分片规则可以继承实现

下面我用内置的 取模 分片模式来说明 ,运行环境: netcore平台

1. DB Sharding

db配置:

  • Provider 指定为 mysql
  • Name 是逻辑名称 可以随意指定
  • ShardingStrategy 指定分片的逻辑处理
  • ConnectionItemList 指定一个或多个db链接配置

ORM框架对分表分库的实现_第2张图片

注意:

class=AntData.DbEngine.Sharding.ModShardingStrategy;column=ID;mod=2;shardByDB=true

的意思是:

采用内置的取模分片法,走分片的字段叫ID mod为2 也就是1分为2个 分别是 (0 和 1),所以下面的ConnectionItemList指定的 Sharding分别是0和1的数据库连接

按照上面的配置的话,当满足

  • 表还有字段ID
  • db搜索的条件含有id字段,或者 db更新的条件含有id字段 或者db删除的条件含有id字段

都应该走取模算法来走对应的db。

下面来测试它

DB Sharding 使用场景举例说明


        /// 
        /// 测试mod分库插入到testorm2数据库
        /// 
        [TestMethod]
        public void TestMethod6_01()
        {
            //id查询 1 mod 2 = 1 所以会走到 testorm2数据库
            var id = 1;
            var odIsExist = DB.Tables.Orders.Any(r => r.ID.Equals(1));
            if (odIsExist)
            {
                return;
            }
            var order = new Order
            {
                ID = 1,
                Name = "上海大学"
            };

            var result = DB.Insert(order);
            Assert.AreEqual(result, 1);

        }
        

        /// 
        /// 测试mod分库插入到testorm1数据库
        /// 
        [TestMethod]
        public void TestMethod6_02()
        {

            var id = 2;
            var odIsExist = DB.Tables.Orders.Any(r => r.ID.Equals(2));
            if (odIsExist)
            {
                return;
            }
            var order = new Order
            {
                ID = 2,
                Name = "北京大学"
            };

            var result = DB.Insert(order);
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分库 查询testorm2数据库
        /// 
        [TestMethod]
        public void TestMethod6_03()
        {
            var id = 1;
            var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(1));
            Assert.IsNotNull(tb1);
        }

        /// 
        /// 测试mod分库 查询testorm1数据库
        /// 
        [TestMethod]
        public void TestMethod6_04()
        {
            var id = 2;
            var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(2));
            Assert.IsNotNull(tb1);
        }

        /// 
        /// 测试mod分库 不指定sharing column 查询叠加
        /// 
        [TestMethod]
        public void TestMethod6_05()
        {
            var tb1 = DB.Tables.Orders.ToList();
            Assert.IsNotNull(tb1);
            Assert.AreEqual(tb1.Count, 2);

            var odIsExist = DB.Tables.Orders.Where(r => r.ID.Equals(1) || r.ID.Equals(2)).ToList();
            Assert.AreEqual(odIsExist.Count, 2);
        }

        /// 
        /// 测试mod分库修改到testorm2数据库
        /// 
        [TestMethod]
        public void TestMethod6_06()
        {
            var id = 1;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(1)).Set(r => r.Name, y => y.Name + "1").Update();
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分库修改到testorm1数据库
        /// 
        [TestMethod]
        public void TestMethod6_07()
        {
            var id = 2;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(2)).Set(r => r.Name, y => y.Name + "1").Update();
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分库删除到testorm2数据库
        /// 
        [TestMethod]
        public void TestMethod6_08()
        {
            var id = 1;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(1)).Delete();
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分库删除到testorm1数据库
        /// 
        [TestMethod]
        public void TestMethod6_09()
        {
            var id = 2;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(2)).Delete();
            Assert.AreEqual(result, 1);
        }

        [TestMethod]
        public void TestMethod7_01()
        {
            var id = 2;

            //var odIsExist = DB.Tables.Orders.Any(r => r.ID.Equals(id));

            var odIsExist = DB.Tables.Orders.Any(r => r.ID.Equals(2));
            if (odIsExist)
            {
                return;
            }


        }

        /// 
        /// 测试mod分库批量分别插入到testorm1  testorm2数据库
        /// 
        [TestMethod]
        public void TestMethod7_02()
        {
            var orderList = new List();
            orderList.Add(new Order
            {
                ID = 3,
                Name = "上海大学"
            });
            orderList.Add(new Order
            {
                ID = 4,
                Name = "上海大学"
            });
            //没有指定 shading column的话是默认分到第一个分片
            orderList.Add(new Order
            {
                ID = null,
                Name = "上海大学"
            });
            var rows = DB.BulkCopy(orderList);
            Assert.AreEqual(rows.RowsCopied, 3);
        }

        /// 
        /// 不指定sharing column 删除会叠加
        /// 
        [TestMethod]
        public void TestMethod7_03()
        {
            var odIsExist = DB.Tables.Orders.Delete();
            Assert.AreEqual(odIsExist, 3);

        }


2. Table Sharding

  • Provider 指定为 mysql
  • Name 是逻辑名称 可以随意指定
  • ShardingStrategy 指定分片的逻辑处理
  • ConnectionItemList 指定一个db链接配置

ORM框架对分表分库的实现_第3张图片

针对分表要对 dbmodels 做一个小修改

ORM框架对分表分库的实现_第4张图片

class=AntData.DbEngine.Sharding.ModShardingStrategy;column=ID;mod=2;tableSharding=0,1;shardByDB=false;shardByTable=true

的意思是:

采用内置的取模分片法,走分片的字段叫ID mod为2 也就是1分为2个 分别是 (0 和 1),所以下面的ConnectionItemList指定的 Sharding分别是order_0和order_1的数据

按照上面的配置的话,当满足

  • 表还有字段ID
  • db搜索的条件含有id字段,或者 db更新的条件含有id字段 或者db删除的条件含有id字段

都应该走取模算法来走对应的table。

下面来测试它

Table Sharding 使用场景举例说明


        /// 
        /// 测试mod分表插入到testorm3数据库的orders_1表里面
        /// 
        [TestMethod]
        public void TestMethod1_01()
        {
            var id = 1;
            var odIsExist = DB.Tables.Orders.Any(r => r.ID.Equals(id));
            if (odIsExist)
            {
                return;
            }

            var order = new Orders
            {
                ID = id,
                Name = "订单1"
            };

            var result = DB.Insert(order);
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分表插入到testorm3数据库的orders_0表里面
        /// 
        [TestMethod]
        public void TestMethod1_02()
        {
            var id = 2;
            var odIsExist = DB.Tables.Orders.Any(r => r.ID.Equals(id));
            if (odIsExist)
            {
                return;
            }
            var order = new Orders
            {
                ID = id,
                Name = "订单2"
            };

            var result = DB.Insert(order);
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分表 查询testorm3数据库orders_1
        /// 
        [TestMethod]
        public void TestMethod1_03()
        {
            var id = 1;
            var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(id));
            Assert.IsNotNull(tb1);
        }

        /// 
        /// 测试mod分表 查询testorm3数据库orders_0
        /// 
        [TestMethod]
        public void TestMethod1_04()
        {
            var id = 2;
            var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(id));
            Assert.IsNotNull(tb1);
        }


        /// 
        /// 测试mod分表 不指定sharing column 查询叠加
        /// 
        [TestMethod]
        public void TestMethod1_05()
        {
            var tb1 = DB.Tables.Orders.ToList();
            Assert.IsNotNull(tb1);
            Assert.AreEqual(tb1.Count, 2);

            var odIsExist = DB.Tables.Orders.Where(r => r.ID.Equals(1) || r.ID.Equals(2)).ToList();
            Assert.AreEqual(odIsExist.Count, 2);
        }

        /// 
        /// 测试mod分表修改到testorm3数据库orders_1
        /// 
        [TestMethod]
        public void TestMethod1_06()
        {
            var id = 1;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(id)).Set(r => r.Name, y => y.Name + "1").Update();
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分表修改到testorm3数据库orders_0
        /// 
        [TestMethod]
        public void TestMethod1_07()
        {
            var id = 2;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(id)).Set(r => r.Name, y => y.Name + "1").Update();
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分表删除到testorm3数据库orders_1
        /// 
        [TestMethod]
        public void TestMethod6_08()
        {
            var id = 1;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(id)).Delete();
            Assert.AreEqual(result, 1);
        }

        /// 
        /// 测试mod分表删除到testorm3数据库orders_0
        /// 
        [TestMethod]
        public void TestMethod6_09()
        {
            var id = 2;
            var result = DB.Tables.Orders.Where(r => r.ID.Equals(id)).Delete();
            Assert.AreEqual(result, 1);
        }
        /// 
        /// 测试mod分库批量分别插入到testorm3数据库orders_0 orders_1
        /// 
        [TestMethod]
        public void TestMethod7_01()
        {

            var orderList = new List();
            orderList.Add(new Orders
            {
                ID = 3,
                Name = "上海大学"
            });
            orderList.Add(new Orders
            {
                ID = 4,
                Name = "上海大学"
            });
            //没有指定 shading column的话是默认分到第一个分片
            orderList.Add(new Orders
            {
                ID = null,
                Name = "上海大学"
            });
            var rows = DB.BulkCopy(orderList);
            Assert.AreEqual(rows.RowsCopied, 3);
        }

        /// 
        ///  不指定sharding 字段会删除所有子表
        /// 
        [TestMethod]
        public void TestMethod7_03()
        {
            var odIsExist = DB.Tables.Orders.Delete();
            Assert.AreEqual(odIsExist, 3);

        }

总结

目前在AntData orm中使用分库分表其实是根据查询的字段来匹配取模或者区间来进行分片,然后只需要配置上进行修改即可。对于实际业务上orm的写法是不需要变化的

你可能感兴趣的:(ORM框架对分表分库的实现)