熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

使用Annotation設計持久層

2013-11-23 19:19:20  來源: Java核心技術 
    這篇文章的想法來自於過去的兩篇文章《設計自己的MVC框架》《設計模式之事務處理》
鏈接




代碼下載同樣在的郵箱裡用戶名 sharesources 密碼 javafans

    本文只是學習性質的文章我一開始的想法就是修改《設計模式之事務處理》提供Annotation來提供事務支持支持到方法級別通過引入一個 @Transaction標注如果被此標注的方法將自動享受事務處理目的是學習下Annotation和加深下對聲明式事務處理的理解

    Annotation是JDK引入的新特性現在越來越多的框架采用此特性來代替煩瑣的xml配置文件比如hibernateejb spring等對Annotation不了解請閱讀IBM網站上的文章還有推薦javaeye的Annotation專欄 ///subject/Annotation

    代碼的示例是一個簡單的用戶管理例子

    首先環境是mysql+jdk+myeclipse+tomcat在mysql中建立一張表adminusers:


        create table adminusers(id int() auto_increment not null primary key
         name varchar() not null
         password varchar() not null
         user_type varchar());
 
    然後在tomcat下建立一個數據源把代碼中的strutsletxml拷貝到tomcat安裝目錄下的 /conf/Catalina/localhost目錄裡請自行修改文件中的數據庫用戶名和密碼以及數據庫名稱另外把mysql的 jdbc驅動拷貝到tomcat安裝目錄下的common/lib目錄這樣數據源就建好了在webxml中引用



       <resourceref>
            <description>DB Connection</description>
            <resrefname>jdbctest</resrefname>
            <restype>javaxsqlDataSource</restype>
            <resauth>Container</resauth>
        </resourceref>
    
    我的例子只是在《設計模式之事務處理》的基礎上改造的在那篇文章裡我講解了自己對聲明式事務處理的理解並利用動態代理實現了一個 TransactionWrapper(事務包裝器)通過業務代理工廠提供兩種版本的業務對象經過事務包裝的和未經過事務包裝的我們在默認情況下包裝業務對象中的所有方法但實際情況是業務對象中的很多方法不用跟數據庫打交道它們根本不需要包裝在一個事務上下文中這就引出了我們為什麼不提供一種方式來配置哪些方法需要事務控制而哪些並不需要?甚至提供事務隔離級別的聲明?很自然的想法就是提供一個配置文件類似spring式的事務聲明既然JDK已經引入Annotation相比於配置文件的煩瑣和容易出錯我們定義一個@Transaction的annotation來提供此功能

    看下Transactionjava的代碼
 

        package comstrutsletdb;

        import javalangannotationDocumented;
        import javalangannotationElementType;
        import javalangannotationRetention;
        import javalangannotationRetentionPolicy;
        import javalangannotationTarget;
        import javasqlConnection;

        @Target(ElementTypeMETHOD)
        @Retention(RetentionPolicyRUNTIME)
        @Documented
        public @interface Transaction {
           //事務隔離級別默認為read_committed
           public int level() default ConnectionTRANSACTION_READ_COMMITTED    ;
        }

  @Transaction 標注只有一個屬性levellevel表示事務的隔離級別默認為Read_Committed(也是一般JDBC驅動的默認級別JDBC驅動默認級別一般於數據庫的隔離級別一致) @Target(ElementTypeMETHOD)表示此標注作用於方法級別 @Retention(RetentionPolicyRUNTIME)表示在運行時此標注的信息將被加載進JVM並可以通過Annotation的 API讀取我們在運行時讀取Annotation的信息根據隔離級別和被標注的方法名決定是否將業務對象的方法加進事務控制我們只要稍微修改下 TransactionWrapper:

//TransactionWrapperjava




    package comstrutsletdb;

    import javalangannotationAnnotation;
    import javalangreflectInvocationHandler;
    import javalangreflectMethod;
    import javalangreflectProxy;
    import javasqlConnection;
    import javasqlSQLException;

    import comstrutsletexceptionSystemException;

    public class TransactionWrapper {

       
        public static Object decorate(Object delegate) {
            return ProxynewProxyInstance(delegategetClass()getClassLoader()
                    delegategetClass()getInterfaces() new XAWrapperHandler(
                            delegate));
        }

        static final class XAWrapperHandler implements InvocationHandler {
            private final Object delegate;

            XAWrapperHandler(Object delegate) {
                // Cache the wrapped delegate so we can pass method invocations
                // to it
                thisdelegate = delegate;
            }

            public Object invoke(Object proxy Method method Object[] args)
                    throws Throwable {
                Object result = null;
                Connection con = ConnectionManagergetConnection();
                //得到Transaction標注
                Transaction transaction = methodgetAnnotation(Transactionclass);

                //如果不為空說明代理對象調用的方法需要事務控制
                if (transaction != null) {
                    // Systemoutprintln(transaction + contoString());
                    // 得到事務隔離級別信息
                    int level = transactionlevel();
                    try {
                        if (congetAutoCommit())
                            consetAutoCommit(false);
                        //設置事務隔離級別
                        consetTransactionIsolation(level);
                        //調用原始對象的業務方法
                        result = methodinvoke(delegate args);
                        mit();
                        consetAutoCommit(true);
                    } catch (SQLException se) {
                        // Rollback exception will be thrown by the invoke method
                        conrollback();
                        consetAutoCommit(true);
                        throw new SystemException(se);
                    } catch (Exception e) {
                        conrollback();
                        consetAutoCommit(true);
                        throw new SystemException(e);
                    }
                } else {
                    result = methodinvoke(delegate args);
                }

                return result;
            }
        }
    }
 
現在看下我們的UserManager業務接口請注意我們是使用動態代理只能代理接口所以要把@Transaction標注是接口中的業務方法(與EJB中的RemoteLocal接口類似的道理):



    package comstrutsletdemoservice;

    import javasqlSQLException;

    import comstrutsletdbTransaction;
    import comstrutsletdemodomainAdminUser;

    public interface UserManager {
        //查詢不需要事務控制
        public boolean checkUser(String name String password) throws SQLException;

        //新增一個用戶需要事務控制默認級別
        @Transaction
        public boolean addUser(AdminUser user) throws SQLException;

    }
 

    要把addUser改成其他事務隔離級別(比如oracle的serializable級別)稍微修改下@Transaction(level=ConnectionTRANSACTION_SERIALIZABLE)
public boolean addUser(AdminUser user) throws SQLException;

     不准備詳細解釋例子的業務流程不過是登錄和增加用戶兩個業務方法看下就明白閱讀本文前最好已經讀過開頭提過的兩篇文章我相信代碼是最好的解釋


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26651.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.