2009/08/24

weblcc发布了

上周五Tom把virtual server帮我搞定. 可是把该装的软件都在新的Windows server 2008上装好后, 却在Netbeans中运行时发生Java虚拟机的错误. 周末想了两天, 发现还是MCR的问题: 在数据库操作之后实例化matlab接口会出现问题. 看来还是要在server 2008上装matlab. 那个stand along的MCR还是不太完善. 

今天上午装上了matlab. 虽然可以在一个普通的Java类中实例化matlab接口,可是还是运行不了web程序. 比较一下, 看到web程序中servlet实例化matlab接口的方法是:

weblcc.WeblccMat weblccMat = null;

...

synchronized (application) {
weblccMat = (weblcc.WeblccMat) pageContext.getAttribute("weblccMat", PageContext.APPLICATION_SCOPE);
if (weblccMat == null) {
weblccMat = new weblcc.WeblccMat();
pageContext.setAttribute("weblccMat", weblccMat, PageContext.APPLICATION_SCOPE);
}
}

于是尝试把程序改为

if(session.getAttribute("weblccMat")==null){

  weblccMat =  new weblcc.WeblccMat();

 session.setAttribute("weblccMat",weblccMat);

}else{

  weblccMat = (weblcc.WeblccMat)session.getAttribute("weblccMat");

}

运行,失败。不是代码的错误,而是glassfish在经历了Java虚拟机的错误之后就启动不了了。当初之所以用glassfish,是因为netbeans的doc是用glassfish做实例。可是后来看网上很多资料都是tomcat相关的。而且,我也发现tomcat的启动速度要比glassfish快很多, 这对于调试当然很重要了。于是我决定用tomcat做我的服务器程序。

在netbeans中设置tomcat为运行时服务器后,weblcc终于可以顺利运行。

之后我把weblcc的web程序在tomcat中deploy,运行,前面所有页面都顺利,就是最后的results picture出不来。有了上次的经验,我很快找到了问题的原因:还是路径问题。 matlab程序将图片按绝对路径存到了我的netbeans的project下build/web/resultpics/文件夹下,可是tomcat会按相对路径在tomcat目录下的webapps/LCC/resultpics/文件夹下找图片。 这样当然不会显示图片。

于是我把原servlet程序中的

private static final String figureDir = System.getProperty("user.dir") + "/domains/LCC/build/web/resultpics/";

改为

private static final String figureDir = "D:/program/Apache Tomcat 6.0.18/webapps/LCC/resultpics/". 注意最后那个backslash一定要加,不然图片全存到/LCC下了!

运行bin/startup.bat,成功!


weblcc 顺利发布。 


2009/08/15

[转]mysql自动断开连接的问题及解决方法

工作的两年多时间里,接触过几种数据库,在实际项目开发中使用过Oracle 10g和MySql,其中遇到过一件比较有意思的问题:以前公司开发的一个项目使用的MySql数据库,用的是连接池的方式连接数据库,然后发现一个问题,如果一段时间不登陆该系统 ,下一次登陆的时候就会报“用户名或密码错误”,接着再次登陆就不会有问题了,而第一次登陆的用户名和密码肯定是正确的,之前的技术人员也一直没有找到出现这个问题的原因。我到这个公司之后,经理让我看看代码能不能解决这个问题,我当时怀疑是不是登陆跳转页面中有什么问题呢?可是看了几天也没有什么问题啊,最后我想到是不是数据库的原因呢?可是我对数据库也不是很熟悉,然后就问了一个赛迪的网友,经过他的提示和在网上查的资料,知道了原因和解决方法,原来是当MySql数据库连接空闲一定时间后,服务器就会断开等待超时的连接,默认时间是8小时,当我修改了连接池的连接方式,使用了DBCP连接方式,设置几个参数,这样,每次访问数据库的时候都会先检查连接是否有效,如果无效则建立有效连接,这样就不会出现我之前说的那个问题了,啰啰嗦嗦的说了一大堆,其实是个很简单的问题,只是当时我对数据库不了解才一直都找不到原因。 

  下面是我当时参考的一篇文章和自己总结的一些需要注意的问题: 
数据库连接池的好处是不言而喻的,现在大部分的application server都提供自己的数据库连接池方案,此时,只要按照application server的文档说明,正确配置,即可在应用中享受到数据库连接池的好处。 
但是,有些时候,我们的应用是个独立的java application,并不是普通的WEB/J2EE应用,而且是单独运行的,不要什么application server的配合,这种情况下,我们就需要建立自己的数据库连接池方案了。这里,介绍如何利用apache的dbcp来建立为民自己的数据库连接池。 

1、首先,下载必须的jar包 
dbcp包,目前版本是1.2.1:http://jakarta.apache.org/commons/dbcp/ 
pool包,目前版本是1.3:http://jakarta.apache.org/commons/pool/, 
如果下载的pool包是1.2的版本,还要下载common-collections包:http://jakarta.apache.org/commons/collections/ 
在建立我们自己的数据库连接池时,可以使用xml文件来传入需要的参数,这里只使用hard code的方式来简单介绍,所有需要我们自己写的代码很少,只要建立一个文件如下: 
import org.apache.commons.dbcp.BasicDataSource; 
import org.apache.commons.dbcp.BasicDataSourceFactory; 

