v9.10.2019.0101 全面巩固批量Insert/Update/Upsert,支持数据备份、恢复和同步,支持实体列表保存到文件以及加载
|
# »º´æÏµÍ³ ICache
## ¸ÅÊö
NewLife.Core ÌṩÁËͳһµÄ»º´æ½Ó¿Ú `ICache`£¬Ö§³ÖÄڴ滺´æ¡¢Redis »º´æµÈ¶àÖÖʵÏÖ¡£Í¨¹ýͳһ½Ó¿Ú£¬¿ÉÒÔÔÚ²»Í¬»·¾³ÏÂÎÞ·ìÇл»»º´æÊµÏÖ£¬Í¬Ê±Ö§³Ö¹ýÆÚʱ¼ä¡¢Ô×Ó²Ù×÷¡¢ÅúÁ¿²Ù×÷µÈ¸ß¼¶ÌØÐÔ¡£
**ÃüÃû¿Õ¼ä**£º`NewLife.Caching`
**ÎĵµµØÖ·**£ºhttps://newlifex.com/core/icache
## ºËÐÄÌØÐÔ
- **ͳһ½Ó¿Ú**£º`ICache` ½Ó¿Ú¶¨Òå±ê×¼»º´æ²Ù×÷
- **¸ßÐÔÄÜ**£º`MemoryCache` »ùÓÚ `ConcurrentDictionary`£¬·åÖµÐÔÄÜ´ï 10 ÒÚ ops
- **×Ô¶¯¹ýÆÚ**£ºÖ§³ÖÏà¶Ô¹ýÆÚʱ¼ä£¨TTL£©
- **Ô×Ó²Ù×÷**£ºµÝÔö¡¢µÝ¼õ¡¢Ìæ»»µÈÔ×Ó²Ù×÷
- **ÅúÁ¿²Ù×÷**£ºÅúÁ¿¶Áд¼õÉÙÍøÂ翪Ïú
- **LRU ÌÔÌ**£ºÄڴ滺´æ³¬ÈÝÁ¿Ê±×Ô¶¯ÇåÀí
## ¿ìËÙ¿ªÊ¼
### »ù±¾Ê¹ÓÃ
```csharp
using NewLife.Caching;
// ʹÓÃĬÈÏÄڴ滺´æ
var cache = MemoryCache.Instance;
// ÉèÖûº´æ£¨60Ãë¹ýÆÚ£©
cache.Set("name", "ÕÅÈý", 60);
// »ñÈ¡»º´æ
var name = cache.Get<String>("name");
// ɾ³ý»º´æ
cache.Remove("name");
```
### ³£ÓòÙ×÷
```csharp
var cache = MemoryCache.Instance;
// ¼ì²éÊÇ·ñ´æÔÚ
if (cache.ContainsKey("user:1"))
{
var user = cache.Get<User>("user:1");
}
// »ñÈ¡»òÌí¼Ó£¨»º´æ´©Í¸±£»¤£©
var data = cache.GetOrAdd("data:key", k =>
{
// »º´æ²»´æÔÚʱ£¬Ö´Ðд˻ص÷»ñÈ¡Êý¾Ý
return LoadFromDatabase(k);
}, 300);
// Ô×ÓµÝÔö
var count = cache.Increment("visit:count", 1);
```
## API ²Î¿¼
### ICache ½Ó¿Ú
#### »ù±¾ÊôÐÔ
```csharp
/// <summary>»º´æÃû³Æ</summary>
String Name { get; }
/// <summary>ĬÈϹýÆÚʱ¼ä£¨Ã룩</summary>
Int32 Expire { get; set; }
/// <summary>»º´æÏî×ÜÊý</summary>
Int32 Count { get; }
/// <summary>ËùÓлº´æ¼ü</summary>
ICollection<String> Keys { get; }
```
#### »ù´¡²Ù×÷
```csharp
/// <summary>¼ì²éÊÇ·ñ´æÔÚ</summary>
Boolean ContainsKey(String key);
/// <summary>ÉèÖûº´æ</summary>
/// <param name="expire">¹ýÆÚÃëÊý¡£-1ʹÓÃĬÈÏ£¬0ÓÀ²»¹ýÆÚ</param>
Boolean Set<T>(String key, T value, Int32 expire = -1);
/// <summary>ÉèÖûº´æ£¨TimeSpan£©</summary>
Boolean Set<T>(String key, T value, TimeSpan expire);
/// <summary>»ñÈ¡»º´æ</summary>
T Get<T>(String key);
/// <summary>³¢ÊÔ»ñÈ¡£¨½â¾ö»º´æ´©Í¸£©</summary>
Boolean TryGetValue<T>(String key, out T value);
/// <summary>ɾ³ý»º´æ</summary>
Int32 Remove(String key);
/// <summary>ÅúÁ¿É¾³ý</summary>
Int32 Remove(params String[] keys);
/// <summary>Çå¿ÕËùÓлº´æ</summary>
void Clear();
```
#### ¹ýÆÚʱ¼ä¹ÜÀí
```csharp
/// <summary>ÉèÖùýÆÚʱ¼ä</summary>
Boolean SetExpire(String key, TimeSpan expire);
/// <summary>»ñȡʣÓà¹ýÆÚʱ¼ä</summary>
TimeSpan GetExpire(String key);
```
#### ÅúÁ¿²Ù×÷
```csharp
/// <summary>ÅúÁ¿»ñÈ¡</summary>
IDictionary<String, T?> GetAll<T>(IEnumerable<String> keys);
/// <summary>ÅúÁ¿ÉèÖÃ</summary>
void SetAll<T>(IDictionary<String, T> values, Int32 expire = -1);
```
#### ¸ß¼¶²Ù×÷
```csharp
/// <summary>Ìí¼Ó£¨ÒÑ´æÔÚʱ²»¸üУ©</summary>
Boolean Add<T>(String key, T value, Int32 expire = -1);
/// <summary>Ìæ»»²¢·µ»Ø¾ÉÖµ</summary>
T Replace<T>(String key, T value);
/// <summary>»ñÈ¡»òÌí¼Ó</summary>
T GetOrAdd<T>(String key, Func<String, T> callback, Int32 expire = -1);
/// <summary>Ô×ÓµÝÔö</summary>
Int64 Increment(String key, Int64 value);
Double Increment(String key, Double value);
/// <summary>Ô×ӵݼõ</summary>
Int64 Decrement(String key, Int64 value);
Double Decrement(String key, Double value);
```
### MemoryCache Àà
```csharp
public class MemoryCache : Cache
{
/// <summary>ĬÈÏʵÀý</summary>
public static MemoryCache Instance { get; set; }
/// <summary>ÈÝÁ¿¡£³¬±êʱLRUÌÔÌ£¬Ä¬ÈÏ100000</summary>
public Int32 Capacity { get; set; }
/// <summary>¶¨Ê±ÇåÀí¼ä¸ô£¨Ã룩£¬Ä¬ÈÏ60</summary>
public Int32 Period { get; set; }
/// <summary>»º´æ¼ü¹ýÆÚʼþ</summary>
public event EventHandler<KeyEventArgs>? KeyExpired;
}
```
## ʹÓó¡¾°
### 1. Êý¾Ý»º´æ
```csharp
public class UserService
{
private readonly ICache _cache;
public UserService(ICache cache)
{
_cache = cache;
}
public User? GetUser(Int32 id)
{
var key = $"user:{id}";
// ÏȲ黺´æ
if (_cache.TryGetValue<User>(key, out var user))
return user;
// »º´æÎ´ÃüÖУ¬²éÊý¾Ý¿â
user = LoadUserFromDb(id);
if (user != null)
_cache.Set(key, user, 300); // »º´æ5·ÖÖÓ
return user;
}
}
```
### 2. ·ÀÖ¹»º´æ´©Í¸
```csharp
// ʹÓà GetOrAdd ·ÀÖ¹»º´æ´©Í¸
var user = cache.GetOrAdd($"user:{id}", key =>
{
// ¼´Ê¹Êý¾Ý¿â·µ»Ø null£¬Ò²»á±»»º´æ
return LoadUserFromDb(id);
}, 60);
// ʹÓà TryGetValue Çø·Ö¿ÕÖµºÍ²»´æÔÚ
if (cache.TryGetValue<User?>($"user:{id}", out var user))
{
// ¼ü´æÔÚ£¨¿ÉÄÜΪ null£©
return user;
}
else
{
// ¼ü²»´æÔÚ£¬ÐèÒª²éѯÊý¾Ý¿â
}
```
### 3. ¼ÆÊýÆ÷
```csharp
// ·ÃÎʼÆÊý
var count = cache.Increment("page:home:views", 1);
// ÏÞÁ÷¼ÆÊý
var requests = cache.Increment($"rate:{userId}", 1);
if (requests == 1)
{
// Ê״ηÃÎÊ£¬ÉèÖùýÆÚʱ¼ä
cache.SetExpire($"rate:{userId}", TimeSpan.FromMinutes(1));
}
if (requests > 100)
{
throw new Exception("ÇëÇó¹ýÓÚÆµ·±");
}
```
### 4. ·Ö²¼Ê½Ëø¼òÒ×ʵÏÖ
```csharp
public class SimpleLock
{
private readonly ICache _cache;
public Boolean TryLock(String key, Int32 seconds = 30)
{
// Add Ö»ÔÚ²»´æÔÚʱ³É¹¦
return _cache.Add($"lock:{key}", DateTime.Now, seconds);
}
public void Unlock(String key)
{
_cache.Remove($"lock:{key}");
}
}
// ʹÓÃ
var locker = new SimpleLock(cache);
if (locker.TryLock("order:create"))
{
try
{
// Ö´ÐÐÒµÎñ
}
finally
{
locker.Unlock("order:create");
}
}
```
### 5. »á»°»º´æ
```csharp
public class SessionCache
{
private readonly ICache _cache;
private readonly Int32 _expire = 1800; // 30·ÖÖÓ
public void Set(String sessionId, Object data)
{
_cache.Set($"session:{sessionId}", data, _expire);
}
public T? Get<T>(String sessionId)
{
var key = $"session:{sessionId}";
var data = _cache.Get<T>(key);
if (data != null)
{
// ÐøÆÚ
_cache.SetExpire(key, TimeSpan.FromSeconds(_expire));
}
return data;
}
}
```
### 6. ÅúÁ¿²Ù×÷ÓÅ»¯
```csharp
// ÅúÁ¿»ñÈ¡
var keys = new[] { "user:1", "user:2", "user:3" };
var users = cache.GetAll<User>(keys);
foreach (var kv in users)
{
Console.WriteLine($"{kv.Key}: {kv.Value?.Name}");
}
// ÅúÁ¿ÉèÖÃ
var items = new Dictionary<String, User>
{
["user:1"] = new User { Id = 1, Name = "ÕÅÈý" },
["user:2"] = new User { Id = 2, Name = "ÀîËÄ" }
};
cache.SetAll(items, 300);
```
## ¹ýÆÚʱ¼ä˵Ã÷
| expire Öµ | º¬Òå |
|-----------|------|
| < 0 | ʹÓÃĬÈϹýÆÚʱ¼ä `Expire` |
| = 0 | ÓÀ²»¹ýÆÚ |
| > 0 | ´ÓÏÖÔÚÆð N Ãëºó¹ýÆÚ |
```csharp
// ʹÓÃĬÈϹýÆÚʱ¼ä
cache.Set("key1", value);
// ÓÀ²»¹ýÆÚ
cache.Set("key2", value, 0);
// 1Сʱºó¹ýÆÚ
cache.Set("key3", value, 3600);
// ʹÓà TimeSpan
cache.Set("key4", value, TimeSpan.FromHours(1));
```
## ÒÀÀµ×¢Èë
```csharp
// ×¢²á»º´æ·þÎñ
services.AddSingleton<ICache>(MemoryCache.Instance);
// »ò´´½¨ÐÂʵÀý
services.AddSingleton<ICache>(sp => new MemoryCache
{
Capacity = 50000,
Expire = 600
});
```
## »º´æ¼ü¹æ·¶
½¨ÒéʹÓÃðºÅ·Ö¸ôµÄ²ã¼¶¼üÃû£º
```
ÀàÐÍ:±êʶ[:×ÓÀàÐÍ]
user:123
user:123:profile
order:2024:001
config:app:debug
```
## ×î¼Ñʵ¼ù
### 1. ºÏÀíÉèÖÃÈÝÁ¿
```csharp
var cache = new MemoryCache
{
Capacity = 100000, // ¸ù¾ÝÄÚ´æµ÷Õû
Period = 60 // ÇåÀí¼ä¸ô
};
```
### 2. ¼àÌý¹ýÆÚʼþ
```csharp
var cache = new MemoryCache();
cache.KeyExpired += (s, e) =>
{
XTrace.WriteLine($"»º´æ¹ýÆÚ: {e.Key}");
// ¿ÉÒÔÔÚÕâÀï´¥·¢Êý¾ÝÔ¤ÈÈ
};
```
### 3. ±ÜÃâ´ó Key
```csharp
// ²»ÍƼö£º´æ´¢´ó¶ÔÏó
cache.Set("bigdata", hugeList);
// ÍÆ¼ö£º²ð·Ö´æ´¢
foreach (var item in hugeList)
{
cache.Set($"item:{item.Id}", item);
}
```
### 4. ʹÓÃǰ׺¸ôÀë
```csharp
// ²»Í¬Ä£¿éʹÓò»Í¬Ç°×º
cache.Set("user:session:abc", data);
cache.Set("order:temp:123", data);
// °´Ç°×ºÅúÁ¿É¾³ý
cache.Remove("user:session:*");
```
## Ïà¹ØÁ´½Ó
- [¶ÔÏó³Ø Pool](/NewLife/X/Blob/dev/Doc/pool-¶ÔÏó³ØPool.md)
- [×ֵ仺´æ DictionaryCache](/NewLife/X/Blob/dev/Doc/dictionary_cache-×ֵ仺´æ.md)
- [Ñ©»¨Ëã·¨ Snowflake](/NewLife/X/Blob/dev/Doc/snowflake-Ñ©»¨Ëã·¨Snowflake.md)
|