一,Window于Document区别:
不要混淆Window对象的location属性和Document对象的location属性。前者引用一个Location对象,而后者只是一个只读字符串,并不具有Location对象的任何特性。document.location与document.URL是同义的,后者在 JavaScript1.1中是该属性的首选名称(因为这样避免了潜在的混淆)。在大多数情况下,document.location和 location.href是相同的。但是,当存在服务器重定向时,document.location包含的是已经装载的URL,而 location.href包含的则是原始请求的文档的URL。
二,asp .NET 脚本跳出对话框:
<p>对话框有三种</p>
<p>1:只是提醒,不能对脚本产生任何改变;</p>
<p>2:一般用于确认,返回 true 或者 false ,所以可以轻松用于 ifelse判断 </p>
<p>3: 一个带输入的对话框,可以返回用户填入的字符串,常见于某些留言本或者论坛输入内容那里的 插入UBB格式图片 </p>
<p>下面我们分别演示:</p>
<p>演示一:提醒 对话框</p>
<p>
<input type="submit" name="Submit" value="提交" οnclick="ale()" />
</p>
<p>演示二 :确认对话框 </p>
<p>
<input type="submit" name="Submit2" value="提交" οnclick="firm()" />
</p>
<p>演示三 :要求用户输入,然后给个结果</p>
<p>
<input type="submit" name="Submit3" value="提交" οnclick="prom()" />
</p>
</body>
</html>
三,ASP .Net 页面生命周期描述
下面是ASP.NET页面初始的过程:
1. Page_Init();
2. Load ViewState;
3. Load Postback data;
4. Page_Load();
5. Handle control events;
6. Page_PreRender();
7. Page_Render();
8. Unload event;
9. Dispose method called;
下面对其中的一些过程作下描述:
1. Page_Init();
这个过程主要是初始化控件,每次页面载入执行这个初始过程,包括第一次和以后的Postback(这里说下Postback,其实就可以简单理解成用户点击 SUBMIT按钮之类的,把表单<Form>提交给服务器,这就是一次postback),在这里面可以访问控件,但是这里面的控件值不是我们期待的控件里面的值,他只是一个控件的初始值(默认值),举例: 比如一个TextBox1,我们填入了"哈哈",在点击SUBMIT提交了页面后,在Page_Init()里面,我们访问到的 TextBox1.Text不是我们的"哈哈",而是开始的""空字符串,如果TextBox1在我们设计的时候提供了默认值,这里访问到的也就是提供的默认值,为什么呢,这就要看下一个过程了.
对应的事件Page.Init
2. Load ViewState
这个过程是载入VIEWSTATE和Postback数据,比如我们上面的TextBox1,这时就赋了"哈哈",所以,在Post_Init()对控件赋值是无意义的,它都会在这个过程里被改写,当然第一次页面载入例外,因为没有VIEWSTATE数据。
没有对应的事件
3.Load Postback data;
上面说了,Postback可以理解成用户提交表单数据,所以这里就是处理表单数据,当然这里要设计到控件的设计,一般情况不会要我们自己处理这个过程,我们暂且略过.
没有对应的事件
4. Page_Load();
这个过程也是每次页面载入时一定会执行的,但是注意和Page_Init的区别,上面已经涉及了,这里注意的是一般都会用到Page.IsPostBack,该值指示该页是否正为响应客户端回发而加载,或者它是否正被首次加载和访问。
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
//第一次执行的CODE HERE
}
else
{
//用户提交FORM(即Postback)CODE HERE
}
//每次这里的都会执行CODE HERE
}
对应的事件Page.Load
5. Handle control events;
这个过程里,相应具体的控件事件,比如private void ListBox1_SelectedIndexChanged(object sender, System.EventArgs e)事件等等
没有对应的事件(我们自己的事件函数都包括在这个过程里比如上面的ListBox1_SelectedIndexChanged)
6. Page_PreRender();
预先呈递对象,这里是在向用户程序呈现数据的倒数第二步,提供这个过程的意义,就是在这里能对控件属性等等要呈现给用户的数据进行修改,这也是最后的修改, 以前的修改(比如在Page_Init里面)都可能被覆盖.做完这了还会进行一个操作就是保存状态,即SaveViewState.
对应的事件时Page.PreRender
7. Page_Render();
可以在浏览器里View->Source查看到,每个页面都有一个隐藏的<input>,其中的"__VIEWSTATE"就是服务器写回来的页面状态信息,在这个之前,服务器要呈现页面(也就是构造HTML格式的文件),就是从这个"__VIEWSTATE"里面获取的数据,当然也会注意到,这里有个Page.Render事件,可以添加自己的处理代码,也就是说在这里又可以更改数据,不推荐在这里修改,既然提供了PreRender, 就应该在里面做最后的修改,当然这不是必须的,只是推荐!
对应的事件Page.Render
8. Unload event;
当向服务器请求一个对象的时候,会在内存里生成一个继承页面对象,也就是页面的类,它继承自System.Web.UI.Page.
当页面对象从内存中卸载时发生,将触发该事件.
对应的事件Page.Unload
9. Dispose method called;
销毁所有的对象.当从内存释放Page时发生,这是生存期的最后阶段。可能第8和9似乎有些模糊,不过我也没怎么搞清楚,待研究!
对应的事件Dispose
以上就是ASP.NET页面周期的描述。
四,ibatis执行insert返回主键的设置方法:
在<insert id="Insert" parameterClass="SysAuthUsers">
</insert>里添加<selectKey resultClass="int" type="post" property="Id" >
select @@IDENTITY as value
</selectKey>
需要注意的地方:<selectKey>里的property的值必须跟
<resultMaps>
<resultMap id="FullResultMap" class="SysAuthUsers">
<result property="Id" column="ID" dbType="Int"/>
<result property="Code" column="Code" dbType="NVarChar"/>
<result property="Username" column="UserName" dbType="NVarChar"/>
<result property="Password" column="PassWord" dbType="NVarChar"/>
<result property="Roles" column="Roles" dbType="NVarChar"/>
<result property="Depid" column="DepID" dbType="NVarChar"/>
<result property="Typeid" column="TypeID" dbType="NVarChar"/>
<result property="Dutyid" column="DutyID" dbType="NVarChar"/>
<result property="Issys" column="IsSys" dbType="Bit"/>
<result property="Ulock" column="ULock" dbType="Bit"/>
</resultMap>
</resultMaps>里的property同名,ibatis是区分大小写的。
五,ibatis执行insert语句判断是否执行成功的两种方法:
(1)通过执行return sqlMap.Insert(NAME_SPACE + "Insert", userRntity);判断返回的 数据库 主键,如果返回的是null表示insert失败,否则insert成功,因为主键有int和string等多种类型所以返回值是object类型。
(2)执行调用sqlMaps[i].Update(statementName, parameterObject);方法,虽然调用的是update方法,但是却是执行的insert语句,注意xml文件的节点写法:(因为是用id属性所以有两个<update>没有关系)。
<update id="Insert" parameterClass="SysAuthUsers">
INSERT INTO [dbo].[sys_auth_Users] (
[Code]
, [UserName]
, [PassWord]
, [Roles]
, [DepID]
, [TypeID]
, [DutyID]
, [IsSys]
, [ULock]
) VALUES (
#Code,dbType=NVarChar#
, #Username,dbType=NVarChar#
, #Password,dbType=NVarChar#
, #Roles,dbType=NVarChar#
, #Depid,dbType=NVarChar#
, #Typeid,dbType=NVarChar#
, #Dutyid,dbType=NVarChar#
, #Issys,dbType=Bit#
, #Ulock,dbType=Bit#
)
</update>
<update id="Update" parameterClass="SysAuthUsers">
UPDATE [dbo].[sys_auth_Users] SET
[Code] = #Code,dbType=NVarChar#
, [UserName] = #Username,dbType=NVarChar#
, [PassWord] = #Password,dbType=NVarChar#
, [Roles] = #Roles,dbType=NVarChar#
, [DepID] = #Depid,dbType=NVarChar#
, [TypeID] = #Typeid,dbType=NVarChar#
, [DutyID] = #Dutyid,dbType=NVarChar#
, [IsSys] = #Issys,dbType=Bit#
, [ULock] = #Ulock,dbType=Bit#
WHERE
([ID] = #Id,dbType=Int#)
</update>
六,Ibatis.net里的缓存解决方案:
IBatis.Net学习笔记四--数据库的缓存模式
在IBatis中提供了数据库缓存的模式,可以提高访问效率。对于一些不常更新的表可以直接利用IBatis的缓存方式。
要使用IBatis的数据库缓存,只要利用配置文件就可以了,实现起来比较简单:
<select id="GetCachedAccountsViaResultMap"
resultMap="account-result"
cacheModel="account-cache" >
select *
from Accounts
order by Account_ID
</select>
最主要的就是cacheModel="account-cache",指定缓存的方式,如下,是具体配置缓存的地方:
<cacheModels>
<cacheModel id="account-cache" implementation="MEMORY" >
<flushInterval hours="24"/>
<flushOnExecute statement="UpdateAccountViaInlineParameters"/>
<flushOnExecute statement="UpdateAccountViaParameterMap"/>
<flushOnExecute statement="InsertAccountViaParameterMap"/>
<property name="Type" value="Weak"/>
</cacheModel>
</cacheModels>
其中:implementation="MEMORY"是设置缓存的实现方式,可以指定LRU、FIFO等,有点类似于内存的页替换策略。MEMORY是最常使用的一种方式。
flushOnExecute设置的是当执行了这些语句时更新缓存。
配置好之后我进行了一个简单的 测试 ,基本上是可以的,但也有一点问题:
1、第一次查询结果是4条记录,当我手工往数据库中插入一条记录时,第二次查询还是4条记录
2、当我把系统时间改成第二天(24小时后),再查,得到的结果是5条记录
3、当我执行了InsertAccountViaParameterMap语句插入一条记录时,再查询得到的是6条记录
也就是说:当系统中的表从不进行手工维护,也不由第三方程序修改时,可以使用数据库缓存的方式提高效率。
七,ibatis下用memocache替换掉ibatis自身的缓存解决方案:momocache的优点参见八,momocache的优点
近有个项目, 使用Ibatis.net需要部署在负载均衡的环境下, 显然Ibatis.net的内置缓存方式, 是不能适用的.
多个Web服务器之间的缓存不能进行同步是问题的关键. 于是决定扩展他的缓存策略, 使用MemCached.
Ibatis.net现有的缓存方式有: MEMORY, LRU, FIFO, 我们扩展一个叫MemCached的方式.
1. 实现一个ICacheController类, 先要下载一个MemCaced的客户端,
我使用的是enyim.com memcached 1.2.0.2的客户端.
/// <summary>
/// 使用MemCached做分布式缓存
/// </summary>
public class MemCachedController : ICacheController
{
MemcachedClient _mc = null;
private int _cacheSize = 0;
private IList _keyList = null;
/// <summary>
///
/// </summary>
public MemCachedController()
{
_mc = new MemcachedClient();
_cacheSize = 100;
_keyList = ArrayList.Synchronized(new ArrayList());
}
#region ICacheController Members
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object this[object key]
{
get
{
_keyList.Remove(key);
_keyList.Add(key);
return _mc.Get(key.ToString());
}
set
{
_mc.Store(StoreMode.Set, key.ToString(), value);
_keyList.Add(key);
if (_keyList.Count > _cacheSize)
{
object oldestKey = _keyList[0];
_keyList.Remove(0);
_mc.Remove(oldestKey.ToString());
}
}
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object Remove(object key)
{
//object o = _mc.Get(key.ToString());
_keyList.Remove(key);
_mc.Remove(key.ToString());
return null;
}
/// <summary>
///
/// </summary>
public void Flush()
{
//_mc.FlushAll();
foreach (object arr in _keyList)
{
_mc.Remove(arr.ToString());
}
_keyList.Clear();
}
/// <summary>
///
/// </summary>
/// <param name="properties"></param>
public void Configure(System.Collections.IDictionary properties)
{
string size = (string)properties["CacheSize"];
if (size != null)
{
_cacheSize = Convert.ToInt32(size);
}
}
#endregion
}
如上, 比较简单.
2. 第二步在DomSqlMapBuilder类中注册我们的新缓存类型.
// xionglx添加的使用MemCached
cacheAlias = new TypeAlias(typeof(MemCachedController));
cacheAlias.Name = "MEMCACHED";
_configScope.SqlMapper.TypeHandlerFactory.AddTypeAlias(cacheAlias.Name, cacheAlias);
3. 在SqlMap.xsd配置文件中注册新的类型,
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="LRU"/>
<xs:enumeration value="MEMORY"/>
<xs:enumeration value="FIFO"/>
<xs:enumeration value="MEMCACHED"/>
</xs:restriction>
</xs:simpleType>
4. Web.Config中添加配置.
<!--memcached-->
<sectionGroup name="enyim.com">
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</sectionGroup>
<enyim.com>
<memcached>
<servers>
<add address="127.0.0.1" port="11211" />
<!--<add address="127.0.0.1" port="20004" />-->
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:10:00" deadTimeout="00:02:00" />
</memcached>
</enyim.com>
经过测试, 可以正常的访问MemeCached服务端, 并且缓存正常.
需要注意的是, 实体类需要标记为可序列化. 在Map文件的缓存策略中,
<cacheModels>
<cacheModel id="ModuleCache" implementation="MEMCACHED" readOnly="false">
<flushInterval hours="24"/>
<flushOnExecute statement="Module.Insert"/>
<flushOnExecute statement="Module.Update"/>
<flushOnExecute statement="Module.Delete"/>
<property name="CacheSize" value="100"/>
</cacheModel>
</cacheModels>
不能使用serialize="true", 反序列化的时候会出错, 我还没仔细查原因. 这里readOnly="false"是说, 这个对象是
会发生更改的, 只有那些系统初始化后, 不会发生变化的数据,才设置成readOnly="true".
八,momocache的优点于却缺点:
Memcached 是“分布式”的内存对象缓存系统,那么就是说,那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应用,memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源,即使是UNIX本地连接也一样。在我之前的测试数据中显示,memcached本地读写速度要比直接 PHP 内存数组慢几十倍,而APC、共享内存方式都和直接数组差不多。可见,如果只是本地级缓存,使用memcached是非常不划算的。
使用方法:
Memcached的使用
一 Memcached服务器端的安装 (此处将其作为系统服务安装)
下载文件:memcached 1.2.1 for Win32 binaries (Dec 23, 2006)
1 解压缩文件到c:/memcached
2 命令行输入 'c:/memcached/memcached.exe -d install'
3 命令行输入 'c:/memcached/memcached.exe -d start' ,该命令启动 Memcached ,默认监听端口为 11211
通过 memcached.exe -h 可以查看其帮助
不要混淆Window对象的location属性和Document对象的location属性。前者引用一个Location对象,而后者只是一个只读字符串,并不具有Location对象的任何特性。document.location与document.URL是同义的,后者在 JavaScript1.1中是该属性的首选名称(因为这样避免了潜在的混淆)。在大多数情况下,document.location和 location.href是相同的。但是,当存在服务器重定向时,document.location包含的是已经装载的URL,而 location.href包含的则是原始请求的文档的URL。
二,asp .NET 脚本跳出对话框:
<p>对话框有三种</p>
<p>1:只是提醒,不能对脚本产生任何改变;</p>
<p>2:一般用于确认,返回 true 或者 false ,所以可以轻松用于 ifelse判断 </p>
<p>3: 一个带输入的对话框,可以返回用户填入的字符串,常见于某些留言本或者论坛输入内容那里的 插入UBB格式图片 </p>
<p>下面我们分别演示:</p>
<p>演示一:提醒 对话框</p>
<p>
<input type="submit" name="Submit" value="提交" οnclick="ale()" />
</p>
<p>演示二 :确认对话框 </p>
<p>
<input type="submit" name="Submit2" value="提交" οnclick="firm()" />
</p>
<p>演示三 :要求用户输入,然后给个结果</p>
<p>
<input type="submit" name="Submit3" value="提交" οnclick="prom()" />
</p>
</body>
</html>
三,ASP .Net 页面生命周期描述
下面是ASP.NET页面初始的过程:
1. Page_Init();
2. Load ViewState;
3. Load Postback data;
4. Page_Load();
5. Handle control events;
6. Page_PreRender();
7. Page_Render();
8. Unload event;
9. Dispose method called;
下面对其中的一些过程作下描述:
1. Page_Init();
这个过程主要是初始化控件,每次页面载入执行这个初始过程,包括第一次和以后的Postback(这里说下Postback,其实就可以简单理解成用户点击 SUBMIT按钮之类的,把表单<Form>提交给服务器,这就是一次postback),在这里面可以访问控件,但是这里面的控件值不是我们期待的控件里面的值,他只是一个控件的初始值(默认值),举例: 比如一个TextBox1,我们填入了"哈哈",在点击SUBMIT提交了页面后,在Page_Init()里面,我们访问到的 TextBox1.Text不是我们的"哈哈",而是开始的""空字符串,如果TextBox1在我们设计的时候提供了默认值,这里访问到的也就是提供的默认值,为什么呢,这就要看下一个过程了.
对应的事件Page.Init
2. Load ViewState
这个过程是载入VIEWSTATE和Postback数据,比如我们上面的TextBox1,这时就赋了"哈哈",所以,在Post_Init()对控件赋值是无意义的,它都会在这个过程里被改写,当然第一次页面载入例外,因为没有VIEWSTATE数据。
没有对应的事件
3.Load Postback data;
上面说了,Postback可以理解成用户提交表单数据,所以这里就是处理表单数据,当然这里要设计到控件的设计,一般情况不会要我们自己处理这个过程,我们暂且略过.
没有对应的事件
4. Page_Load();
这个过程也是每次页面载入时一定会执行的,但是注意和Page_Init的区别,上面已经涉及了,这里注意的是一般都会用到Page.IsPostBack,该值指示该页是否正为响应客户端回发而加载,或者它是否正被首次加载和访问。
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
//第一次执行的CODE HERE
}
else
{
//用户提交FORM(即Postback)CODE HERE
}
//每次这里的都会执行CODE HERE
}
对应的事件Page.Load
5. Handle control events;
这个过程里,相应具体的控件事件,比如private void ListBox1_SelectedIndexChanged(object sender, System.EventArgs e)事件等等
没有对应的事件(我们自己的事件函数都包括在这个过程里比如上面的ListBox1_SelectedIndexChanged)
6. Page_PreRender();
预先呈递对象,这里是在向用户程序呈现数据的倒数第二步,提供这个过程的意义,就是在这里能对控件属性等等要呈现给用户的数据进行修改,这也是最后的修改, 以前的修改(比如在Page_Init里面)都可能被覆盖.做完这了还会进行一个操作就是保存状态,即SaveViewState.
对应的事件时Page.PreRender
7. Page_Render();
可以在浏览器里View->Source查看到,每个页面都有一个隐藏的<input>,其中的"__VIEWSTATE"就是服务器写回来的页面状态信息,在这个之前,服务器要呈现页面(也就是构造HTML格式的文件),就是从这个"__VIEWSTATE"里面获取的数据,当然也会注意到,这里有个Page.Render事件,可以添加自己的处理代码,也就是说在这里又可以更改数据,不推荐在这里修改,既然提供了PreRender, 就应该在里面做最后的修改,当然这不是必须的,只是推荐!
对应的事件Page.Render
8. Unload event;
当向服务器请求一个对象的时候,会在内存里生成一个继承页面对象,也就是页面的类,它继承自System.Web.UI.Page.
当页面对象从内存中卸载时发生,将触发该事件.
对应的事件Page.Unload
9. Dispose method called;
销毁所有的对象.当从内存释放Page时发生,这是生存期的最后阶段。可能第8和9似乎有些模糊,不过我也没怎么搞清楚,待研究!
对应的事件Dispose
以上就是ASP.NET页面周期的描述。
四,ibatis执行insert返回主键的设置方法:
在<insert id="Insert" parameterClass="SysAuthUsers">
</insert>里添加<selectKey resultClass="int" type="post" property="Id" >
select @@IDENTITY as value
</selectKey>
需要注意的地方:<selectKey>里的property的值必须跟
<resultMaps>
<resultMap id="FullResultMap" class="SysAuthUsers">
<result property="Id" column="ID" dbType="Int"/>
<result property="Code" column="Code" dbType="NVarChar"/>
<result property="Username" column="UserName" dbType="NVarChar"/>
<result property="Password" column="PassWord" dbType="NVarChar"/>
<result property="Roles" column="Roles" dbType="NVarChar"/>
<result property="Depid" column="DepID" dbType="NVarChar"/>
<result property="Typeid" column="TypeID" dbType="NVarChar"/>
<result property="Dutyid" column="DutyID" dbType="NVarChar"/>
<result property="Issys" column="IsSys" dbType="Bit"/>
<result property="Ulock" column="ULock" dbType="Bit"/>
</resultMap>
</resultMaps>里的property同名,ibatis是区分大小写的。
五,ibatis执行insert语句判断是否执行成功的两种方法:
(1)通过执行return sqlMap.Insert(NAME_SPACE + "Insert", userRntity);判断返回的 数据库 主键,如果返回的是null表示insert失败,否则insert成功,因为主键有int和string等多种类型所以返回值是object类型。
(2)执行调用sqlMaps[i].Update(statementName, parameterObject);方法,虽然调用的是update方法,但是却是执行的insert语句,注意xml文件的节点写法:(因为是用id属性所以有两个<update>没有关系)。
<update id="Insert" parameterClass="SysAuthUsers">
INSERT INTO [dbo].[sys_auth_Users] (
[Code]
, [UserName]
, [PassWord]
, [Roles]
, [DepID]
, [TypeID]
, [DutyID]
, [IsSys]
, [ULock]
) VALUES (
#Code,dbType=NVarChar#
, #Username,dbType=NVarChar#
, #Password,dbType=NVarChar#
, #Roles,dbType=NVarChar#
, #Depid,dbType=NVarChar#
, #Typeid,dbType=NVarChar#
, #Dutyid,dbType=NVarChar#
, #Issys,dbType=Bit#
, #Ulock,dbType=Bit#
)
</update>
<update id="Update" parameterClass="SysAuthUsers">
UPDATE [dbo].[sys_auth_Users] SET
[Code] = #Code,dbType=NVarChar#
, [UserName] = #Username,dbType=NVarChar#
, [PassWord] = #Password,dbType=NVarChar#
, [Roles] = #Roles,dbType=NVarChar#
, [DepID] = #Depid,dbType=NVarChar#
, [TypeID] = #Typeid,dbType=NVarChar#
, [DutyID] = #Dutyid,dbType=NVarChar#
, [IsSys] = #Issys,dbType=Bit#
, [ULock] = #Ulock,dbType=Bit#
WHERE
([ID] = #Id,dbType=Int#)
</update>
六,Ibatis.net里的缓存解决方案:
IBatis.Net学习笔记四--数据库的缓存模式
在IBatis中提供了数据库缓存的模式,可以提高访问效率。对于一些不常更新的表可以直接利用IBatis的缓存方式。
要使用IBatis的数据库缓存,只要利用配置文件就可以了,实现起来比较简单:
<select id="GetCachedAccountsViaResultMap"
resultMap="account-result"
cacheModel="account-cache" >
select *
from Accounts
order by Account_ID
</select>
最主要的就是cacheModel="account-cache",指定缓存的方式,如下,是具体配置缓存的地方:
<cacheModels>
<cacheModel id="account-cache" implementation="MEMORY" >
<flushInterval hours="24"/>
<flushOnExecute statement="UpdateAccountViaInlineParameters"/>
<flushOnExecute statement="UpdateAccountViaParameterMap"/>
<flushOnExecute statement="InsertAccountViaParameterMap"/>
<property name="Type" value="Weak"/>
</cacheModel>
</cacheModels>
其中:implementation="MEMORY"是设置缓存的实现方式,可以指定LRU、FIFO等,有点类似于内存的页替换策略。MEMORY是最常使用的一种方式。
flushOnExecute设置的是当执行了这些语句时更新缓存。
配置好之后我进行了一个简单的 测试 ,基本上是可以的,但也有一点问题:
1、第一次查询结果是4条记录,当我手工往数据库中插入一条记录时,第二次查询还是4条记录
2、当我把系统时间改成第二天(24小时后),再查,得到的结果是5条记录
3、当我执行了InsertAccountViaParameterMap语句插入一条记录时,再查询得到的是6条记录
也就是说:当系统中的表从不进行手工维护,也不由第三方程序修改时,可以使用数据库缓存的方式提高效率。
七,ibatis下用memocache替换掉ibatis自身的缓存解决方案:momocache的优点参见八,momocache的优点
近有个项目, 使用Ibatis.net需要部署在负载均衡的环境下, 显然Ibatis.net的内置缓存方式, 是不能适用的.
多个Web服务器之间的缓存不能进行同步是问题的关键. 于是决定扩展他的缓存策略, 使用MemCached.
Ibatis.net现有的缓存方式有: MEMORY, LRU, FIFO, 我们扩展一个叫MemCached的方式.
1. 实现一个ICacheController类, 先要下载一个MemCaced的客户端,
我使用的是enyim.com memcached 1.2.0.2的客户端.
/// <summary>
/// 使用MemCached做分布式缓存
/// </summary>
public class MemCachedController : ICacheController
{
MemcachedClient _mc = null;
private int _cacheSize = 0;
private IList _keyList = null;
/// <summary>
///
/// </summary>
public MemCachedController()
{
_mc = new MemcachedClient();
_cacheSize = 100;
_keyList = ArrayList.Synchronized(new ArrayList());
}
#region ICacheController Members
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object this[object key]
{
get
{
_keyList.Remove(key);
_keyList.Add(key);
return _mc.Get(key.ToString());
}
set
{
_mc.Store(StoreMode.Set, key.ToString(), value);
_keyList.Add(key);
if (_keyList.Count > _cacheSize)
{
object oldestKey = _keyList[0];
_keyList.Remove(0);
_mc.Remove(oldestKey.ToString());
}
}
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object Remove(object key)
{
//object o = _mc.Get(key.ToString());
_keyList.Remove(key);
_mc.Remove(key.ToString());
return null;
}
/// <summary>
///
/// </summary>
public void Flush()
{
//_mc.FlushAll();
foreach (object arr in _keyList)
{
_mc.Remove(arr.ToString());
}
_keyList.Clear();
}
/// <summary>
///
/// </summary>
/// <param name="properties"></param>
public void Configure(System.Collections.IDictionary properties)
{
string size = (string)properties["CacheSize"];
if (size != null)
{
_cacheSize = Convert.ToInt32(size);
}
}
#endregion
}
如上, 比较简单.
2. 第二步在DomSqlMapBuilder类中注册我们的新缓存类型.
// xionglx添加的使用MemCached
cacheAlias = new TypeAlias(typeof(MemCachedController));
cacheAlias.Name = "MEMCACHED";
_configScope.SqlMapper.TypeHandlerFactory.AddTypeAlias(cacheAlias.Name, cacheAlias);
3. 在SqlMap.xsd配置文件中注册新的类型,
<xs:simpleType>
<xs:restriction base="xs:NMTOKEN">
<xs:enumeration value="LRU"/>
<xs:enumeration value="MEMORY"/>
<xs:enumeration value="FIFO"/>
<xs:enumeration value="MEMCACHED"/>
</xs:restriction>
</xs:simpleType>
4. Web.Config中添加配置.
<!--memcached-->
<sectionGroup name="enyim.com">
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</sectionGroup>
<enyim.com>
<memcached>
<servers>
<add address="127.0.0.1" port="11211" />
<!--<add address="127.0.0.1" port="20004" />-->
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:10:00" deadTimeout="00:02:00" />
</memcached>
</enyim.com>
经过测试, 可以正常的访问MemeCached服务端, 并且缓存正常.
需要注意的是, 实体类需要标记为可序列化. 在Map文件的缓存策略中,
<cacheModels>
<cacheModel id="ModuleCache" implementation="MEMCACHED" readOnly="false">
<flushInterval hours="24"/>
<flushOnExecute statement="Module.Insert"/>
<flushOnExecute statement="Module.Update"/>
<flushOnExecute statement="Module.Delete"/>
<property name="CacheSize" value="100"/>
</cacheModel>
</cacheModels>
不能使用serialize="true", 反序列化的时候会出错, 我还没仔细查原因. 这里readOnly="false"是说, 这个对象是
会发生更改的, 只有那些系统初始化后, 不会发生变化的数据,才设置成readOnly="true".
八,momocache的优点于却缺点:
Memcached 是“分布式”的内存对象缓存系统,那么就是说,那些不需要“分布”的,不需要共享的,或者干脆规模小到只有一台服务器的应用,memcached不会带来任何好处,相反还会拖慢系统效率,因为网络连接同样需要资源,即使是UNIX本地连接也一样。在我之前的测试数据中显示,memcached本地读写速度要比直接 PHP 内存数组慢几十倍,而APC、共享内存方式都和直接数组差不多。可见,如果只是本地级缓存,使用memcached是非常不划算的。
使用方法:
Memcached的使用
一 Memcached服务器端的安装 (此处将其作为系统服务安装)
下载文件:memcached 1.2.1 for Win32 binaries (Dec 23, 2006)
1 解压缩文件到c:/memcached
2 命令行输入 'c:/memcached/memcached.exe -d install'
3 命令行输入 'c:/memcached/memcached.exe -d start' ,该命令启动 Memcached ,默认监听端口为 11211
通过 memcached.exe -h 可以查看其帮助