import java.sql.SQLException; 
import java.sql.Connection; 
import java.util.Properties; 

public class ConnectionSource { 
private static BasicDataSource dataSource = null; 

public ConnectionSource() { 


public static void init() { 

if (dataSource != null) { 
try { 
dataSource.close(); 
} catch (Exception e) { 
// 

dataSource = null; 


try { 
Properties p = new Properties(); 
p.setProperty("driverClassName", "oracle.jdbc.driver.OracleDriver"); 
p.setProperty("url", "jdbc:oracle:thin:@192.168.0.1:1521:testDB"); 
p.setProperty("password", "scott"); 
p.setProperty("username", "tiger"); 
p.setProperty("maxActive", "30"); 
p.setProperty("maxIdle", "10"); 
p.setProperty("maxWait", "1000"); 
p.setProperty("removeAbandoned", "false"); 
p.setProperty("removeAbandonedTimeout", "120"); 
p.setProperty("testOnBorrow", "true"); 
p.setProperty("logAbandoned", "true"); 

dataSource = (BasicDataSource) BasicDataSourceFactory.createDataSource(p); 

} catch (Exception e) { 
// 




public static synchronized Connection getConnection() throws SQLException { 
if (dataSource == null) { 
init(); 

Connection conn = null; 
if (dataSource != null) { 
conn = dataSource.getConnection(); 

return conn; 



  接下来,在我们的应用中,只要简单地使用ConnectionSource.getConnection()就可以取得连接池中的数据库连接,享受数据库连接带给我们的好处了。当我们使用完取得的数据库连接后,只要简单地使用connection.close()就可把此连接返回到连接池中,至于为什么不是直接关闭此连接,而是返回给连接池,这是因为dbcp使用委派模型来实现Connection接口了。 

  在使用Properties来创建BasicDataSource时,有很多参数可以设置,比较重要的还有: 

  testOnBorrow、testOnReturn、testWhileIdle,他们的意思是当是取得连接、返回连接或连接空闲时是否进行有效性验证(即是否还和数据库连通的),默认都为false。所以当数据库连接因为某种原因断掉后,再从连接池中取得的连接,实际上可能是无效的连接了,所以,为了确保取得的连接是有效的,可以把把这些属性设为true。当进行校验时,需要另一个参数:validationQuery,对oracle来说,可以是:SELECT COUNT(*) FROM DUAL,实际上就是个简单的SQL语句,验证时,就是把这个SQL语句在数据库上跑一下而已,如果连接正常的,当然就有结果返回了。 

  还有2个参数:timeBetweenEvictionRunsMillis 和 minEvictableIdleTimeMillis,他们两个配合,可以持续更新连接池中的连接对象,当timeBetweenEvictionRunsMillis 大于0时,每过timeBetweenEvictionRunsMillis 时间,就会启动一个线程,校验连接池中闲置时间超过minEvictableIdleTimeMillis的连接对象。 
还有其他的一些参数,可以参考源代码。 
部分参数简要说明: 
removeAbandoned :是否自动回收超时连接 
removeAbandonedTimeout:超时时间(以秒数为单位) 
rmoveAbandoned=true那么在getNumActive()快要到getMaxActive()的时候,系统会进行无效的Connection的回收,回收的Connection为removeAbandonedTimeout(默认300秒)中设置的秒数后没有使用的Connection 
logAbandoned:logAbandoned=true的话,将会在回收事件后,在log中打印出回收Connection的错误信息,包括在哪个地方用了Connection却忘记关闭了,在调试的时候很有用。 
maxWait:超时等待时间以毫秒为单位 
maxIdle:最大空闲连接 
minIdle:最小空闲连接 
maxActive:最大连接数 
testOnBorrow、testOnReturn、testWhileIdle、validationQuery:上面有介绍 
另外很重要的一点是每次连接使用完了不要忘了调用connection.close()使连接返回到连接池


(原文出处: http://hi.baidu.com/freeafon/blog/item/3775ff8a70843d779e2fb4b5.html)

2009/08/12

path problem

I have been confused by the Matlab-generated figures' problem for more than 3 weeks! It is the path that cause this problem.

The pictures should be saved under the directory 'build' in my Netbeans web project, hence they could be referred and displayed in jsp.

MySQL connetion problem

The problem pops up when I was trying to connect to the MySQL database:

'The last packet successfully received from the server was41645 seconds ago.The last packet sent successfully to the server was 41645 seconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was41645 seconds ago.The last packet sent successfully to the server was 41645 seconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem.'

I checked online (http://bbs.cnw.com.cn/thread-192473-1-1.html) and it's said that it's better to write the URL of the database in the following way:

jdbc:mysql://localhost:3306/test?autoReconnect=true&failOverReadOnly=false 

I've tried this trick but it's not working. Alternatively I checked the validity of the database connection, via 'conn.isValidate()' (this conn is the class 'JDCConnection' . Plz see my previous blog 'Using connection pool in java bean'). If it's not a validate connection any longer, I get a new connection from DriverManager again.