java中,类的static变量作为类变量,只需要被一次初始化,就可使用,但是,我在程序中遇到一个问题:
在web.xml中配置listener,服务器启动时,ServletContextListen初始化数据源(DataSource),第一次初始化成功,但是在Test类中,调用ConnectionManager.getConnection()时,DataSource却为null,意味着ServletContextListen初始化数据源失败了,大家帮忙解答下,到底什么原因造成的,谢谢!!!
以下是代码:
[code="java"]
package c3p0.connection;
import java.beans.PropertyVetoException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class ConnectionManager {
private static DataSource data_source=null;;
private static Properties props=null;
private static String porps_name=null;
/**
* 创建数据库连接池
* @return
*/
private static DataSource createDataSource(){
load();
data_source=initDB();
return data_source;
}
/**
* 加载配置文件
*/
private static void load(){
try {
props = new Properties();
InputStream in=Thread.currentThread().getContextClassLoader().getResourceAsStream(porps_name);
props.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 初始化数据库
*/
private static DataSource initDB(){
System.out.println("开始初始化数据源...");
ComboPooledDataSource pool_ds=new ComboPooledDataSource();
try {
pool_ds.setDriverClass(getProperty("c3p0.connection.driverClass"));
} catch (PropertyVetoException e) {
e.printStackTrace();
throw new RuntimeException("数据库驱动加载失败");
}
pool_ds.setJdbcUrl(getProperty("c3p0.connection.url"));
pool_ds.setUser(getProperty("c3p0.connection.user"));
pool_ds.setPassword(getProperty("c3p0.connection.password"));
pool_ds.setInitialPoolSize(Integer.parseInt(getProperty("c3p0.connection.initialPoolSize")));
pool_ds.setMaxPoolSize(Integer.parseInt(getProperty("c3p0.connection.maxPoolSize")));
pool_ds.setMinPoolSize(Integer.parseInt(getProperty("c3p0.connection.minPoolSize")));
pool_ds.setMaxIdleTime(Integer.parseInt(getProperty("c3p0.connection.maxIdleTime")));
pool_ds.setAcquireIncrement(Integer.parseInt(getProperty("c3p0.connection.acquireIncrement")));
pool_ds.setAcquireRetryAttempts(Integer.parseInt(getProperty("c3p0.connection.acquireRetryAttempts")));
pool_ds.setAcquireRetryDelay(Integer.parseInt(getProperty("c3p0.connection.acquireRetryDelay")));
pool_ds.setTestConnectionOnCheckout(Boolean.parseBoolean(getProperty("c3p0.connection.testConnectionOnCheckout")));
pool_ds.setTestConnectionOnCheckin(Boolean.parseBoolean(getProperty("c3p0.connection.testConnectionOnCheckin")));
pool_ds.setIdleConnectionTestPeriod(Integer.parseInt(getProperty("c3p0.connection.idleConnectionTestPeriod")));
pool_ds.setCheckoutTimeout(Integer.parseInt(getProperty("c3p0.connection.checkoutTimeout")));
pool_ds.setAutomaticTestTable(getProperty("c3p0.connection.automaticTestTable"));
System.out.println("数据源初始化完毕...");
return pool_ds;
}
/**
* 获取c3p0连接池文件配置信息
* @param key
* @return
*/
private static String getProperty(String key){
if(key==null||"".equals(key)){
throw new NullPointerException("key不能为空!!!请检查key的赋值!!!");
}
return props.getProperty(key);
}
public static Connection getConnection() throws SQLException{
data_source=(data_source==null) ? createDataSource() : data_source;
return data_source.getConnection();
}
public static void start(String porps_name) throws SQLException{
ConnectionManager.porps_name=porps_name;
Connection conn=getConnection();
conn.close();
}
public static void stop(){
data_source=null;
}
public static void release(Connection conn,PreparedStatement pstmt,ResultSet res){
try {
if(conn!=null){
conn.close();
}
if(pstmt!=null){
pstmt.close();
}
if(res!=null){
res.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
[/code]
[code="java"]
package mystruts.listener;
import java.sql.SQLException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import c3p0.connection.ConnectionManager;
/**
@author tianly
*
/
public class ServletContextListen implements ServletContextListener {
/*
/**
web服务器启动时执行
*/
@Override
public void contextInitialized(ServletContextEvent event) {
/**
}
[/code]
[code="java"]
package test.c3p0;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import c3p0.connection.ConnectionManager;
import c3p0.util.DateUtil;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
String currdate=DateUtil.getDateTime();
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet res=null;
try {
String sql="insert into userinfo(username,password,sex,regdate) values(?,?,?,?)";
String sql4ID="select LAST_INSERT_ID()";
conn=ConnectionManager.getConnection();
conn.setAutoCommit(false);
pstmt=conn.prepareStatement(sql);
pstmt.setString(1, "tly");
pstmt.setString(2, "tly");
pstmt.setInt(3, 0);
pstmt.setString(4, currdate); //mysql中无需进行日期格式转换
pstmt.executeUpdate();
pstmt=conn.prepareStatement(sql4ID);
res=pstmt.executeQuery();
if(res.next()){
int ID=res.getInt(1);
System.out.println("ID:"+ID);
}
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
ConnectionManager.release(conn, pstmt, res);
}
}
}
[/code]
[code="xml"]
<?xml version="1.0" encoding="UTF-8"?>
mysystem
index.html
index.htm
index.jsp
default.html
default.htm
default.jsp
<!-- 登录Servlet配置
LoginServlet
login.LoginServlet
LoginServlet
/login
-->
ActionDispatcher
mystruts.actionfilter.ActionDispatcher
ActionDispatcher
*.action
<!-- 数据库信息配置 -->
DataBaseConfig
c3p0/c3p0.properties
mystruts.listener.ServletContextListen
[/code]
在Test类中,调用ConnectionManager.getConnection()时,DataSource却为null,但我在debug时,跟踪查看,发现DataSource是被初始化了,不知什么原因造成初始化失败,请大家帮忙查看下,谢谢
没必要放到ServletContextListener。
直接放在ConnectionManager中的static块中,默认加载classpath下的配置文件。
如 static {
load();
data_source=initDB();
return data_source;
}
读取classpath下的资源可以通过
Thread.currentThread().getContextClassLoader().getResourceAsStream(name)
public static void stop(){
data_source=null; //容器销毁了 自动垃圾回收了,不需要
}
报的什么异常,能否全部贴出来
那是应为他们没有运行在同一个环境中,,服务器启动是在tomcat容器中的,而你自己写的test类 是在外面JDK里面跑的 和 tomcat没有关系,当然是空了
其它的 我就不多说了 ,开源中国 红薯大哥也是用的 c3p0,同时 他把它的数据库 工具类 已经贡献出来了
[code="java"]package my.db;
import java.sql.*;
import java.util.*;
import java.lang.reflect.*;
import javax.sql.DataSource;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
@date 2010-2-2 下午10:18:50
*/
public class DBManager {
private final static Log log = LogFactory.getLog(DBManager.class);
private final static ThreadLocal conns = new ThreadLocal();
private static DataSource dataSource;
private static boolean show_sql = false;
static {
initDataSource(null);
}
/**
@param show_sql
*/
private final static void initDataSource(Properties dbProperties) {
try {
if(dbProperties == null){
dbProperties = new Properties();
dbProperties.load(DBManager.class.getResourceAsStream("db.properties"));
}
Properties cp_props = new Properties();
for(Object key : dbProperties.keySet()) {
String skey = (String)key;
if(skey.startsWith("jdbc.")){
String name = skey.substring(5);
cp_props.put(name, dbProperties.getProperty(skey));
if("show_sql".equalsIgnoreCase(name)){
show_sql = "true".equalsIgnoreCase(dbProperties.getProperty(skey));
}
}
}
dataSource = (DataSource)Class.forName(cp_props.getProperty("datasource")).newInstance();
if(dataSource.getClass().getName().indexOf("c3p0")>0){
//Disable JMX in C3P0
System.setProperty("com.mchange.v2.c3p0.management.ManagementCoordinator",
"com.mchange.v2.c3p0.management.NullManagementCoordinator");
}
log.info("Using DataSource : " + dataSource.getClass().getName());
BeanUtils.populate(dataSource, cp_props);
Connection conn = getConnection();
DatabaseMetaData mdm = conn.getMetaData();
log.info("Connected to " + mdm.getDatabaseProductName() +
" " + mdm.getDatabaseProductVersion());
closeConnection();
} catch (Exception e) {
throw new DBException(e);
}
}
/**
public final static Connection getConnection() throws SQLException {
Connection conn = conns.get();
if(conn ==null || conn.isClosed()){
conn = dataSource.getConnection();
conns.set(conn);
}
return (show_sql && !Proxy.isProxyClass(conn.getClass()))?
new _DebugConnection(conn).getConnection():conn;
}
/**
/**
@author Winter Lau
*/
static class _DebugConnection implements InvocationHandler {
private final static Log log = LogFactory.getLog(_DebugConnection.class);
private Connection conn = null;
public _DebugConnection(Connection conn) {
this.conn = conn;
}
/**
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
try {
String method = m.getName();
if("prepareStatement".equals(method) || "createStatement".equals(method))
log.info("[SQL] >>> " + args[0]);
return m.invoke(conn, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
}
[/code]
[url]http://www.oschina.net/code/snippet_12_8[/url]
要看你的tomcat启动了没的,如果没有启动,你的test又没连接数据库,如何会拿到值啊。
你的初始化是tomcat启动后才会去初始化的。
前面的几个哥们也都说了,如果配置在xml中那么你肯定得去启动这个xml才能生效。
如果你想测试你的代码用测试类中mian方法来测试,你首先要去执行xml文件。
楼上说得对。
你建一个Servlet,把那段测试代码放到Servlet里去,再用浏览器调Servlet.
兄弟你太幽默了。。。监听器 是运行在web容器里的。是一个jvm实例。
main方法是另外一个jvm实例。
本质是两个main方法。。能互相调用彼此的运行时变量么。。。