以下是我目前在抽象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的信息,因为它在这里很重要。
答案 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驱动程序也不是线程安全的。