我使用纯JSP
和JavaBeans
设计并实现了一个基于传统MVC Model 1架构的简单Webstore(是的,我仍然在我的宠物项目中使用该传统技术;))。
我使用DAO
设计模式为webstore实现我的持久层。但我不确定我是否在DAO层中正确实现了类。我特别关注QueryExecutor.java
和DataPopulator.java
类(如下所述)。这两个类中的所有方法都定义为static
,这使我想到这是多线程环境中的正确方法。因此,我对静态方法有以下问题。
Product-101
但由于非线程安全代码而显示Product-202
? new
运算符创建实例或者是否应在非线程安全代码周围放置synchronized
块?请指导。
MasterDao.java
public interface MasterDao {
Product getProduct(int productId) throws SQLException;
}
BaseDao.java
public abstract class BaseDao {
protected DataSource dataSource;
public BaseDao(DataSource dataSource) {
this.dataSource = dataSource;
}
}
MasterDaoImpl.java
public class MasterDaoImpl extends BaseDao implements MasterDao {
private static final Logger LOG = Logger.getLogger(MasterDaoImpl.class);
public MasterDaoImpl(DataSource dataSource) {
super(dataSource);
}
@Override
public Product getProduct(int productId) throws SQLException {
Product product = null;
String sql = "select * from products where product_id= " + productId;
//STATIC METHOD CALL HERE, COULD THIS POSE A SYNCHRONIZATION ISSUE ??????
List<Product> products = QueryExecutor.executeProductsQuery(dataSource.getConnection(), sql);
if (!GenericUtils.isListEmpty(products)) {
product = products.get(0);
}
return product;
}
}
QueryExecutor.java
public final class QueryExecutor {
private static final Logger LOG = Logger.getLogger(QueryExecutor.class);
//SO CANNOT NEW AN INSTANCE
private QueryExecutor() {
}
static List<Product> executeProductsQuery(Connection cn, String sql) {
Statement stmt = null;
ResultSet rs = null;
List<Product> al = new ArrayList<>();
LOG.debug(sql);
try {
stmt = cn.createStatement();
rs = stmt.executeQuery(sql);
while (rs != null && rs.next()) {
//STATIC METHOD CALL HERE, COULD THIS POSE A SYNCHRONIZATION ISSUE ???????
Product p = DataPopulator.populateProduct(rs);
al.add(p);
}
LOG.debug("al.size() = " + al.size());
return al;
} catch (Exception ex) {
LOG.error("Exception while executing products query....", ex);
return null;
} finally {
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (cn != null) {
cn.close();
}
} catch (Exception ex) {
LOG.error("Exception while closing DB resources rs, stmt or cn.......", ex);
}
}
}
}
DataPopulator.java
public class DataPopulator {
private static final Logger LOG = Logger.getLogger(DataPopulator.class);
//SO CANNOT NEW AN INSTANCE
private DataPopulator() {
}
//STATIC METHOD DEFINED HERE, COULD THIS POSE A SYNCHRONIZATION ISSUE FOR THE CALLING METHODS ???????
public static Product populateProduct(ResultSet rs) throws SQLException {
String productId = GenericUtils.nullToEmptyString(rs.getString("PRODUCT_ID"));
String name = GenericUtils.nullToEmptyString(rs.getString("NAME"));
String image = GenericUtils.nullToEmptyString(rs.getString("IMAGE"));
String listPrice = GenericUtils.nullToEmptyString(rs.getString("LIST_PRICE"));
Product product = new Product(new Integer(productId), name, image, new BigDecimal(listPrice));
LOG.debug("product = " + product);
return product;
}
}
答案 0 :(得分:3)
您的代码是线程安全的。
原因和线程安全的关键是你的(静态)方法不维护状态。即你的方法只使用局部变量(而不是字段)。
方法是否静态无关紧要。
答案 1 :(得分:1)
假设存在同步问题;这些方法是否应该是非静态的,并且类可以立即生成,以便我们可以使用new运算符
创建实例
这不会有帮助。多个线程可以使用单个对象随意使用静态方法,并且您将遇到同步问题。
OR是否应在非线程安全代码周围放置同步块?
是的,这是安全的方式。同步块内的任何代码都保证在任何给定时间内最多有一个线程。
查看代码,我看不到许多可能在线程之间共享的数据结构。假设你有像
这样的东西public final class QueryExecutor {
int numQueries = 0;
public void doQuery() {
numQueries++;
}
}
然后你遇到了麻烦,因为4个线程可能同时执行doQuery
,所以你有4个线程修改numQueries
的值 - 这是个大问题。
但是对于您的代码,唯一的共享类字段是日志记录类,它将内置自己的线程安全同步 - 因此您提供的代码看起来很好。
答案 2 :(得分:1)
代码中没有状态(例如,没有可变成员变量或字段),因此Java同步无关紧要。
另据我所知,没有数据库创建,更新或删除,因此也没有问题。
确实有一些可疑的做法(例如,数据库连接对象的非管理,一些变量的广泛范围,更不用说静态),但没有任何错误。
至于如何测试或确定线程安全性,您可能会比使用两个不同的浏览器并行手动操作您的站点更糟糕。或者创建一个shell脚本,使用curl
执行自动HTTP请求。或者创建一个WebDriver
测试,在各种真实浏览器中运行多个会话,并检查所有场景下预期的产品是否可见......