分类:java/ssh/webx

Java Exception性能问题[转]

背景:
大学里学java,老师口口声声,言之凿凿,告诫我们,Java千万别用异常控制业务流程,只有系统级别的问题,才能使用异常;
(当时,我们都不懂为什么不能用异常,只知道老师这么说,我们就这么做,考试才不会错 🙂 )
公司里,有两派.异常拥护者说,使用业务异常,代码逻辑更清晰,更OOP;反之者说,使用异常,性能非常糟糕;
(当然,我是拥护者)
论坛上,争论得更多,仁者见仁智者见智,口水很多;
(我不发表意见,其实怎么用,真的都可以)

那么,为什么反对异常呢?貌似大多数人的原因都只有一个:性能差!
使用异常性能真的差吗? 是的!
是什么原因,导致性能问题呢? 那么请看下文…

根本原因在于:
异常基类Throwable.java的public synchronized native Throwable fillInStackTrace()方法
方法介绍:
Fills in the execution stack trace. This method records within this Throwable object information about the current state of the stack frames for the current thread.
性能开销在于:
1. 是一个synchronized方法(主因)
2. 需要填充线程运行堆栈信息

但是对于业务异常来说,它只代表业务分支;压根儿不需要stack信息的.如果去掉这个过程,是不是有性能提升呢?

于是做了一个简单的测试对比,对比主体:
1。 创建普通Java对象              (CustomObject extends HashMap)
2。 创建普通Java异常对象          (CustomException extends Exception)
3。 创建改进的Java业务异常对象    (CustomException extends Exception,覆写fillInStackTrace方法,并且去掉同步)

测试结果:
(运行环境:xen虚拟机,5.5G内存,8核;jdk1.6.0_18)
(10个线程,创建10000000个对象所需时间)
普通Java对象         45284 MS
普通java异常        205482 MS
改进的Java业务异常   16731 MS

测试代码如下:

  1 /**
2  * <pre>
3  * xen虚拟机,5.5G内存;8核CPU
4  * LOOP = 10000000
5  * THREADS = 10
6  * o:       45284
7  * e:       205482
8  * exte:    16731
9  * </pre>
10  *
11  * k
12  *
13  * @author li.jinl 2010-7-9 上午09:16:14
14  */
15 public class NewExceptionTester {
16
17     private static final int             LOOP                 = 10000000;                        // 单次循环数量
18     private static final int             THREADS              = 10;                              // 并发线程数量
19
20     private static final List<Long>      newObjectTimes       = new ArrayList<Long>(THREADS);
21     private static final List<Long>      newExceptionTimes    = new ArrayList<Long>(THREADS);
22     private static final List<Long>      newExtExceptionTimes = new ArrayList<Long>(THREADS);
23
24     private static final ExecutorService POOL                 = Executors.newFixedThreadPool(30);
25
26     public static void main(String[] args) throws Exception {
27         List<Callable<Boolean>> all = new ArrayList<Callable<Boolean>>();
28         all.addAll(tasks(new NewObject()));
29         all.addAll(tasks(new NewException()));
30         all.addAll(tasks(new NewExtException()));
31
32         POOL.invokeAll(all);
33
34         System.out.println(“o:\t\t” + total(newObjectTimes));
35         System.out.println(“e:\t\t” + total(newExceptionTimes));
36         System.out.println(“exte:\t\t” + total(newExtExceptionTimes));
37
38         POOL.shutdown();
39     }
40
41     private static List<Callable<Boolean>> tasks(Callable<Boolean> c) {
42         List<Callable<Boolean>> list = new ArrayList<Callable<Boolean>>(THREADS);
43         for (int i = 0; i < THREADS; i++) {
44             list.add(c);
45         }
46         return list;
47     }
48
49     private static long total(List<Long> list) {
50         long sum = 0;
51         for (Long v : list) {
52             sum += v;
53         }
54         return sum;
55     }
56
57     public static class NewObject implements Callable<Boolean> {
58
59         @Override
60         public Boolean call() throws Exception {
61             long start = System.currentTimeMillis();
62             for (int i = 0; i < LOOP; i++) {
63                 new CustomObject(“”);
64             }
65             newObjectTimes.add(System.currentTimeMillis() – start);
66             return true;
67         }
68
69     }
70
71     public static class NewException implements Callable<Boolean> {
72
73         @Override
74         public Boolean call() throws Exception {
75             long start = System.currentTimeMillis();
76             for (int i = 0; i < LOOP; i++) {
77                 new CustomException(“”);
78             }
79             newExceptionTimes.add(System.currentTimeMillis() – start);
80             return true;
81         }
82
83     }
84
85     public static class NewExtException implements Callable<Boolean> {
86
87         @Override
88         public Boolean call() throws Exception {
89             long start = System.currentTimeMillis();
90             for (int i = 0; i < LOOP; i++) {
91                 new ExtCustomException(“”);
92             }
93             newExtExceptionTimes.add(System.currentTimeMillis() – start);
94             return true;
95         }
96
97     }
98
99     /**
100      * 自定义java对象.
101      *
102      * @author li.jinl 2010-7-9 上午11:28:27
103      */
104     public static class CustomObject extends HashMap {
105
106         private static final long serialVersionUID = 5176739397156548105L;
107
108         private String            message;
109
110         public CustomObject(String message){
111             this.message = message;
112         }
113
114         public String getMessage() {
115             return message;
116         }
117
118         public void setMessage(String message) {
119             this.message = message;
120         }
121
122     }
123
124     /**
125      * 自定义普通的Exception对象
126      *
127      * @author li.jinl 2010-7-9 上午11:28:58
128      */
129     public static class CustomException extends Exception {
130
131         private static final long serialVersionUID = -6879298763723247455L;
132
133         private String            message;
134
135         public CustomException(String message){
136             this.message = message;
137         }
138
139         public String getMessage() {
140             return message;
141         }
142
143         public void setMessage(String message) {
144             this.message = message;
145         }
146
147     }
148
149     /**
150      * <pre>
151      * 自定义改进的Exception对象 覆写了 fillInStackTrace方法
152      * 1. 不填充stack
153      * 2. 取消同步
154      * </pre>
155      *
156      * @author li.jinl 2010-7-9 上午11:29:12
157      */
158     public static class ExtCustomException extends Exception {
159
160         private static final long serialVersionUID = -6879298763723247455L;
161
162         private String            message;
163
164         public ExtCustomException(String message){
165             this.message = message;
166         }
167
168         public String getMessage() {
169             return message;
170         }
171
172         public void setMessage(String message) {
173             this.message = message;
174         }
175
176         @Override
177         public Throwable fillInStackTrace() {
178             return this;
179         }
180     }
181 }

