请教,Struts2 中对数据库连接使用单例模式

我的同事设计了在Struts2中对数据库连接使用单例模式,我问他如果连接只有一个实例,多用户下怎么办;他说Struts2可以确保多线程,我不太懂,这样设计行吗?

程序如下:
public class DatabaseInteraction {

private static Statement m_statement;
private static Connection m_connection;
private boolean m_stateConnection = false;
private boolean m_stateStatement = false;
private ProjectProperties m_databaseProperties;

private static final DatabaseInteraction INSTANCE = new DatabaseInteraction();

private DatabaseInteraction(){
    try{
        this.m_databaseProperties = ProjectProperties.getInstance();
        String sDriver = m_databaseProperties.getM_driver();
        Class.forName(sDriver);

        String url = "";
            url = "jdbc:mysql://" + m_databaseProperties.getM_hostname() + ":" + this.m_databaseProperties.getM_port() + "/" + m_databaseProperties.getM_sid() + "?"
                    + "user=" + m_databaseProperties.getM_login() + "&password=" + m_databaseProperties.getM_password() + "&autoReconnect=true&failOverReadOnly=false";
            m_connection = DriverManager.getConnection(url);

        if(m_connection != null)
            m_stateConnection = true;

        m_statement = m_connection.createStatement();

        if(m_statement != null)
            m_stateStatement = true;

    } catch (Exception e) {
        Log4jInteraction.getInstance().getLogger().error("DatabaseInteraction.DatabaseInteraction(), database wrong!\n" + e.getMessage() + "\n" + e.getStackTrace());
        //TODO:
        //INSTANCE = null;
    }
}


/*
 returnning the only object for accessing the database
 */
public static DatabaseInteraction getInstance() {
     return INSTANCE;
 }


public Object execute(String query){
    boolean bResult = false;

    try{
        bResult = m_statement.execute(query);

        if (bResult){
            return m_statement.getResultSet();
        }else{
            return new Integer(m_statement.getUpdateCount());
        }
    }
    catch (CommunicationsException ce){
        return "";
    }
    catch (SQLException e){
        Log4jInteraction.getInstance().getLogger().error("DatabaseInteraction.execute, wrong!\n" + e.getMessage() + "\n" + e.getStackTrace() + "\n");
        return e.getErrorCode() + "";
    }
}


/*
 close the database connection object
 */
public boolean close(){
    try{
        m_statement.close();
        m_connection.close();
        return true;
    }
    catch (Exception e){
        Log4jInteraction.getInstance().getLogger().error("DatabaseInteraction.close, wrong!\n" + e.getMessage() + "\n" + e.getStackTrace());
        return false;
    }
} 



// Getter and Setter
public boolean isM_stateConnection() {
    return m_stateConnection;
}

public boolean isM_stateStatement() {
    return m_stateStatement;
}

}

我来说一点吧,这里的单例模式的代码是没有问题的。只是要看你的系统是不是适合这种用法;如果你的程序里边没有涉及到事物(数据库事物)神马的,这样写完全可以,也没有什么问题,但是如果使用了事物,那就不行了,因为事物没有办法控制了。

从你的说法上来看(你说:Struts2 + 单例模式数据库连接),这样来说你们的系统应该没有涉及到事物,因为没有使用spring,(这年头,谁使用事物不用spring呀),所以我敢说,这样的用法在你们的系统里是没有问题的,而且在一定程度上还会提高程序的效率。还要说一点:这里没有判断链接是否可用,如果这个链接空闲时间太长,数据库服务器可能(只是可能,因为这个在数据库上是可以设置的)会关闭这个链接,如果链接被关闭的话,那就不可用了。

至于事物这东西,如果想多了解些,就自己再google一下吧。

这个代码在多线程下肯定有问题的~~

单例是来干什么的要先弄清楚啊
主要是减少类的生成数量,固定的,不会造成同步数据部安全的,才用单例
这个明显不能用,干嘛非要给它往什么设计上面套呢
都是什么设计模式害死人,学好基础再来学模式,它只不过是常用代码的提升罢了
学学把代码分层吧,Action太复杂了些
虽然对于struts来说,每个请求都会去帮你默认生成一个Action,这个地方的数据是可以保证线程安全的,但是你每次发送你个请求这里就创建数据连接,这个别人用起来还不慢死了

