Enterprise Library——企业库缓存应用程序块

提供了一些方便易用的、可扩展的缓冲机制。
这些缓冲机制可以使用在整体应用中的各个层面。
支持后期存储,支持的存储方式包括数据库方式和独立存储方式(Isolated storage), 便于应用方便的重新启动
便于使用
便于配置
支持使用配置工具
线程安全
可以确保在内存中的缓冲和后端存储保持同步
1.创建配置文件
在您的应用配置文件中增加一个缓冲应用
为要创建的数据项创建 Cache manager
每一个子项需要有独立的名字
确定哪一个是默认的Cache manager
%E5%9B%BE%E7%89%871.png
内存驻留型缓冲的典型应用:
应用程序经常使用同样的数据
一个应用程序经常需要重新获得数据
磁盘驻留型缓冲的典型应用:
数据量比较大
同时,从应用服务提供商(例如数据库)重新获取数据,开销比较大
在缓冲的生命周期中,必须经历系统的重新启动
创建默认 cache manager
CacheManager myCache = CacheManager.GetCacheManager();
创建命名的cache manager
CacheManager productsCache =
       CacheManager.GetCacheManager(“Products”);
默认的增加一个条目
productsCache.Add(“ProductID123”, productObject);
基于时间的过期实例
DateTime refreshTime = new DateTime(2005, 3, 21, 2, 0, 0);
AbsoluteTime expireTime = new AbsoluteTime(refreshTime);
     
primitivesCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal,
                                      null, expireTime);
变化时间的过期
被访问5分钟后
TimeSpan refreshTime = new TimeSpan(0, 5, 0);
SlidingTime expireTime = new SlidingTime(refreshTime);
     
primitivesCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal,
                                      null, expireTime);
扩展时间应用范例
ExtendedFormatTime expireTime =
  new ExtendedFormatTime("0 0 * * 6");
     
primitivesCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal,
                                      null, expireTime);
基于提醒机制的过期  文件依赖的例子
FileDependency expireNotice = new FileDependency(“Trigger.txt”);
    
productsCache.Add("Key1", "Cache Item1", CacheItemPriority.Normal,
                                      null, expireNotice);
配置过期表决的频率
通过后台线程(BackgroundScheduler),移除过期事项
您可以对次线程进行配置
过高:CPU浪费,且CACHE没有起到作用
过低:内存消耗太大
建议使用性能计数器监视一下
%E5%9B%BE%E7%89%872.png
条目移除提示
Caching Application Block 提供了项目移除的提醒,并在一下情况下被激活
条目过期了
条目被显式的移除了
条目被策略的清楚了
需要实现 ICacheItemRefreshAction接口
一个类实现了 ICacheItemRefreshAction 接口,同时如果需要后端存储时,还必须被标识为 Serializable (Especially for persistent backing store)
[Serializable]
public class ProductCacheRefreshAction : ICacheItemRefreshAction
{
    public void Refresh(string key, object expiredValue,
                        CacheItemRemovedReason removalReason)
    {
      // Item has been removed from cache.
      // Perform desired actions here,
      // based upon the removal reason (e.g. refresh the cache with the    
      // item).
    }
}
从Cache manager中获取
类型要正确
一定要检查空值 (item not found in cache)
public Product ReadProductByID(string productID)
{
     Product product = (Product)cache.GetData(productID);

    if (product == null)
    {
        // Item not in cache
    }
}
装载缓冲
缓冲的前期装载(Proactive loading)
应用启动时装载
优点
全部装载后,应用运行性能提升明显
缺点
启动时间长
可能带来不必要的资源浪费 
为了提升启动性能而进行的——基于不同线程的装载,有造成了应用结构的复杂性
缓冲的被动装载(Reactive loading)
按需装载
优点
只有在需要的时候才装载,对资源的需求小
缺点
但是在首次装载的时候,速度慢
主动装载的实例
1:Create cache manager
CacheManager productsCache = CacheManager.GetCacheManager();
2:Add items during component initialization
// Retrieve the data from the source
ArrayList list = dataProvider.GetProductList();

// Add all the items to the cache
for (int i = 0; i < list.Count; i++)
{
    Product product = (Product) list[i];
    productsCache.Add( product.ProductID, product );
}
后期装载的实例
1:Create cache manager
CacheManager productsCache = CacheManager.GetCacheManager();
2:Add items when retrieved from data source
Product product = (Product) productsCache.GetData(productID);
if (product == null)
{
    // Retrieve it from the data provider
    // and cache it for more requests.
    product = dataProvider.GetProductByID(productID);
    if (product != null)
    {
       productsCache.Add(productID, product);
    }
}
从缓冲中移除
1:Remove item with specified key
productsCache.Remove(“Product101Key”)
2:No error occurs if key is not found
因此通过这种方法,不能知道ITEM是否移除了
如果对象实现了ICacheRefreshItemAction,可以有信息
刷新缓冲
productsCache.Flush()
为缓冲建立优先级
productsCache.Add("Key1", "Cache Item1", CacheItemPriority.High,
                   new ProductCacheRefreshAction(), expireNotice)

 实例