所以,如果我们业务异常的基类,一旦覆写fillInStackTrace,并且去掉同步,那么异常性能有大幅度提升(因为业务异常本身也不需要堆栈信息)

如果说,创建异常的性能开销大家已经有些感觉了,那么TryCatch是否也存在性能开销呢?
接下来,做了一次try…catch 和 if…esle的性能比较

测试结果(运行环境和上面一样):
20个线程,100000000,所消耗的时间:
try…catch:  101412MS
if…else:    100749MS

备注:
在我自己的开发机器上(xp和ubuntu下,单核),try…catch耗时是if…else的2倍(在同一数量级)
具体原因还未知,之后会使用专业的性能测试工具进行分析

测试代码如下:

  1 /**
2  * <pre>
3  * xen虚拟机,5.5G内存;8核CPU
4  * LOOP = 100000000
5  * THREADS = 20
6  *
7  * tc:  101412
8  * ie:  100749
9  * </pre>
10  *
11  * @author li.jinl 2010-7-9 上午10:47:56
12  */
13 public class ProcessTester {
14
15     private static final int             LOOP          = 100000000;
16     private static final int             THREADS       = 20;
17
18     private static final List<Long>      tryCatchTimes = new ArrayList<Long>(THREADS);
19     private static final List<Long>      ifElseTimes   = new ArrayList<Long>(THREADS);
20
21     private static final ExecutorService POOL          = Executors.newFixedThreadPool(40);
22
23     public static void main(String[] args) throws Exception {
24         List<Callable<Boolean>> all = new ArrayList<Callable<Boolean>>();
25         all.addAll(tasks(new TryCatch()));
26         all.addAll(tasks(new IfElse()));
27
28         POOL.invokeAll(all);
29
30         System.out.println(“tc:\t\t” + total(tryCatchTimes));
31         System.out.println(“ie:\t\t” + total(ifElseTimes));
32
33         POOL.shutdown();
34     }
35
36     private static List<Callable<Boolean>> tasks(Callable<Boolean> c) {
37         List<Callable<Boolean>> list = new ArrayList<Callable<Boolean>>(THREADS);
38         for (int i = 0; i < THREADS; i++) {
39             list.add(c);
40         }
41         return list;
42     }
43
44     private static long total(List<Long> list) {
45         long sum = 0;
46         for (Long v : list) {
47             sum += v;
48         }
49         return sum;
50     }
51
52     public static class TryCatch implements Callable<Boolean> {
53
54         @Override
55         public Boolean call() throws Exception {
56             long start = System.currentTimeMillis();
57             for (int i = 0; i < LOOP; i++) {
58                 try {
59                     exception();
60                     // 
61                 } catch (ExtCustomException e) {
62                     // 
63                 }
64             }
65             tryCatchTimes.add(System.currentTimeMillis() – start);
66             return true;
67         }
68
69         private void exception() throws ExtCustomException {
70             throw new ExtCustomException(“”);
71         }
72
73     }
74
75     public static class IfElse implements Callable<Boolean> {
76
77         @Override
78         public Boolean call() throws Exception {
79             long start = System.currentTimeMillis();
80             for (int i = 0; i < LOOP; i++) {
81                 Exception e = exception();
82                 if (e instanceof ExtCustomException) {
83                     // 
84                 }
85             }
86             ifElseTimes.add(System.currentTimeMillis() – start);
87             return true;
88         }
89
90         private Exception exception() {
91             return new ExtCustomException(“”);
92         }
93
94     }
95
96     public static class ExtCustomException extends Exception {
97
98         private static final long serialVersionUID = -6879298763723247455L;
99
100         private String            message;
101
102         public ExtCustomException(String message){
103             this.message = message;
104         }
105
106         public String getMessage() {
107             return message;
108         }
109
110         public void setMessage(String message) {
111             this.message = message;
112         }
113
114         @Override
115         public Throwable fillInStackTrace() {
116             return this;
117         }
118
119     }
120
121 }