[code="java"]项目采用了Struts2+Spring的装配方式,Spring管理Struts2的Action自动设置为单例。这样Action的生命周期为服务器生命周期,也就是说不关闭应用服务器,Action一直存在,Action中的属性也一直存在。

这种现象的好处在于,分页对象所需要的数据对象存在于Action中是不被销毁的,直到页面重新对数据对象输入查询条件。

这样做的缺点在于,一,两个浏览器同时操作一个页面,会在查询等条件的保存上产生冲突,致使A浏览器的查询条件影响到B浏览器的查询结果;二,没有良好设计的系统中,重用Action和多次利用Action的时候无法有效甄别数据的有效性。

举个例子,有一个查询分类的Action,实现对分类的查询和定位功能,在人员Action中可能也会用到分类Action,如果单独使用两个Action都是好用的,但是如果先调用了分类的Action,再调用人员Action,因为人员Action中存在基于分类选择后的条件查询,分类Action的查询结果就会直接影响到人员Action的结果。这种结果在逻辑上可以解释的通,但是在客户体验上是很难说得过去的。

因此思考是否可以通过一些办法来解决此类问题。

办法一:设置Action bean的生命周期为Session,即每个浏览器的打开影响着一套Action的生命周期,解决不同用户互相影响的问题;

(通常和spring整合使用的时候,在struts.xml文件要配置一个元素 或者在struts.property文件中配置 struts.objectFactory = spring 。。。可以在spring的配置文件中的bean元素里用一个scope属性来配置action是用什么生命周期,singleton,prototype,request,session等等)

办法二:通过设置过滤器或者拦截器,或者设置类中的单独属性,判断查询条件是否由理想对象传来,如果不是则销毁值对象,如果是则继承值对象的查询条件。

一些关于拦截器的资料:[url]http://blog.csdn.net/feng_sundy/archive/2007/10/11/1820668.aspx[/url]
[/code]

[url]http://blog.csdn.net/feng_sundy/archive/2007/10/11/1820668.aspx[/url]

单例模式就是为了节省创建对像,保证一个类在运行中只产生一个对像

简单讲,如果客户端同时两个请求过来(并发),这两个请求都需要操作数据库
因此调用 这个单例
先拿到这个单例的线程A在执行
public Object execute(String query){
到这边时
bResult = m_statement.execute(query);

另一个线程B也执行到这行时
bResult = m_statement.execute(query); 怎么办
最后代码肯定混乱了(多线程执行速度不能保证)

还有关闭链接那个操作
整个对像的生存周期就是系统的启动到停止,而且只有一个对像
当其中一个线程关闭了这个链接,那下个线程还刚到执行那个动作时就肯定报链接关闭的问题

像你这个获取数据库连接的代码要吗自己写个连接池的功能,要吗就是使用成熟的连接池组件,自己写太费时了,还不能保证代码的稳定性

这个不是单例模式,单例至少需要synchronized这个关键字

但是数据库连接不必非要单例啊,通常采用Treadlocal来做

ps:现在开源的连接池做的都很成熟了,干嘛非得用这个???

哎,这个写的明显就是错的不沾边啊。。。
多个用户拿到的都是一个action不错大了才怪了
楼主action struts默认都是prototype的,你这样给别人改了个singleton的
一般代码分为
action 这个是来控制请求转发的
service 处理业务逻辑
manger 处理业务数据和dao的交互
dao 处理数据库数据

为了省事可以合并action和services,manger和dao
前者必须是prototype的,后者为singleton的

最好把spring加进来,使用ioc,来注入需要的东西
数据连接池用proxool吧

首先,要用连接池。
其次,单例就代表这个对象只在内存中存一份,只有一个对象,你前台action显然不止一个吧,当有多个action访问这个数据库连接对象的时候,读对象没问题,但是对对象操作就有问题了,如一个action线程在执行close方法关闭了连接,而此时还有好几个线程正在用连接执行execute呢,就有问题了。
这个单例最大的问题就是connection是只有一个,在这个对象初始化时候实例化的。如果每次都在execute时候初始化,执行完后关闭是没有问题的。但是效率就会慢到冰点。。。。。
你可以把整个数据源操作类变成单例,但是里面要组合进来一个连接池,每次执行的时候从连接池里获取连接,完了再释放连接。写单例要注意复用执行代码,避免竞争资源就行了。

你确认一个答案啊。。。