None.gif using  System;
None.gif
using  System.Drawing;
None.gif
using  System.Collections;
None.gif
using  System.ComponentModel;
None.gif
using  System.Windows.Forms;
None.gif
using  System.Data;
None.gif
None.gif
using  Microsoft.Practices.EnterpriseLibrary.Caching;
None.gif
using  Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;
None.gif
using  Microsoft.Practices.EnterpriseLibrary.Data;
None.gif
None.gif
None.gif
namespace  CacheWindowsApplication
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// Form1 的摘要说明。
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public class Form1 : System.Windows.Forms.Form
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private System.Windows.Forms.Button btnQuery;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 必需的设计器变量。
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        private System.ComponentModel.Container components = null;
InBlock.gif        
private System.Windows.Forms.Label label;
InBlock.gif        
private System.Windows.Forms.ListBox listBox;
InBlock.gif        
private System.Windows.Forms.Button btnGetFromCache;
InBlock.gif
InBlock.gif        
// **********************************************
InBlock.gif        
// Define parameters for demonstration
InBlock.gif        
//***********************************************
InBlock.gif
        private IDataReader myDr = null;
InBlock.gif        
private System.Windows.Forms.Button btnTestExpire;
InBlock.gif        
private CacheManager myCacheManager = null;
InBlock.gif        
private System.Windows.Forms.Button btnReview;
InBlock.gif        
private System.Windows.Forms.Button btnFileDependency;
InBlock.gif        
private System.Windows.Forms.Button btnQueryByFile;
InBlock.gif        
private System.Windows.Forms.Button button1;
InBlock.gif        
private System.Windows.Forms.Button button2;
InBlock.gif        
private System.Windows.Forms.Button button3;
InBlock.gif        
private CacheManager IsolatedCacheManager =null;
InBlock.gif
InBlock.gif        
public Form1()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// Windows 窗体设计器支持所必需的
InBlock.gif            
//
InBlock.gif
            InitializeComponent();
InBlock.gif
InBlock.gif            
//
InBlock.gif            
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
InBlock.gif            
//
ExpandedSubBlockEnd.gif
        }

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 清理所有正在使用的资源。
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        protected override void Dispose( bool disposing )
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
if( disposing )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
if (components != null
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    components.Dispose();
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

InBlock.gif            
base.Dispose( disposing );
ExpandedSubBlockEnd.gif        }

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
Windows 窗体设计器生成的代码#region Windows 窗体设计器生成的代码
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
InBlock.gif        
/// 此方法的内容。
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        private void InitializeComponent()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.btnQuery = new System.Windows.Forms.Button();
InBlock.gif            
this.label = new System.Windows.Forms.Label();
InBlock.gif            
this.listBox = new System.Windows.Forms.ListBox();
InBlock.gif            
this.btnGetFromCache = new System.Windows.Forms.Button();
InBlock.gif            
this.btnTestExpire = new System.Windows.Forms.Button();
InBlock.gif            
this.btnReview = new System.Windows.Forms.Button();
InBlock.gif            
this.btnFileDependency = new System.Windows.Forms.Button();
InBlock.gif            
this.btnQueryByFile = new System.Windows.Forms.Button();
InBlock.gif            
this.button1 = new System.Windows.Forms.Button();
InBlock.gif            
this.button2 = new System.Windows.Forms.Button();
InBlock.gif            
this.button3 = new System.Windows.Forms.Button();
InBlock.gif            
this.SuspendLayout();
InBlock.gif            
// 
InBlock.gif            
// btnQuery
InBlock.gif            
// 
InBlock.gif
            this.btnQuery.Location = new System.Drawing.Point(24328);
InBlock.gif            
this.btnQuery.Name = "btnQuery";
InBlock.gif            
this.btnQuery.Size = new System.Drawing.Size(7224);
InBlock.gif            
this.btnQuery.TabIndex = 1;
InBlock.gif            
this.btnQuery.Text = "查询";
InBlock.gif            
this.btnQuery.Click += new System.EventHandler(this.btnQuery_Click);
InBlock.gif            
// 
InBlock.gif            
// label
InBlock.gif            
// 
InBlock.gif
            this.label.Location = new System.Drawing.Point(3216);
InBlock.gif            
this.label.Name = "label";
InBlock.gif            
this.label.Size = new System.Drawing.Size(23223);
InBlock.gif            
this.label.TabIndex = 2;
InBlock.gif            
this.label.Text = "显示:";
InBlock.gif            
// 
InBlock.gif            
// listBox
InBlock.gif            
// 
InBlock.gif
            this.listBox.ItemHeight = 12;