结论:
1。Exception的性能是差,原因在于ThrowablefillInStackTrace()方法
2. 可以通过改写业务异常基类的方法,提升性能
3。try…catch和if…else的性能开销在同一数量级

4。至于是否使用异常进行业务逻辑的控制,主要看代码风格.(我个人挺喜欢业务异常的)

备注:
以上测试比较简单,写得也比较急.此文也写得比较急(工作时间偷偷写).如果分析不到位的地方,请指出.


jni内存泄露

在c++中new的对象,如果不返回java,必须用release掉,否则内存泄露。包括NewStringUTF,NewObject
。如果返回java不必release,java会自己回收。

jstring jstr = env->NewStringUTF((*p).sess_id);

env->DeleteLocalRef( jstr);

jobject jobj = env->NewObject(clazz,midInit);
return jobj;

内存泄露可以先从windows资源管理器中,看到随程序运行,内存不断增长的趋势,具体可以用hp jmeter检测在运行程序时,加jvm参数 -Xrunhprof:heap=all,cutoff=0 ,生成java.hprof.txt,用jmeter打开,Metric -> Residual Objects (Count),可以看到未回收的对象,选中要查看的对象,点Mark记录下要查看的对象,Window -> New Window 打开新窗口,用Metric -> Reference Graph Tree,然后点Find Immediately可以看到对象被哪里引用。

找出内存泄漏另一方法

程序有内存泄漏的第一个迹象通常是它抛出一个 DE>OutOfMemoryErrorDE>,或者因为频繁的垃圾收集而表现出糟糕的性能。幸运的是,垃圾收集可以提供能够用来诊断内存泄漏的大量信息。如果以 DE>-verbose:gcDE> 或者 DE>-XloggcDE> 选项调用 JVM,那么每次 GC 运行时在控制台上或者日志文件中会打印出一个诊断信息,包括它所花费的时间、当前堆使用情况以及恢复了多少内存。记录 GC 使用情况并不具有干扰性,因此如果需要分析内存问题或者调优垃圾收集器,在生产环境中默认启用 GC 日志是值得的。

