最近在写一个Asp.net 的框架,在本地搭建了数据缓存,采用了 定时的lazy fresh的过期方式,
但是大量的数据其实是没有改变的,改变的只是很小的部分,这个时候缓存过期,全部重新刷新数据就显得非常浪费了。
思来想去,觉得我可以从数据库的更新方法下手,于是有了下面这些尝试了。
在Oracle 中Insert 语句是可以使用 returning 返回新增的记录的。
于是我们的Insert 语句就是这样了.
INSERT INTO TableName (UniqueColumn,OtherColumns)
VALUES(Table_SEQ.Nextval,Values) RETURNING UniqueColumn INTO :Unique_Id。
这样执行之后,我就可以通过Out参数 Unique_Id 获取新增的记录的主键啦。
附C#:
public override object Insert(EditorParams pm) { if (pm != null && pm.EditValues.Count > 0) { QuerySetting qs = ConfigEnginer.Instance.DataModels[pm.ModelType]; string insertformart = @"INSERT INTO #OysterVal:TableName# (#OysterVal:UniqueColumn#,#OysterVal:Columns#) VALUES(#OysterVal:TableName#_SEQ.Nextval,#OysterVal:Values#) RETURNING #OysterVal:UniqueColumn# INTO :Unique_Id"; Dictionary<string, string> vals = new Dictionary<string, string>(); List<IDataParameter> parms = new List<IDataParameter>(); vals.Add("TableName", qs.TableName); vals.Add("UniqueColumn", qs.UniqueColumn.ColumnName); vals.Add("Columns", pm.InsertColumns); vals.Add("Values", pm.InsertValues); //System.Nullable var Unqtype = qs.UniqueColumn.PropertyType; if (Unqtype.FullName.Contains("System.Nullable")) { var types = Unqtype.GetGenericArguments(); if (types != null && types.Length > 0) { Unqtype = types[0]; } } var pr = new OracleParameter(":Unique_Id", Activator.CreateInstance(Unqtype)); pr.Direction = ParameterDirection.InputOutput; parms.Add(pr); parms.AddRange(pm.DataParms); string sql = insertformart.ToOysterTemplate(vals); pm.EffectCount = DbEnginer.Instance.ExecuteNonQuery(sql, parms.ToArray()); pm.EffectUniqueIds.Add(pr.Value); return pm.EffectUniqueIds[0]; } else { throw new Exception("请检查传入的EditParams,更新列数据不能为空!"); } return null; }
仅供参考,里面使用到的其他类型引用,以后会慢慢分享。
而UPDATE 则可以这样:SELECT UniqueColumn FROM TableName WHERE Condition FOR UPDATE。
将要更新的行Select 出来,并且加上Update 的锁。保证Update按顺序执行,而不会错乱。
附C#代码:
public override int Update(EditorParams pm) { if (pm != null && pm.EditValues.Count > 0) { try { QuerySetting qs = ConfigEnginer.Instance.DataModels[pm.ModelType]; string selectforupdatestr = "SELECT #OysterVal:UniqueColumn# FROM #OysterVal:TableName# WHERE #OysterVal:Condition# FOR UPDATE"; List<IDataParameter> parms = new List<IDataParameter>(); string cond = pm.condition.ToString(parms); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add("UniqueColumn", qs.UniqueColumn.ColumnName); dic.Add("TableName", qs.TableName); dic.Add("Condition", cond); string selectsql = selectforupdatestr.ToOysterTemplate(dic); DbEnginer.Instance.DbConnection.IsReaderReading = true; var ds = DbEnginer.Instance.ExecuteQuery(selectsql, parms); if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) { dic.Add("Columns", pm.UpdateColumns); List<object> ids = new List<object>(); for (int i = 0; i < ds.Tables[0].Rows.Count; i++) { if (!ds.Tables[0].Rows[i][0].Equals(DBNull.Value)) { ids.Add(ds.Tables[0].Rows[i][0]); } if ((i > 0 && i % 999 == 0) || i == ds.Tables[0].Rows.Count - 1) { var condition = Condition.New(qs.ClassType, qs.UniqueColumn.Property, ConditionOperator.In, ids); parms = new List<IDataParameter>(); cond = condition.ToString(parms); dic["Condition"] = cond; string updatestr = "UPDATE #OysterVal:TableName# SET #OysterVal:Columns# WHERE #OysterVal:Condition#"; string updatesql = updatestr.ToOysterTemplate(dic); foreach (var p in pm.DataParms) { var temp = DbEnginer.Instance.NewDataParameter(p.ParameterName); temp.ParameterName = p.ParameterName; temp.DbType = p.DbType; temp.Direction = p.Direction; temp.Value = p.Value; parms.Add(temp); } pm.EffectCount += DbEnginer.Instance.ExecuteNonQuery(updatesql, parms); pm.EffectUniqueIds.AddRange(ids); ids.Clear(); } } DbEnginer.Instance.ExecuteNonQuery("commit"); } } catch (Exception ex) { DbEnginer.Instance.ExecuteNonQuery("rollback"); throw ex; } finally { DbEnginer.Instance.DbConnection.IsReaderReading = false; DbEnginer.Instance.DbConnection.Close(); } } else { throw new Exception("请检查传入的EditParams,更新列不能为空!"); } return pm.EffectCount; }
哈哈,先就这样吧,只是分享一个思路,不过这样的效率不是很好。10000条Insert 12秒,Update 4秒,谢谢大家。