ORM框架對分表分庫的實現
AntData ORM框架是我維護的一個開源ORM框架
該框架是在Linq2db這個優秀的linq轉sql引擎基礎上進行改造而來的。
分離了linq2sql引擎和db執行邏輯。
畫一個圖的話 應該是這樣的:
分表分庫功能設計
框架內置目前使用比較多的兩種分片模式:
- 取模 (mod)
- 範圍 (range)
為了讓框架更容易擴展
- 開放分片策略的介面 當有自定義分片規則可以繼承實現
下面我用內置的 取模 分片模式來說明 ,運行環境: netcore平台
1. DB Sharding
db配置:
- Provider 指定為 mysql
- Name 是邏輯名稱 可以隨意指定
- ShardingStrategy 指定分片的邏輯處理
- ConnectionItemList 指定一個或多個db鏈接配置
注意:
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 使用場景舉例說明
/// <summary>
/// 測試mod分庫插入到testorm2資料庫
/// </summary>
[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);
}
/// <summary>
/// 測試mod分庫插入到testorm1資料庫
/// </summary>
[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);
}
/// <summary>
/// 測試mod分庫 查詢testorm2資料庫
/// </summary>
[TestMethod]
public void TestMethod6_03()
{
var id = 1;
var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(1));
Assert.IsNotNull(tb1);
}
/// <summary>
/// 測試mod分庫 查詢testorm1資料庫
/// </summary>
[TestMethod]
public void TestMethod6_04()
{
var id = 2;
var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(2));
Assert.IsNotNull(tb1);
}
/// <summary>
/// 測試mod分庫 不指定sharing column 查詢疊加
/// </summary>
[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);
}
/// <summary>
/// 測試mod分庫修改到testorm2資料庫
/// </summary>
[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);
}
/// <summary>
/// 測試mod分庫修改到testorm1資料庫
/// </summary>
[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);
}
/// <summary>
/// 測試mod分庫刪除到testorm2資料庫
/// </summary>
[TestMethod]
public void TestMethod6_08()
{
var id = 1;
var result = DB.Tables.Orders.Where(r => r.ID.Equals(1)).Delete();
Assert.AreEqual(result, 1);
}
/// <summary>
/// 測試mod分庫刪除到testorm1資料庫
/// </summary>
[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;
}
}
/// <summary>
/// 測試mod分庫批量分別插入到testorm1 和 testorm2資料庫
/// </summary>
[TestMethod]
public void TestMethod7_02()
{
var orderList = new List<Order>();
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);
}
/// <summary>
/// 不指定sharing column 刪除會疊加
/// </summary>
[TestMethod]
public void TestMethod7_03()
{
var odIsExist = DB.Tables.Orders.Delete();
Assert.AreEqual(odIsExist, 3);
}
2. Table Sharding
- Provider 指定為 mysql
- Name 是邏輯名稱 可以隨意指定
- ShardingStrategy 指定分片的邏輯處理
- ConnectionItemList 指定一個db鏈接配置
針對分表要對 dbmodels 做一個小修改
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 使用場景舉例說明
/// <summary>
/// 測試mod分表插入到testorm3資料庫的orders_1表裡面
/// </summary>
[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);
}
/// <summary>
/// 測試mod分表插入到testorm3資料庫的orders_0表裡面
/// </summary>
[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);
}
/// <summary>
/// 測試mod分表 查詢testorm3資料庫orders_1表
/// </summary>
[TestMethod]
public void TestMethod1_03()
{
var id = 1;
var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(id));
Assert.IsNotNull(tb1);
}
/// <summary>
/// 測試mod分表 查詢testorm3資料庫orders_0表
/// </summary>
[TestMethod]
public void TestMethod1_04()
{
var id = 2;
var tb1 = DB.Tables.Orders.FirstOrDefault(r => r.ID.Equals(id));
Assert.IsNotNull(tb1);
}
/// <summary>
/// 測試mod分表 不指定sharing column 查詢疊加
/// </summary>
[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);
}
/// <summary>
/// 測試mod分表修改到testorm3資料庫orders_1表
/// </summary>
[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);
}
/// <summary>
/// 測試mod分表修改到testorm3資料庫orders_0表
/// </summary>
[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);
}
/// <summary>
/// 測試mod分表刪除到testorm3資料庫orders_1表
/// </summary>
[TestMethod]
public void TestMethod6_08()
{
var id = 1;
var result = DB.Tables.Orders.Where(r => r.ID.Equals(id)).Delete();
Assert.AreEqual(result, 1);
}
/// <summary>
/// 測試mod分表刪除到testorm3資料庫orders_0表
/// </summary>
[TestMethod]
public void TestMethod6_09()
{
var id = 2;
var result = DB.Tables.Orders.Where(r => r.ID.Equals(id)).Delete();
Assert.AreEqual(result, 1);
}
/// <summary>
/// 測試mod分庫批量分別插入到testorm3資料庫orders_0表 orders_1表
/// </summary>
[TestMethod]
public void TestMethod7_01()
{
var orderList = new List<Orders>();
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);
}
/// <summary>
/// 不指定sharding 欄位會刪除所有子表
/// </summary>
[TestMethod]
public void TestMethod7_03()
{
var odIsExist = DB.Tables.Orders.Delete();
Assert.AreEqual(odIsExist, 3);
}
總結
目前在AntData orm中使用分庫分表其實是根據查詢的欄位來匹配取模或者區間來進行分片,然後只需要配置上進行修改即可。對於實際業務上orm的寫法是不需要變化的