有工具可以利用 GC 日志输出并以图形方式将它显示出来,JTune 就是这样的一种工具(请参阅 参考资料)。观察 GC 之后堆大小的图,可以看到程序内存使用的趋势。对于大多数程序来说,可以将内存使用分为两部分:baseline 使用和current load 使用。对于服务器应用程序,baseline 使用就是应用程序在没有任何负荷、但是已经准备好接受请求时的内存使用,current load 使用是在处理请求过程中使用的、但是在请求处理完成后会释放的内存。只要负荷大体上是恒定的,应用程序通常会很快达到一个稳定的内存使用水平。如果在应用程序已经完成了其初始化并且负荷没有增加的情况下,内存使用持续增加,那么程序就可能在处理前面的请求时保留了生成的对象。

 

图 1 显示  GC 之后应用程序堆大小随着时间的变化图。上升趋势是存在内存泄漏的警示信号。(在真实的应用程序中,坡度不会这么大,但是在收集了足够长时间的 GC 数据后,上升趋势通常会表现得很明显。)
图 1. 持续上升的内存使用趋势

确信有了内存泄漏后,下一步就是找出哪种对象造成了这个问题。所有内存分析器都可以生成按照对象类进行分解的堆快照。有一些很好的商业堆分析工具,但是找出内存泄漏不一定要花钱买这些工具 —— 内置的 DE>hprofDE> 工具也可完成这项工作。要使用 DE>hprofDE> 并让它跟踪内存使用,需要以 DE>-Xrunhprof:heap=sitesDE> 选项调用 JVM。

清单 3 显示分解了应用程序内存使用的 DE>hprofDE> 输出的相关部分。(DE>hprofDE> 工具在应用程序退出时,或者用 DE>kill -3DE> 或在 Windows 中按 Ctrl+Break 时生成使用分解。)注意两次快照相比,DE>Map.EntryDE>、DE>TaskDE> 和 DE>int[]DE> 对象有了显著增加。

请参阅 清单 3

清单 4 展示了 DE>hprofDE> 输出的另一部分,给出了 DE>Map.EntryDE> 对象的分配点的调用堆栈信息。这个输出告诉我们哪些调用链生成了 DE>Map.EntryDE> 对象,并带有一些程序分析,找出内存泄漏来源一般来说是相当容易的。
清单 4. HPROF 输出,显示 Map.Entry 对象的分配点

DE>    TRACE 300446:   java.util.HashMap$Entry.<init>(<Unknown Source>:Unknown line)   java.util.HashMap.addEntry(<Unknown Source>:Unknown line)   java.util.HashMap.put(<Unknown Source>:Unknown line)   java.util.Collections$SynchronizedMap.put(<Unknown Source>:Unknown line)   com.quiotix.dummy.MapLeaker.newTask(MapLeaker.java:48)   com.quiotix.dummy.MapLeaker.main(MapLeaker.java:64)  DE>

另外
jstring jstr = (jstring)env->CallObjectMethod(authenRequest, mid_authenReq_getSdId_S);
env->GetStringUTFRegion(jstr,0,env->GetStringLength(jstr),authenReq.sd_id);
当jstr是null时,env->GetStringLength(jstr)会出错,导致jvm崩溃

FROM: http://www.blogjava.net/neumqp/archive/2006/03/02/33152.html


使用maven建立多模块web项目

有时候我们需要创建多模块maven项目,即将传统的ssh项目中的model,dao,manager,service,view层划分成单个的maven module。具体步骤如下:

首先前提是必须安装好maven,在安装好maven之后进入命令行窗口,转到你所在的workspace目录

1.   生成父级工程

 

命令:

wanghaihua@wanghaihua-pc:~/workspace$ mvn archetype:create -DgroupId=com.duanqu -DartifactId=duanqu_2.0 

 

打开duanqu_2.0目录删除src文件夹,打开pom.xml,将packaging属性修改为pom(表示为父工程)

2.   生成子工程:

进入duanqu_2.0目录:

例如生成domain子工程

 

命令

wanghaihua@wanghaihua-pc:~/workspace$ mvn archetype:create -DgroupId=com.duanqu -DartifactId=duanqu-domain -Dpackage=com.duanqu.domain

 

   特例(web子项目)

 

命令

wanghaihua@wanghaihua-pc:~/workspace$ mvn archetype:create -DgroupId=com.duanqu -DartifactId=duanqu-web -Dpackage=com.duanqu.web -DarchetypeArtifactId=maven-archetype-webapp 

 