InBlock.gif            
this.listBox.Location = new System.Drawing.Point(3256);
InBlock.gif            
this.listBox.Name = "listBox";
InBlock.gif            
this.listBox.Size = new System.Drawing.Size(336244);
InBlock.gif            
this.listBox.TabIndex = 3;
InBlock.gif            
// 
InBlock.gif            
// btnGetFromCache
InBlock.gif            
// 
InBlock.gif
            this.btnGetFromCache.Location = new System.Drawing.Point(104328);
InBlock.gif            
this.btnGetFromCache.Name = "btnGetFromCache";
InBlock.gif            
this.btnGetFromCache.TabIndex = 4;
InBlock.gif            
this.btnGetFromCache.Text = "";
InBlock.gif            
this.btnGetFromCache.Click += new System.EventHandler(this.btnGetFromCache_Click);
InBlock.gif            
// 
InBlock.gif            
// btnTestExpire
InBlock.gif            
// 
InBlock.gif
            this.btnTestExpire.Location = new System.Drawing.Point(192328);
InBlock.gif            
this.btnTestExpire.Name = "btnTestExpire";
InBlock.gif            
this.btnTestExpire.Size = new System.Drawing.Size(9623);
InBlock.gif            
this.btnTestExpire.TabIndex = 5;
InBlock.gif            
this.btnTestExpire.Text = "加个可过期的";
InBlock.gif            
this.btnTestExpire.Click += new System.EventHandler(this.btnTestExpire_Click);
InBlock.gif            
// 
InBlock.gif            
// btnReview
InBlock.gif            
// 
InBlock.gif
            this.btnReview.Location = new System.Drawing.Point(304328);
InBlock.gif            
this.btnReview.Name = "btnReview";
InBlock.gif            
this.btnReview.Size = new System.Drawing.Size(7224);
InBlock.gif            
this.btnReview.TabIndex = 6;
InBlock.gif            
this.btnReview.Text = "在看一下";
InBlock.gif            
this.btnReview.Click += new System.EventHandler(this.btnReview_Click);
InBlock.gif            
// 
InBlock.gif            
// btnFileDependency
InBlock.gif            
// 
InBlock.gif
            this.btnFileDependency.Location = new System.Drawing.Point(24360);
InBlock.gif            
this.btnFileDependency.Name = "btnFileDependency";
InBlock.gif            
this.btnFileDependency.Size = new System.Drawing.Size(10424);
InBlock.gif            
this.btnFileDependency.TabIndex = 7;
InBlock.gif            
this.btnFileDependency.Text = "文件类型的";
InBlock.gif            
this.btnFileDependency.Click += new System.EventHandler(this.btnFileDependency_Click);
InBlock.gif            
// 
InBlock.gif            
// btnQueryByFile
InBlock.gif            
// 
InBlock.gif
            this.btnQueryByFile.Location = new System.Drawing.Point(144360);
InBlock.gif            
this.btnQueryByFile.Name = "btnQueryByFile";
InBlock.gif            
this.btnQueryByFile.Size = new System.Drawing.Size(10424);
InBlock.gif            
this.btnQueryByFile.TabIndex = 8;
InBlock.gif            
this.btnQueryByFile.Text = "文件类型查询";
InBlock.gif            
this.btnQueryByFile.Click += new System.EventHandler(this.btnQueryByFile_Click);
InBlock.gif            
// 
InBlock.gif            
// button1
InBlock.gif            
// 
InBlock.gif
            this.button1.Location = new System.Drawing.Point(272360);
InBlock.gif            
this.button1.Name = "button1";
InBlock.gif            
this.button1.Size = new System.Drawing.Size(10424);
InBlock.gif            
this.button1.TabIndex = 9;
InBlock.gif            
this.button1.Text = "文件类型不要了";
InBlock.gif            
this.button1.Click += new System.EventHandler(this.button1_Click_1);
InBlock.gif            
// 
InBlock.gif            
// button2
InBlock.gif            
// 
InBlock.gif
            this.button2.Location = new System.Drawing.Point(24400);
InBlock.gif            
this.button2.Name = "button2";
InBlock.gif            
this.button2.Size = new System.Drawing.Size(10424);
InBlock.gif            
this.button2.TabIndex = 10;
InBlock.gif            
this.button2.Text = "优先级问题";
InBlock.gif            
this.button2.Click += new System.EventHandler(this.button2_Click);
InBlock.gif            
// 
InBlock.gif            
// button3
InBlock.gif            
// 
InBlock.gif
            this.button3.Location = new System.Drawing.Point(144400);
