ServiceStack.OrmLite 笔记2 -增

阻止并发下的产品超卖思路是利用redis串行处理数据,但又有高并发处理数据的能力

ServiceStack.OrmLite 笔记2

这篇主要介绍 增加

db.Insert(new Employee { Id = 1, Name = “Employee 1” }); //默认同步

await db.InsertAsync(new Employee { Id = 1, Name = “Employee 1” });
//异步 其他的异步类似这里的这个示例

db.InsertOnly(new Person { FirstName = “Amy” }, q => q.Insert(p =>
new {p.FirstName}))
// 插入部分字段 后面的参数q.Insert表示要插入的字段 生成sql: INSERT INTO
“Person” (“FirstName”) VALUES (‘Amy’)

var rowId = db.Insert(new Poco { Text = “Text” },
selectIdentity:true);// selectIdentity:true返回自增长的id

这里代码有点多 全局的插入时过滤 类似的有UpdateFilter
,感觉就是插入时对数据进行拦截,可以发挥你的想象,比如可以在这里加日志,或者扩展新的字段,做爱做的事情。
public interface IAudit
{
DateTime CreatedDate { get; set; }
DateTime ModifiedDate { get; set; }
string ModifiedBy { get; set; }
}

//表对应的类
public class AuditTableA : IAudit
{
public AuditTableA()
{
this.CreatedDate = this.ModifiedDate = DateTime.UtcNow;
}

    [AutoIncrement]
    public int Id { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime ModifiedDate { get; set; }
    public string ModifiedBy { get; set; }
}

OrmLiteConfig.InsertFilter = (dbCmd, row) => {
var auditRow = row as IAudit;
if (auditRow != null)
auditRow.CreatedDate = auditRow.ModifiedDate = DateTime.UtcNow;
};
下面是上面方法的新体位,也来自官网。对数据进行验证
OrmLiteConfig.InsertFilter = OrmLiteConfig.UpdateFilter = (dbCmd, row)
=> {
var auditRow = row as IAudit;
if (auditRow != null && auditRow.ModifiedBy == null)
throw new ArgumentNullException(“ModifiedBy”);
};

try
{
db.Insert(new AuditTable());
}
catch (ArgumentNullException) {
//throws ArgumentNullException
}

db.Insert(new AuditTable { ModifiedBy = “Me!” }); //succeeds

下面的代码因为也有insert 就也放上吧
在表被创建或者删除的时候执行sql语句
[PostCreateTable(“INSERT INTO TableWithSeedData (Name) VALUES (‘Foo’);”

  • “INSERT INTO TableWithSeedData (Name) VALUES (‘Bar’);”)]
    public class TableWithSeedData
    {
    [AutoIncrement]
    public int Id { get; set; }
    public string Name { get; set; }
    }

typeof(TableWithSeedData)
.AddAttributes(new PostCreateTableAttribute(
“INSERT INTO TableWithSeedData (Name) VALUES (‘Foo’);” +
“INSERT INTO TableWithSeedData (Name) VALUES (‘Bar’);”));

前戏和事后,都是可以有自己的玩法
[PreCreateTable(runSqlBeforeTableCreated)][PostCreateTable(runSqlAfterTableCreated)]
[PreDropTable(runSqlBeforeTableDropped)][PostDropTable(runSqlAfterTableDropped)]
public class Table {}

Db.ExecuteSql(“INSERT INTO page_stats (ref_id, fav_count) VALUES
(@refId, @favCount)”, new { refId, favCount }) //直接执行sql语句

Db.ExecuteSqlAsync(“UPDATE page_stats SET view_count = view_count + 1
WHERE id = @id”, new { id })//直接执行sql语句

产品表(product) 

class Product

{

  public int Id{get;set} //自增Id

       public string Name{get;set}//产品名称

       public int Number{get;set}//库存

       public DateTime NTime{get;set;}//库存同步时间

       ….

}

库存变更记录表(productNumberRecord)

class productNumberRecord

{

  public int Id{get;set;}

       public int Number{get;set;} //本次消耗库存数量

       public int SurplusNumber{get;set} //本次消耗后的剩余数量

       public DataTime Time{get;set;} //记录时间

       ….

}

1.将产品Id,库存存入redis,每次操作产品库存,则产生一条库存的变更记录存入sql库中

2.此时sql库产品的实际库存应该是 库存=库存-库存记录(大于NTime时间的记录)

3.sql库中的余额,可以做定时任务
按天或小时数进行同步,防止过大的记录造成select超时

4.如果redis挂掉,那么它将从数据库中 按照步揍2的方式同步库存

 

伪代码实现(不加锁)

(开始事务){

try{

func1(插入变更记录表);
如果func1 执行失败 直接跳出

func3 …

func4 …

等其他业务

funcX(增减redis库存)
如果funcX执行失败,直接跳出,不插入日志

如果都成功 则提交事务

catch{
tran.callback()//事务回滚
}