其中 -DarchetypeArtifactId=maven-archetype-webapp表示生成的子项目为web工程

 

   3.转换成eclipse项目:

 

命令

mvn eclipse:clean eclipse:eclipse

 

另:mvn eclipse:clean eclipse:eclipse -Dwtpversion=1.0据说可以完成自动热部署。还没试过。。

 


ibatis动态查询

IBatis 动态查询条件

下面这个配置基本上包含了最复杂的功能:分页\搜索\排序\缓存\传值Hash表\返回hash表\动态sql

<statement id=”XinxiTable_SelectAll” listClass=”ArrayList” resultMap=”SimpleXinxi” parameterClass=”Hashtable” cacheModel=”xinxi-cache” >

SELECT

<dynamic prepend=”top”>

<isNotEqual prepend=”top” property=”TopNum” compareValue = “0”>

$TopNum$

</isNotEqual>

</dynamic>

*

FROM

(select a.[iXinxiID],a.[sXinxiTitle],a.[iXinxiClassId],b.[sClassName],

a.[dXinxiDate],a.[dXinxiYxq],a.[iXinxiHits],a.[sXinxiUser],a.[sRedirectUrl],

ROW_NUMBER() OVER(

<dynamic prepend=”order by”>

<isEqual prepend=”order by” property=”Sort” compareValue = “0”>

a.iXinxiID desc

</isEqual>

<isEqual prepend=”order by” property=”Sort” compareValue = “1”>

a.iXinxiID asc

</isEqual>

<isEqual prepend=”order by” property=”Sort” compareValue = “2”>

a.iXinxiHits desc

</isEqual>

<isEqual prepend=”order by” property=”Sort” compareValue = “3”>

a.iXinxiHits asc

</isEqual>

</dynamic>

) as row

FROM

[dbo].[XinxiTable] as a,[dbo].[XinxiClass] as b

<dynamic prepend=”where”>

<isParameterPresent>

<isNotEmpty prepend=”and” property=”XinxiType” >

a.[iXinxiState]= $XinxiType$

</isNotEmpty>

<isNotEqual prepend=”and” property=”XinxiClass” compareValue = “0”>

a.[iXinxiClassID]= $XinxiClass$

</isNotEqual>

<isEqual prepend=”and” property=”SearchType” compareValue = “1”>

a.[sXinxiTitle] LIKE ‘%$Keyword$%’

</isEqual>

<isEqual prepend=”and” property=”SearchType” compareValue = “2”>

(a.[sXinxiTitle] LIKE ‘%$Keyword$%’ or a.[sXinxiContent] LIKE ‘%$Keyword$%’)

</isEqual>

</isParameterPresent>

</dynamic>

and a.iXinxiClassId=b.iClassId

)a

<dynamic prepend=”where”>

<isParameterPresent>

<isEqual prepend=”and” property=”IsPage” compareValue = “1”>

row between $PageLower$ and $PageUpper$

</isEqual>

</isParameterPresent>

</dynamic>

</statement>

ibatis动态查询条件:

<select id=”SelectEemployee” parameterClass=”string” resultMap = “employee-result”>

select * from employee

//动态SQL语句

<dynamic prepend=”WHERE”>

<isParameterPresent>

emp_id = #value#

</isParameterPresent>

</dynamic>

</select>

</statements>

</sqlMap>

/*动态SQL的写法:

开始 <dynamic

条件成立时前面要加的字符串 prepend =”字符串”>

<属性关键字  (见下表)

prepend=”字符串”

判断条件的对象属性名 property=”字符串”

如果是属性关键字是比较条件时,字符串存放要比较的值compareValue=”字符串”>

要显示的条件名

</属性关键字>

结束</dynamic>

*/