InBlock.gif            
this.button3.Name = "button3";
InBlock.gif            
this.button3.Size = new System.Drawing.Size(23224);
InBlock.gif            
this.button3.TabIndex = 11;
InBlock.gif            
this.button3.Text = "在来几个高优先级";
InBlock.gif            
this.button3.Click += new System.EventHandler(this.button3_Click);
InBlock.gif            
// 
InBlock.gif            
// Form1
InBlock.gif            
// 
InBlock.gif
            this.AutoScaleBaseSize = new System.Drawing.Size(614);
InBlock.gif            
this.ClientSize = new System.Drawing.Size(408478);
InBlock.gif            
this.Controls.Add(this.button3);
InBlock.gif            
this.Controls.Add(this.button2);
InBlock.gif            
this.Controls.Add(this.button1);
InBlock.gif            
this.Controls.Add(this.btnQueryByFile);
InBlock.gif            
this.Controls.Add(this.btnFileDependency);
InBlock.gif            
this.Controls.Add(this.btnReview);
InBlock.gif            
this.Controls.Add(this.btnTestExpire);
InBlock.gif            
this.Controls.Add(this.btnGetFromCache);
InBlock.gif            
this.Controls.Add(this.listBox);
InBlock.gif            
this.Controls.Add(this.label);
InBlock.gif            
this.Controls.Add(this.btnQuery);
InBlock.gif            
this.Name = "Form1";
InBlock.gif            
this.Text = "Form1";
InBlock.gif            
this.Load += new System.EventHandler(this.Form1_Load);
InBlock.gif            
this.ResumeLayout(false);
InBlock.gif
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 应用程序的主入口点。
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        [STAThread]
InBlock.gif        
static void Main() 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Application.Run(
new Form1());
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void btnQuery_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{        
InBlock.gif            
this.label.Text = System.Convert.ToString(myCacheManager.Count);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void Form1_Load(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Database db 
= DatabaseFactory.CreateDatabase("Database Instance");
InBlock.gif            IDataReader dr 
= db.ExecuteReader(CommandType.Text,"Select * from Products");
InBlock.gif
InBlock.gif            
this.myDr=dr;
InBlock.gif            
InBlock.gif            myCacheManager 
= CacheFactory.GetCacheManager();
InBlock.gif            myCacheManager.Add(
"MyDataReader",this.myDr);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void btnGetFromCache_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            IDataReader toBeDisplay 
= (IDataReader)myCacheManager.GetData("MyDataReader");
InBlock.gif            
InBlock.gif            
if(toBeDisplay != null)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
while(toBeDisplay.Read())
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    
this.listBox.Items.Add(toBeDisplay.GetValue(2));
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void btnTestExpire_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            Database db 
= DatabaseFactory.CreateDatabase("Database Instance");
InBlock.gif            DataSet ds 
= db.ExecuteDataSet(CommandType.Text,"Select * from Products");
InBlock.gif        
InBlock.gif            IsolatedCacheManager 
= CacheFactory.GetCacheManager("Isolated Cache Manager");
InBlock.gif            
InBlock.gif            DateTime refreshTime 
= new DateTime(2005624125130);
InBlock.gif            AbsoluteTime expireTime 
= new AbsoluteTime(refreshTime);
InBlock.gif                    
InBlock.gif            IsolatedCacheManager.Add(
"MyDataSet",ds, CacheItemPriority.Normal, null,expireTime);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void btnReview_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.label.Text = System.Convert.ToString(IsolatedCacheManager.Count);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void button1_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif        
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void btnFileDependency_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            FileDependency expireNotice 
= new FileDependency("DependencyFile.txt");
InBlock.gif                
InBlock.gif            myCacheManager.Add(
"FileKey""String: Test Cache Item Dependency", CacheItemPriority.Normal, null, expireNotice);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void btnQueryByFile_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.label.Text = System.Convert.ToString(myCacheManager.Count);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void button1_Click_1(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            myCacheManager.Remove(
"FileKey");
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void button2_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
for(int intCount=0; intCount<8; intCount++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
string strKeyName = "Key"+System.Convert.ToString(intCount);
InBlock.gif                
InBlock.gif                
if (intCount%2 == 0)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    myCacheManager.Add(strKeyName, 
"High", CacheItemPriority.High, nullnull);
ExpandedSubBlockEnd.gif                }

InBlock.gif                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif{
InBlock.gif                    myCacheManager.Add(strKeyName, 
"Low", CacheItemPriority.Low, nullnull);
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
private void button3_Click(object sender, System.EventArgs e)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
for(int intCount=0; intCount<5; intCount++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
string strKeyName = "HighKey"+System.Convert.ToString(intCount);
InBlock.gif                myCacheManager.Add(strKeyName, 
"High", CacheItemPriority.High, nullnull);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值