<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    神秘的 J2ee 殿堂

    ·古之學(xué)者必有師·做學(xué)者亦要做師者·FIGHTING·

    Generic Data Access Objects一篇關(guān)于泛型DAO的文章

    This is a pattern for Data Access Objects with JDK 5.0, from the CaveatEmptor example application. It is also explained in the book Java Persistence with Hibernate. Two links you might find useful: Sessions and transactions and Open Session in View.

    This time I based the DAO example on interfaces. Tools like Hibernate already provide database portability, so persistence layer portability shouldn't be a driving motivation for interfaces. However, DAO interfaces make sense in more complex applications, when several persistence services are encapsulate in one persistence layer. I'd say that you should use Hibernate (or Java Persistence APIs) directly in most cases, the best reason to use an additional DAO layer is higher abstraction (e.g. methods like getMaximumBid() instead of session.createQuery(...) repeated a dozen times).

    The DAO interfaces

    I use one interface per persistent entity, with a super interface for common CRUDfunctionality:

    public interface GenericDAO<T, ID extends Serializable> {

        T findById(ID id, 
    boolean lock);

        List
    <T> findAll();

        List
    <T> findByExample(T exampleInstance);

        T makePersistent(T entity);

        
    void makeTransient(T entity);
    }

    You can already see that this is going to be a pattern for a state-oriented data access API, with methods such as makePersistent() and makeTransient(). Furthermore, to implement a DAO you have to provide a type and an identifier argument. As for most ORM solutions, identifier types have to be serializable.

    The DAO interface for a particular entity extends the generic interface and provides the type arguments:


    public interface ItemDAO extends GenericDAO<Item, Long> {

        
    public static final String QUERY_MAXBID = "ItemDAO.QUERY_MAXBID";
        
    public static final String QUERY_MINBID = "ItemDAO.QUERY_MINBID";

        Bid getMaxBid(Long itemId);
        Bid getMinBid(Long itemId);

    }

    We basically separate generic CRUD operations and actual business-related data access operations from each other. (Ignore the named query constants for now, they are convenient if you use annotations.) However, even if only CRUD operations are needed for a particular entity, you should still write an interface for it, even it it is going to be empty. It is important to use a concrete DAO in your controller code, otherwise you will face some refactoring once you have to introduce specific data access operations for this entity.

    An implementation with Hibernate

    An implementation of the interfaces could be done with any state-management capable persistence service. First, the generic CRUD implementation with Hibernate:

    public abstract class GenericHibernateDAO<T, ID extends Serializable>
            
    implements GenericDAO<T, ID> {

        
    private Class<T> persistentClass;
        
    private Session session;

        
    public GenericHibernateDAO() {
            
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
                                    .getGenericSuperclass()).getActualTypeArguments()[
    0];
         }

        @SuppressWarnings(
    "unchecked")
        
    public void setSession(Session s) {
            
    this.session = s;
        }

        
    protected Session getSession() {
            
    if (session == null)
                
    throw new IllegalStateException("Session has not been set on DAO before usage");
            
    return session;
        }

        
    public Class<T> getPersistentClass() {
            
    return persistentClass;
        }

        @SuppressWarnings(
    "unchecked")
        
    public T findById(ID id, boolean lock) {
            T entity;
            
    if (lock)
                entity 
    = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);
            
    else
                entity 
    = (T) getSession().load(getPersistentClass(), id);

            
    return entity;
        }

        @SuppressWarnings(
    "unchecked")
        
    public List<T> findAll() {
            
    return findByCriteria();
        }

        @SuppressWarnings(
    "unchecked")
        
    public List<T> findByExample(T exampleInstance, String[] excludeProperty) {
            Criteria crit 
    = getSession().createCriteria(getPersistentClass());
            Example example 
    =  Example.create(exampleInstance);
            
    for (String exclude : excludeProperty) {
                example.excludeProperty(exclude);
            }
            crit.add(example);
            
    return crit.list();
        }

        @SuppressWarnings(
    "unchecked")
        
    public T makePersistent(T entity) {
            getSession().saveOrUpdate(entity);
            
    return entity;
        }

        
    public void makeTransient(T entity) {
            getSession().delete(entity);
        }

        
    public void flush() {
            getSession().flush();
        }

        
    public void clear() {
            getSession().clear();
        }

        
    /**
         * Use this inside subclasses as a convenience method.
         
    */
        @SuppressWarnings(
    "unchecked")
        
    protected List<T> findByCriteria(Criterion criterion) {
            Criteria crit 
    = getSession().createCriteria(getPersistentClass());
            
    for (Criterion c : criterion) {
                crit.add(c);
            }
            
    return crit.list();
       }

    }

    There are some interesting things in this implementation. First, it clearly needs a Session to work, provided with setter injection. You could also use constructor injection. How you set the Session and what scope this Session has is of no concern to the actual DAO implementation. A DAO should not control transactions or the Session scope.

    We need to suppress a few compile-time warnings about unchecked casts, because Hibernate's interfaces are JDK 1.4 only. What follows are the implementations of the generic CRUD operations, quite straightforward. The last method is quite nice, using another JDK 5.0 feature, varargs. It helps us to build Criteria queries in concrete entity DAOs. This is an example of a concrete DAO that extends the generic DAO implementation for Hibernate:

    public class ItemDAOHibernate
            
    extends     GenericHibernateDAO<Item, Long>
            
    implements  ItemDAO {

        
    public Bid getMaxBid(Long itemId) {
            Query q 
    = getSession().getNamedQuery(ItemDAO.QUERY_MAXBID);
            q.setParameter(
    "itemid", itemId);
            
    return (Bid) q.uniqueResult();
        }

        
    public Bid getMinBid(Long itemId) {
            Query q 
    = getSession().getNamedQuery(ItemDAO.QUERY_MINBID);
            q.setParameter(
    "itemid", itemId);
            
    return (Bid) q.uniqueResult();
        }

    }
    Another example which uses the findByCriteria() method of the superclass with variable arguments:
    public class CategoryDAOHibernate
            
    extends     GenericHibernateDAO<Category, Long>
            
    implements  CategoryDAO {

        
    public Collection<Category> findAll(boolean onlyRootCategories) {
            
    if (onlyRootCategories)
                
    return findByCriteria( Expression.isNull("parent") );
            
    else
                
    return findAll();
        }
    }

    Preparing DAOs with factories

    We could bring it all together in a DAO factory, which not only sets the Session when a DAO is constructed but also contains nested classes to implement CRUD-only DAOs with no business-related operations:


    public class HibernateDAOFactory extends DAOFactory {

        
    public ItemDAO getItemDAO() {
            
    return (ItemDAO)instantiateDAO(ItemDAOHibernate.class);
        }

        
    public CategoryDAO getCategoryDAO() {
            
    return (CategoryDAO)instantiateDAO(CategoryDAOHibernate.class);
        }

        
    public CommentDAO getCommentDAO() {
            
    return (CommentDAO)instantiateDAO(CommentDAOHibernate.class);
        }

        
    public ShipmentDAO getShipmentDAO() {
            
    return (ShipmentDAO)instantiateDAO(ShipmentDAOHibernate.class);
        }

        
    private GenericHibernateDAO instantiateDAO(Class daoClass) {
            
    try {
                GenericHibernateDAO dao 
    = (GenericHibernateDAO)daoClass.newInstance();
                dao.setSession(getCurrentSession());
                
    return dao;
            } 
    catch (Exception ex) {
                
    throw new RuntimeException("Can not instantiate DAO: " + daoClass, ex);
            }
        }

        
    // You could override this if you don't want HibernateUtil for lookup
        protected Session getCurrentSession() {
            
    return HibernateUtil.getSessionFactory().getCurrentSession();
        }

        
    // Inline concrete DAO implementations with no business-related data access methods.
        
    // If we use public static nested classes, we can centralize all of them in one source file.

        
    public static class CommentDAOHibernate
                
    extends GenericHibernateDAO<Comment, Long>
                
    implements CommentDAO {}

        
    public static class ShipmentDAOHibernate
                
    extends GenericHibernateDAO<Shipment, Long>
                
    implements ShipmentDAO {}

    }
    This concrete factory for Hibernate DAOs extends the abstract factory, which is the interface we'll use in application code:
    public abstract class DAOFactory {

        
    /**
         * Creates a standalone DAOFactory that returns unmanaged DAO
         * beans for use in any environment Hibernate has been configured
         * for. Uses HibernateUtil/SessionFactory and Hibernate context
         * propagation (CurrentSessionContext), thread-bound or transaction-bound,
         * and transaction scoped.
         
    */
        
    public static final Class HIBERNATE = org.hibernate.ce.auction.dao.hibernate.HibernateDAOFactory.class;

        
    /**
         * Factory method for instantiation of concrete factories.
         
    */
        
    public static DAOFactory instance(Class factory) {
            
    try {
                
    return (DAOFactory)factory.newInstance();
            } 
    catch (Exception ex) {
                
    throw new RuntimeException("Couldn't create DAOFactory: " + factory);
            }
        }

        
    // Add your DAO interfaces here
        public abstract ItemDAO getItemDAO();
        
    public abstract CategoryDAO getCategoryDAO();
        
    public abstract CommentDAO getCommentDAO();
        
    public abstract ShipmentDAO getShipmentDAO();

    }

    Note that this factory example is suitable for persistence layers which are primarily implemented with a single persistence service, such as Hibernate or EJB 3.0 persistence. If you have to mix persistence APIs, for example, Hibernate and plain JDBC, the pattern changes slightly. Keep in mind that you can also call session.connection() inside a Hibernate-specific DAO, or use one of the many bulk operation/SQL support options in Hibernate 3.1 to avoid plain JDBC.

    Finally, this is how data access now looks like in controller/command handler code (pick whatever transaction demarcation strategy you like, the DAO code doesn't change):


    // EJB3 CMT: @TransactionAttribute(TransactionAttributeType.REQUIRED)
    public void execute() {

        
    // JTA: UserTransaction utx = jndiContext.lookup("UserTransaction");
        
    // JTA: utx.begin();

        
    // Plain JDBC: HibernateUtil.getCurrentSession().beginTransaction();

        DAOFactory factory 
    = DAOFactory.instance(DAOFactory.HIBERNATE);
        ItemDAO itemDAO 
    = factory.getItemDAO();
        UserDAO userDAO 
    = factory.getUserDAO();

        Bid currentMaxBid 
    = itemDAO.getMaxBid(itemId);
        Bid currentMinBid 
    = itemDAO.getMinBid(itemId);

        Item item 
    = itemDAO.findById(itemId, true);

        newBid 
    = item.placeBid(userDAO.findById(userId, false),
                                bidAmount,
                                currentMaxBid,
                                currentMinBid);

        
    // JTA: utx.commit(); // Don't forget exception handling

        
    // Plain JDBC: HibernateUtil.getCurrentSession().getTransaction().commit(); // Don't forget exception handling

    }
    The database transaction, either JTA or direct JDBC, is started and committed in an interceptor that runs for every execute(), following the Open Session in View pattern. You can use AOP for this or any kind of interceptor that can be wrapped around a method call, see Session handling with AOP.

    出自:http://www.hibernate.org



    posted on 2007-09-12 16:22 月芽兒 閱讀(1473) 評(píng)論(0)  編輯  收藏 所屬分類: J2EE學(xué)習(xí)摘錄

    導(dǎo)航

    統(tǒng)計(jì)

    常用鏈接

    留言簿(2)

    隨筆分類

    隨筆檔案

    相冊(cè)

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 四虎影视永久免费观看| 欧亚精品一区三区免费| 红杏亚洲影院一区二区三区| 免费一级特黄特色大片| 亚洲国产精品久久久久婷婷软件 | 国产精品色午夜免费视频| 国产成人亚洲综合网站不卡| 成人A毛片免费观看网站| 亚洲精品午夜无码专区| 国产亚洲人成在线播放| 免费A级毛片无码A∨免费| 亚洲精品国产成人| 97在线免费视频| 免费va在线观看| 国产日韩久久免费影院 | 国产精品亚洲αv天堂无码| 九九九精品视频免费| 亚洲中文字幕无码久久精品1| 国产午夜免费高清久久影院| 免费人成年轻人电影| 久久国产精品免费一区| 久久国产亚洲观看| 97在线线免费观看视频在线观看| 国产精品无码亚洲一区二区三区| 夜色阁亚洲一区二区三区| 最新亚洲春色Av无码专区| 全部免费a级毛片| 精品亚洲永久免费精品| 亚洲av无码久久忘忧草| 亚洲 自拍 另类小说综合图区| 免费观看一区二区三区| 久久精品国产亚洲沈樵| 99视频免费在线观看| 亚洲国产午夜精品理论片| 波多野结衣中文一区二区免费| 色www永久免费| 亚洲精品无码av片| 日本免费一区尤物| 在线涩涩免费观看国产精品| 亚洲www77777| 亚洲邪恶天堂影院在线观看|