/*动态SQL的参数有

属性关键字

含义

<isEqual>

如果参数相等于值则查询条件有效。

<isNotEqual>

如果参数不等于值则查询条件有效。

<isGreaterThan>

如果参数大于值则查询条件有效。

<isGreaterEqual>

如果参数等于值则查询条件有效。

<isLessEqual>

如果参数小于值则查询条件有效。如下所示:

<isLessEqual prepend = ”AND” property = ”age” compareValue = ”18” >

ADOLESCENT = ‘TRUE’

</isLessEqual>

<isPropertyAvailable>

如果参数有使用则查询条件有效。

<isNotPropertyAvailable>

如果参数没有使用则查询条件有效。

<isNull>

如果参数为NULL则查询条件有效。

<isNotNull>

如果参数不为NULL则查询条件有效。

<isEmpty>

如果参数为空则查询条件有效。

<isNotEmpty>

如果参数不为空则查询条件有效。参数的数据类型为Collection、String 时参数不为NULL或“”。如下所示:

<isNotEmpty prepend=”AND” property=”firstName” >

FIRST_NAME=#firstName#

</isNotEmpty>

<isParameterPresent>

如果参数类不为NULL则查询条件有效。

<isNotParameterPresent>

Checks to see if the parameter object is not present (null). Example Usage:

<isNotParameterPresent prepend=”AND”>

EMPLOYEE_TYPE = ‘DEFAULT’

</isNotParameterPresent>


spring整合memcache,webx采用memcache存储session

记录些今天倒腾的东西

1、 搜索maven库,搜索出自己想要的库的groupid等信息

http://mvnrepository.com/

2、 spring下面整合memcache

memcache的java客户端选用的是xmemcache,可以在maven中心库中直接搜索到并使用

[codesyntax lang=”xml”]

	<bean name="memcachedClient" class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean">
		<property name="servers">
			<value>127.0.0.1:11211</value>
		</property>
	</bean>

[/codesyntax]

这样就可以在程序中使用MemcachedClient连接类了

[codesyntax lang=”java”]

public class Index {

	@Autowired
	private MemcachedClient memcachedClient;

	public void execute(Context context) {

		try {
			WebSiteDO web = new WebSiteDO();
			memcachedClient.set("test111", 30, web);
			WebSiteDO webCache = memcachedClient.get("test111");
			System.out.println(webCache.getImagesPath());
		} catch (TimeoutException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (MemcachedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
}

[/codesyntax]

3、webx中使用memcache来存储session

修改webx.xml中的session部分

[codesyntax lang=”xml”]

 	<session>
            <id>
                <cookie path="/" maxAge="2048" httpOnly="true" />
            </id>
           <stores>
			    <session-stores:store id="simple" class="cn.yundev.xzy.common.MemCacheSession"/> 
			</stores>
            <store-mappings>
                <match name="*" store="simple" />
            </store-mappings>
        </session>

[/codesyntax]

扩展session只需要继承接口SessionStore接口

[codesyntax lang=”java”]

public class MemCacheSession implements SessionStore {

	private MemcachedClient memcachedClient;

	public void init(String storeName, SessionConfig sessionConfig) throws Exception {
		ApplicationContext atx = new ClassPathXmlApplicationContext("xmemcache.xml");
		memcachedClient = (MemcachedClient) atx.getBean("memcachedClient");
	}

	public Iterable<String> getAttributeNames(String sessionID,
			StoreContext storeContext) {
		try {
			SessionDO session = memcachedClient.get(sessionID);
			if (session == null) {
				return emptyList();
			} else {
				return session.getSessionData().keySet();
			}
		} catch (TimeoutException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (MemcachedException e) {
			e.printStackTrace();
		}
		return null;
	}

	public Object loadAttribute(String attrName, String sessionID,
			StoreContext storeContext) {
		try {
			SessionDO session = memcachedClient.get(sessionID);
			if (session != null) {
				Map<String, Object> sessionData = session.getSessionData();
				return sessionData.get(attrName);
			}
		} catch (TimeoutException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (MemcachedException e) {
			e.printStackTrace();
		}
		return null;
	}

	public void invaldiate(String sessionID, StoreContext storeContext) {
		try {
			memcachedClient.delete(sessionID);
		} catch (TimeoutException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (MemcachedException e) {
			e.printStackTrace();
		}
	}

	public void commit(Map<String, Object> attrs, String sessionID,
			StoreContext storeContext) {
		Map<String, Object> sessionData = new HashMap<String, Object>();
		try {
			SessionDO session = memcachedClient.get(sessionID);
			if (session != null) {
				sessionData = session.getSessionData();
			}

			for (Map.Entry<String, Object> entry : attrs.entrySet()) {
				String attrName = entry.getKey();
				Object attrValue = entry.getValue();

				if (attrValue == null) {
					sessionData.remove(attrName);
				} else {
					sessionData.put(attrName, attrValue);
				}
			}
			SessionDO sessionDO = new SessionDO();
			sessionDO.setSessionData(sessionData);
			boolean r = memcachedClient.set(sessionID, 1200, sessionDO);
			System.out.println(r);

		} catch (TimeoutException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (MemcachedException e) {
			e.printStackTrace();
		}

	}

}

[/codesyntax]


velocity基本语法

1、声明:#set ($var=XXX)
左边可以是以下的内容
Variable reference
String literal
Property reference
Method reference
Number literal #set ($i=1)
ArrayList #set ($arr=[“yt1″,”t2”])
算术运算符

2、注释:
单行## XXX
多行#* xxx
xxxx
xxxxxxxxxxxx*#

References 引用的类型
3、变量 Variables
以 “$” 开头,第一个字符必须为字母。character followed by a VTL Identifier. (a .. z or A .. Z).
变量可以包含的字符有以下内容:
alphabetic (a .. z, A .. Z)
numeric (0 .. 9)
hyphen (“-“)
underscore (“_”)

4、Properties
$Identifier.Identifier
$user.name
hashtable user中的的name值.类似:user.get(“name”)

5、Methods
object user.getName() = $user.getName()

6、Formal Reference Notation
用{}把变量名跟字符串分开


#set ($user=”csy”}
${user}name
返回csyname

$username
$!username
$与$!的区别
当找不到username的时候,$username返回字符串”$username”,而$!username返回空字符串””

7、双引号 与 引号
#set ($var=”helo”)
test”$var” 返回testhello
test’$var’ 返回test’$var’
可以通过设置 stringliterals.interpolate=false改变默认处理方式

8、条件语句
#if( $foo )
<strong>Velocity!</strong>
#end
#if($foo)
#elseif()
#else
#end
当$foo为null或为Boolean对象的false值执行.

9、逻辑运算符:== && || !

10、循环语句#foreach($var in $arrays ) // 集合包含下面三种Vector, a Hashtable or an Array
#end
#foreach( $product in $allProducts )
<li>$product</li>
#end

#foreach( $key in $allProducts.keySet() )
<li>Key: $key -> Value: $allProducts.get($key)</li>
#end

#foreach( $customer in $customerList )
<tr><td>$velocityCount</td><td>$customer.Name</td></tr>
#end

11、velocityCount变量在配置文件中定义
# Default name of the loop counter
# variable reference.
directive.foreach.counter.name = velocityCount
# Default starting value of the loop
# counter variable reference.
directive.foreach.counter.initial.value = 1

12、包含文件
#include( “one.gif”,”two.txt”,”three.htm” )

13、Parse导入脚本
#parse(“me.vm” )

14、#stop 停止执行并返回

15、定义宏Velocimacros ,相当于函数 支持包含功能
#macro( d )
<tr><td></td></tr>
#end
调用
#d()

16、带参数的宏
#macro( tablerows $color $somelist )
#foreach( $something in $somelist )
<tr><td bgcolor=$color>$something</td></tr>
#end
#end

17、Range Operator
#foreach( $foo in [1..5] )


学习java之使用jdbc操作mysql

需要用到mysql for java驱动 mysql-connector-java-5.1.22.tar.gz

下载地址 http://dev.mysql.com/downloads/connector/j/

mysql-connector-java.jar 导入到项目

[codesyntax lang=”java”]

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class testdb {

	static Connection conn = null;

	public static void main(String[] args) {
		testdb testdb = new testdb();
		testdb.test();
	}

	public static void getConnectionByJDBC() {
		try {
			Class.forName("com.mysql.jdbc.Driver");
		} catch (ClassNotFoundException e) {
			System.out.println("装载驱动包出现异常,请查正!");
			e.printStackTrace();
		}
		try {
			conn = DriverManager.getConnection("jdbc:mysql://192.168.56.101/ye55", "root", "root");
		} catch (SQLException e) {
			System.out.println("链接数据库发生异常!");
			e.printStackTrace();
		}
	}

	public void test() {
		String sql = "select * from user";
		getConnectionByJDBC();
		try {
			Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery(sql);
			while (rs.next()) {
				String username = rs.getString("username");
				String password = rs.getString("password");
				System.out.println(username + " --" + password);
			}
		} catch (SQLException e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				if (conn != null)
				conn.close();
			} catch (SQLException e) {
				System.out.println(e.getMessage());
				e.printStackTrace();
			}
		}
	}
}

[/codesyntax]