DAO方法和同步

时间:2010-08-17 20:19:34

标签: java jdbc synchronization dao

以下是我目前在抽象DAO类中使用的方法。如果有并发呼叫,它们是否安全,或者应该同步使用?我知道如果存在对方法范围之外的属性的引用,则应该使用同步,但是我不清楚如何使用外部资源来处理事情。

public Connection getConnection() {
    // Call to singleton handling JDBC stuff
    return Database.getInstance().getCon();
}

public boolean isConnectionAvailable(){     
    if( getConnection() != null ){
        return true;
    }

    return false;
}

public PreparedStatement getPreparedStatement( String sqlStatement ){
    Connection connection = getConnection();
    PreparedStatement pS = null;

    if( connection != null ){
        try {
            pS = connection.prepareStatement( sqlStatement );
        } catch (SQLException e) {
            return null;
        }
    }

    return pS;
}

编辑:我可能会重新编写这个问题,以包含有关编写DAO的信息,因为它在这里很重要。

7 个答案:

答案 0 :(得分:13)

我完全不同意这种实施方式。

首先,应通过拥有工作单位和交易的服务为DAO提供连接信息。

其次,我没有看到界面。

第三,我没有看到模型或域对象。

第四,准备好的陈述应该只是内部实施的一部分。如果他们从你的DAO中泄漏出来,你做错了。

第五,将准备好的陈述从对象中传出,使得关闭它并清理得更不清楚。你的DAO很快就会死于资源泄漏。

这是一个通用DAO的接口。您会注意到它是所有CRUD操作,没有提及java.sql包中的连接或任何接口:

package persistence;

import java.io.Serializable;
import java.util.List;

public interface GenericDao<T, K extends Serializable>
{
    T find(K id);
    List<T> find();
    List<T> find(T example);
    List<T> find(String queryName, String [] paramNames, Object [] bindValues);

    K save(T instance);
    void update(T instance);
    void delete(T instance);
}

你可以走很长的路。这是一个更好的抽象。 T是您的业务对象类型,K是主键。

答案 1 :(得分:3)

如果getCon()每次调用都会返回一个新的Connection,或者返回ThreadLocal个连接,那么您就是安全的,无需使用synchronized < / p>

如果您向同一个人返回相同的连接,您可能仍会在同步方面保存,因为连接中没有状态会被更改(在您当前的代码中)。但你应该避免这种做法。改为考虑连接池。

关于一般设计原则的一些注释。 DAO形成一个单独的层。每一层都存在是有原因的,而不是为了拥有很酷的名字。存在DAO层是为了抽象,或者换句话说 - 从使用DAO对象的服务隐藏数据库访问。为了更清楚地想象它 - DAO必须以如下方式编写:如果明天您决定从RDBMD存储(通过JDBC)切换到XML存储,您应该能够通过仅更改来实现这一点 DAO对象,没有别的。

答案 2 :(得分:3)

不保证JDBC Connection类是线程安全的。如果您的Database.getInstance()。getCon()方法总是返回相同的连接,那么您将遇到问题。但是,如果它正在使用一个池,每次调用getInstance()。getCon()都会返回一个不同的连接,你就可以了。

也就是说,如果每次调用getCon()返回一个不同的连接,那么如果你想让两个Prepared Statement调用使用相同的连接(和相同的事务),则getPreparedStatement()将不起作用。

我喜欢Spring的JDBCTemplate类作为我的DAO类的基础。

答案 3 :(得分:2)

您不应在每个线程中使用相同的连接。 JDBC驱动程序不应该是线程安全的。如果您需要线程安全代码,则应为每个线程创建一个连接。

其余代码似乎很安全。

答案 4 :(得分:2)

看看Spring是如何做到的,他们已经找到了所有这些东西,没有必要重新发明它。查看与Spring完整版本捆绑在一起的petclinic示例代码,或者(对于非Spring方法)阅读Bauer / King Hibernate书籍的DAO章节。

当然,DAO不应该负责获取数据库连接,因为您需要在同一事务中对多个DAO调用进行分组。 Spring的方式就是有一个服务层,它将事务方法包装在一个拦截器中,该拦截器从数据源获取连接并将其放在一个线程局部变量中,DAO可以在其中找到它。

吃SQLException并返回null是不好的。正如duffymo所指出的那样,让PreparedStatement无法保证它会被关闭是非常糟糕的。此外,没有人应该再使用原始JDBC,Ibatis或spring-jdbc是更好的选择。

答案 5 :(得分:0)

对我来说很好看。这些函数是线程安全的。

答案 6 :(得分:0)

连接只是一个接口。它不是线程安全的。 JDBC驱动程序也不是线程安全的。