我手头一个项目的Dao层的代码,Dao维持自己一个单例,Dao的操作方法是非线程安全的,每个方法内创建并销毁DB Connection,如
  
public class UserDao extends AbstractDAO {
  private static Logger log = LoggerFactory.getLogger(ActivityDAO.class);
  public static synchronized UserDao getInstance() {
    if (instance == null) {
      log.debug("getInstance()");
      instance = new UserDao();
    }
  return instance;
  }
 
  public Connection getConnection() throws SQLException {
    Connection con = null;
if (ds == null) {
  Context ctx = new InitialContext();
  Context envContext = (Context) ctx.lookup("java:/comp/env");
  ds = (DataSource) envContext.lookup(getDataSourceName());
  ctx.close();
}
      con = ds.getConnection();
  }  public void create(UserBean user) throws SQLException {
    Connection con = null;
    PreparedStatement stmt = null;
    try {
      con = getConnection();
      ...
      ...
    } finally {
      closeStatement(stmt);
      closeConnection(con);
    }
  }
}     我的问题是Dao是单例,所有Dao的方法没有synchronized不是线程安全的,当多个线程同时调用create方法时会不会出问题,比如con会不会冲突,会不会一个线程把con释放后另一个线程空指针了。
      如果这么写没有问题的话,当Dao的上层要控制事务,con由Dao的上层当做参数传进来,上层控制con的创建和关闭,会有线程安全的问题么?

解决方案 »

  1.   

    你这个类没有实例变量,没有共享数据,哪来的线程安全问题?
    你这个DAO性能也有问题,每次调用create方法都要 lookup datasource,为何不把 datasource cache 起来?
      

  2.   

    回答LZ的问题,首先你的DAO是线程安全的,这能保证你的DAO都是不同的,比如每个用户的请求都有自己的DAO,他们分别调用自己的create方法,那么connection也就不会冲突的,不过建立一个connection是很耗时的,建议将connection缓存起来。其次上层将connection传给DAO,根据现在你写的代码来看应该是没有问题的,因为你的DAO是不同的实例,调用应该不会发生问题,如果DAO上层用了相同的实例,那么LZ就应该控制一下了。多说几句,应该严格将事物控制在DAO层,而不要将业务和DAO混在一起,这样的话,会引发死锁问题。
      

  3.   

    因为这个dao没有实例变量和静态变量,所以它没有共享的冲突,局部变量是保存在方法调用栈中的栈帧中的,你每一次调用这个dao的方法的时候它是在不同的栈帧当中,所以它的局部变量和参数是没有冲突的。但是实例变量是在堆区的,静态变量是在方法区,所以实例变量会有冲突也就是线程的安全问题了。
      

  4.   


    我觉得在dao处理事务好像不好列,如果一个事务有多个步骤,每次都提交不是很麻烦啊? 
      

  5.   

    由于connection不是共享资源,所以不存在线程不安全的问题。对于连接的处理建议放到dao层处理,可以缓存为连接池方式。