DAO Design Pattern and Connection Handling

点点圈 提交于 2019-12-08 14:00:30

问题


I have EmployeeDAOImpl.java and DepartmentDAOImpl.java. Now I am calling this two from data service layer. EmployeeDAO and DepartmentDAO is interface and they have only abtract CRUD methods. In Service layer I have two method call createEmployee(Employee employee) and createDepartment(Department department) with in a method. These 2 calls should be in same transaction that means you cant close connection only after 2 calls succeeded. Now do you people have any idea how to supply a connection. I dont want to supply a connection at the constructor of DepartmentDAOImpl and EmployeeDAOImpl. Also I dont want to use Spring AOP or ThreadLocale, Is there any solution to do that?


回答1:


I dont want to use Spring AOP or ThreadLocale

Unfortunately (?) this is how Spring handles transactions and connections - (in short) once you enter @Transactional method from non-transactional context it places database connection responsible for that transaction in ThreadLocal. This way every method within that transaction uses the same connection, thus the same transaction. This is completely transaprent, you just use DataSource abstraction or JdbcTemplate (that elegantly hides this complexity).

Notice that passing connection as a constructor parameter is completely broken in multi-threaded environment. You should pass DataSource instead. Spring (or EJB for that matter) will handle the low-level stuff.

Slightly better approach would be to pass Connection to every method of every DAO. But this is sooo 1990s... Can you elaborate what you don't like about Spring approach?




回答2:


You don't explain why you don't want to supply a connection to the DAO constructors or use Spring AOP or ThreadLocale.

I would say that the connection acquisition is part of the transaction management, which is the responsibility of the service tier. It should supply the DAOs with what they need to connect to the database.

You've said how you won't do it, but offered no ideas about how you would do it.

I'd say that service ought to get the connection from a pool, give it to the DAOs, manage the transaction, and return the connection to the pool when the use case is done.

I'll leave implementation details to you, since you don't want to use Spring. It's possible to do it using straight JDBC. You'll just have to work harder to do it.

If you insist on not using Spring or AOP, your service code will look something like this:

package service;

public class FooServiceImpl implements FooService {
    public void saveFoo(Foo f) {
        Connection connection = null;
        Statement st = null;
        try {
            connection = ConnectionPool.checkout();
            connection.setAutoCommit(false);
            // do something here
            connection.commit();
        } catch (Exception e) {
            rollback(connection);
            e.printStackTrace();
        } finally {
            close(st);
            close(connection);
        }
    }
}

Spring and AOP will be a benefit here. It'll eliminate the boilerplate code. It's your choice.




回答3:


I am on a project ,and folks dont drink the Spring kool-aid...i found the below pattern works well for me...

Service-->*Manager-->DAOs

Say you have 3 different tables that must update within a single transaction(all or nothing). One of the tables is the 'parent' table , with Children tables that must update during a parent save.

public class ParentServive
    private ParentManager parentManager; 

    public void save(Parent parent){
         parentManager.save(parent)
    }
}

create a DAOManager that all *Manager classes would exxtend

public class DAOManager{
...
..
  public Connection getConnection()throws DAOException{
  try{
    dataSource.getConnection();
    }catch(SQLException e){
    throw new DAOExceptoin(e);
    }
  }

    public Connection getTXConnection()throws DAOException{
     Connection connection  = dataSource.connection;
     connection.setAutoCommit(false);
     return connection;
  }

  public void close(Connection connectoin) throws DAOException{

  try{
      if ( !connection.getAutoCommit() ){
         connection.setAutoCommit(true);
     }
     connection.close();
     }catch(SQLException e){
      throw new DAOExceptoin(e);
    }
  }
}

now you have two DAOs that the Parent table must update in order for a save to be valid first create an abstract DAOManager Notice I opened only one connection and can rollback or commit on all tables...

 public class ParentManager extends DAOManager{
   private ParentDAO parentDAO;
   private ChildOneDAO childOneDAO;
   private ChildTwoDAO childTwoDAO;

   public save(Parent parent) throw DAOException{
      Connection connection = null;

      try{
      connection = getTXConnection(); 
      ParentDAO parentDAO   = new ParentDAO(connection);
      ChildTwoDAO childTwoDAO = new ChildOneDAO(connection);
      ChildTwoDAO childTwoDAO = new ChildTwoDAO(connection);

      parentDAO.save(...)

      childOneDAO.save(...)

      childTwoDAO.save(..)    


      connection.commit();

      }catch(Exception e){    
        connection.rollback();
      }finally{
      close(connection);
      }
   }
}

Then your service can use ONLY the Manager classes..and not worry about Connection Management... Each "table" has a Manager and DAO(s) to use is the drawback.



来源:https://stackoverflow.com/questions/14221989/dao-design-pattern-and-connection-handling

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!