少年阿賓

          那些青春的歲月

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            500 Posts :: 0 Stories :: 135 Comments :: 0 Trackbacks

          #

          package com.abin.lee.servlet.process;

          import java.io.IOException;

          import javax.servlet.RequestDispatcher;
          import javax.servlet.ServletContext;
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          public class ProcessServlet extends HttpServlet{
           public void init() throws ServletException {
            super.init();
           }
           @SuppressWarnings("rawtypes")
           protected void doPost(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
            String username=request.getParameter("username");
            String password=request.getParameter("password");
            System.out.println("username="+username);
            System.out.println("password="+password);
            
            ServletContext context = getServletContext();
            RequestDispatcher dispatcher = context.getNamedDispatcher("dispatcher");
            dispatcher.forward(request, response);


          //  ServletOutputStream out=response.getOutputStream();
          //  BufferedWriter writer=new BufferedWriter(new OutputStreamWriter(out));
          //  writer.write("success");
          //  writer.flush();
          //  writer.close();
            
           }
           public void destroy() {
            super.destroy();
           }
          }









          package com.abin.lee.servlet.process;

          import java.io.IOException;
          import java.io.PrintWriter;
          import java.io.StringWriter;

          import javax.servlet.RequestDispatcher;
          import javax.servlet.ServletContext;
          import javax.servlet.ServletException;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;

          import junit.framework.TestCase;

          import org.easymock.EasyMock;
          import org.junit.Before;
          import org.junit.Test;
          public class ServletMock extends TestCase{
           private static HttpServletRequest request =null;
           private static HttpServletResponse response=null;
           private static ServletContext context=null;
           private static RequestDispatcher dispatcher=null;
           private static ProcessServlet servlet=null;
           @Before
           public  void setUp(){
            request =EasyMock.createMock(HttpServletRequest.class);
            response=EasyMock.createMock(HttpServletResponse.class);
            context=EasyMock.createMock(ServletContext.class);
            dispatcher=EasyMock.createMock(RequestDispatcher.class);
            servlet=new ProcessServlet(){
             private static final long serialVersionUID = 7534303474286669635L;

             public ServletContext getServletContext(){
              return context;
             }
            };
           }
           @Test
           public void test() throws ServletException, IOException{
            EasyMock.expect(request.getParameter("username")).andReturn("abin").times(20000);
            EasyMock.expect(request.getParameter("password")).andReturn("varyall").times(20000);
            EasyMock.expectLastCall();
            EasyMock.replay(request);
            EasyMock.replay(response);
            servlet.doPost(request, response);
            EasyMock.verify(response);
            dispatcher.forward(request, response);
            StringWriter sw=new StringWriter();
            PrintWriter writer=new PrintWriter(sw, true);
            response.getOutputStream();
          //  response.set
          //  String line="";
          //  String result="";
          //  while((line=writer.)){
          //   
          //  }
          //  BufferedReader reader=new BufferedReader(new InputStreamReader());
            
            
            
            
           }
          }

          posted @ 2012-11-04 22:29 abin 閱讀(741) | 評論 (0)編輯 收藏

          簡單的JUnit測試

          本文介紹在NetBeans開發工具中編寫和運行JUnit單元測試的基礎部分。測試一個應用程序是開發周期的一部分,編寫和維護單元測試可以保證你源代碼中獨立的方法可以正常工作。

          NetBeans IDE 6.9 中包含JUnit 3.5和JUnit 4.5兩個版本,可自行選擇。(關于使用JUnit的更多信息,參考www.junit.org。)

          目錄
          一、新建Java測試包
          二、創建Java類庫
          三、JUnit注釋
          四、簡單的JUnit4測試方法
          五、運行測試


          一、新建Java測試包

          用于存放JUnit測試類庫的包
          1.右擊“測試包”>“新建”>“Java包”。
          2.在“新建Java包”對話框中,輸入包名,選擇位置(位置最好為“測試包”,以便于區分源碼包與測試包)。
          3.“完成”即可。

          二、創建java類庫測試

          用于為java類庫文件創建測試。
          1.右擊要創建測試的類文件,選擇“工具”>“創建 JUnit 測試”。
          2.在“選擇 JUnit 版本”對話框中,選擇“JUnit 4”。
          3.彈出“創建測試”對話框,在“創建測試”對話框中可以創建的測試命名、選擇位置(最好選擇測試包)。
          注:NetBeans中第一次使用 IDE 創建測試框架時,IDE 會提示選擇 JUnit 版本。選擇JUnit4后會自動刪除JUnit 3庫,下次再創建時,會默認創建JUnit4的測試。

          三、JUnit注釋

          JUnit注釋跟在測試方法前,對測試方法的類型進行說明。

          1.JUnit測試注釋

          測試注釋:@Test 標注將方法標記為測試方法。

          2.測試類、測試的初始化函數和釋放方法

          在 JUnit 4 中,可以使用標注來標記以下類型的初始化函數和釋放方法。
          測試類初始化函數:@BeforeClass 標注將方法標記為測試類初始化方法。測試類初始化方法只能運行一次,并且在測試類中的任何其他方法之前運行。
          測試類釋放方法:@AfterClass 標注將方法標記為測試類釋放方法。測試類釋放方法只能運行一次,并且在測試類中的任何其他方法完成之后運行。
          測試初始化函數:@Before 標注將方法標記為測試初始化方法。測試初始化方法在測試類中的各測試用例之前運行。運行測試不需要測試初始化方法,但是,如果需要在
          運行測試之前初始化一些變量,則可以使用測試初始化方法。
          測試釋放方法:@After 標注將方法標記為測試釋放方法。測試釋放方法在測試類中的各測試用例之后運行。運行測試不需要測試釋放方法,但是,可能需要使用釋放方法
          來清理運行測試用例時所需的任何數據。

          3.禁用測試注釋

          禁用測試:@Ignore 標注將該方法禁用。

          四、簡單的JUnit4測試方法

          創建java類庫測試后,分生成該類所有方法的測試方法。(測試方法很多)
          斷言
          1.assertEquals( 期望值, 實際值 ) // 實際值用被測試方法代替時就是對該方法的測試
          2.assertTrue( 實際值 )
          3.assert False(實際值)
          注:此方法使用 JUnit assertTrue 和 assertFalse 方法來測試各種可能的結果。要通過此方法的測試,assertTrue 必須全部為 true,并且 assertFalse 必須
          全部為 false。
          超時
          4.@Test(timeout=1000) // 超時被設置為 1000 毫秒。
          異常:
          5.@Test(expected=IllegalArgumentException.class) // 返回異常
          禁用測試:
          6.@Ignore // 在@Test 上方添加 @Ignore 標注來禁用測試。

          五、運行測試

          1.運行單個測試:
          右擊要運行的測試,選擇“運行文件”。
          2.運行整個測試:
          1)右擊要運行的測試包,選擇“新建”>“其它”打開“新建向導”。
          2)類別選擇“JUnit”,文件類型選擇“測試套件”,點擊“下一步”。
          3)輸入測試名,選擇位置,及要測試的包。
          4)“完成”即可。
          此時運行這個測試套件即可運行包內的所有測試。
          posted @ 2012-11-02 14:40 abin 閱讀(1338) | 評論 (0)編輯 收藏

          軟件測試
          ___________________________________________________________________________
          Unit Test是由程序員本身來編寫的。

          以下介紹Junit單元測試框架:官網地址www.junit.org

          JUnit是由 Erich Gamma 和 Kent Beck 編寫的一個回歸測試框架(regression testing framework)。Junit測試是程序員測試,即所謂白盒測試,因為程序員知道被測試的軟件如何(How)完成功能和完成什么樣(What)的功能。

          Junit3.x
          ___________________________________________________________________________

          Junit3.x中使用包junit.framework.*

          1.       必須繼承TestCase類

          public class CalculatorTest extends TestCase {

              private Calculator cal;

              public CalculatorTest() {

              }

              public CalculatorTest(String name) {

                  super(name);

              }

              public void setUp() {

                  System.out.println("...........setUp..............");

                  cal = new Calculator();

              }

              public void testAdd() {

                  int result = cal.add(1, 2);

                  Assert.assertEquals("計算添加失敗", 3, result);

                   }

          public void tearDown() {

                  System.out.println("........tearDown........");

                   }

          }



          2.       測試用例(Test Case)是單元測試的一個非常重要的方面。

          3.       單元測試主要是用來判斷程序的執行結果與自己期望的結果是否一致。

          4.       在Junit3.x中,測試方法規則定義如下:

          1)      public

          2)      void

          3)      無參數的

          4)      測試方法名以test開頭

          5.       Test Case之間一定要保持完全的獨立性,不允許出現任何的依賴關系。

          6.       我們不能依賴于測試方法的執行順序。

          7.       關于setUp與tearDown方法的執行順序:

          1) setUp

          2) testAdd

          3) tearDown

          8.       Junit兩種類型錯誤,Failure 和 Error

          Failure:指預期結果與實際結果不同,例如當你使用assertEquals或者assertXXX方法斷言失敗時,或者調用fail方法,就會報出Failure,這時要檢查測試方法邏輯設計是否有誤。

              public void testDevide() {

                  System.out.println(".........testDevide()........");

                  int expected = 0;

                  int actual = 0;

                  try {

                      actual = cal.devide(1, 3);

                  } catch (Exception e) {

                      Assert.fail("測試失敗"); //不應該執行這段.

                  }

                  Assert.assertEquals(expected, actual);

              }

                   Error:指程序在斷言執行之前,程序就因為某種錯誤而引發異常,導致程序終止,例如測試方法中因拋出某個異常,使得測試方法無法正確執行到斷言就結束,這時你要檢查測試的方法是否有未考慮到的情況而引起流程突然中斷。

                         也就是說代碼中拋出了異常等影響代碼正常執行的情況,比如ArrayIndexOfBoundsException、NullPointException,也可能是磁盤已滿、網絡中斷等等外部環境失敗所帶來的影響。

          首先處理Error,然后在處理Failure.

          9.       運行測試用例

          1)      IDE中,如Eclipse工具已經內置了Junit,所以可以直接在測試類中鼠標右鍵Run--Junit Test運行。



          2)      使用junit.textui.TestRunner類運行測試類.

          public static void main(String[] args) {

                  junit.textui.TestRunner.run(MyStackTest.class);

                  junit.textui.TestRunner.run(new CalculatorTest("testAdd"));

          }

          3)      使用TestSuite

          a)        一次可以運行多個測試類進行測試

          public class TestAll {
              public static Test suite() {
                  TestSuite suite = new TestSuite();
                  suite.addTestSuite(OOOTest.class);
                  suite.addTestSuite(XXXTest.class);
                  suite.addTestSuite(YYYTest.class);
                  return suite;
              }
              public static void main(String[] args) {
                  TestRunner.run(suite());
              }
          }

          b)        通過IDE自動發現suite()方法,必須繼承TestCase

          public class TestAll extends TestCase {
              public static Test suite() {
                  TestSuite suite = new TestSuite();
                  suite.addTestSuite(OOOTest.class);
                  suite.addTestSuite(XXXTest.class);
                  suite.addTestSuite(YYYTest.class);
                  return suite;
              }
          }

          c)   組合模式,組合方式多元化

          ……

          public static Test suite() {
                  TestSuite suite = new TestSuite();
                  suite.addTest(new XXXTest("testABC"));  // 執行testABC()方法
                  suite.addTest(YYYTest.suite()); // suite() 傳回TestSuite實例
                  suite.addTestSuite(OOOTest.class);//自動查找OOOTest類中testXXX方法
                  return suite;
              }

          10.測試之前是什么狀態,在測試執行完成后就應該是什么狀態,而不應該由于測試執行的原因到導致了狀態發生了變化。

          Junit4.x
          ___________________________________________________________________________

          Junit4.x開始支持Annotation注解技術,在編寫測試用例時簡化不少動作.
          Junit4.x中使用的包org.junit.*

          Junit4.x是兼容以前版本

          Eclipse中自帶了Junit4,版本為junit4.3.1. BC-EC工程中使用的版本為Junit4.4,目前最新版本4.11



          1. 無需繼承TestCase類,所有被@Test注解所修飾的public,void,無參數的方法都是測試用例,Junit自動查找注解方法并執行測試。

          @Test

              public void testAdd() {

                  int result = cal.add(1, 2);



                  Assert.assertEquals("計算添加失敗", 3, result);

          }

          2. 雖然Junit4.x中測試類中的方法名稱可以隨便取,但是建議跟junit3.x中測試類方法命名約定一致,統一方法名以test開頭。

          3. 使用@Before注解所修飾的方法同junit3.x中的setUp方法的功能,使用@After注解所修改的方法同junit3.x測試類中的tearDown方法的功能。 @Before和@After可以在多次指定.

          @Before

              public void init() {

                  System.out.println("...........setUp..............");

                  cal = new Calculator();

          }



          @After

              public void destroy() {

                  System.out.println("........tearDown........");

          }

          4. 通過@BeforeClass和@AfterClass注解標注public,static,void,無參數的類方法。在所有測試方法執行之前和之后執行。

          @BeforeClass
          public static void setUpBeforeClass() {
              ...
          }
          @AfterClass
          public static void tearDownAfterClass() {
              ...
          }

          5. 使用@Ignore注解所修飾的方法(可以表示尚未編寫完該用例或者想禁用該用例),運行器會忽略該方法的測試;當修飾類時,運行器會忽略掉所有測試方法。

          @Test

              @Ignore("尚未完成")

              public void testMultiply() {

              … …

          }

          Eclipse中Junit執行結果中會提示如下:





          6. 預期異常:

          也可以使用在junit3.x中提到的fail()來測試預期拋出異常的情況。

          public void testDevideByZero() {

                  Throwable tx = null;

                  try {

                      cal.devide(1, 0);

                      Assert.fail("應該按預期拋出異常,測試失敗");

                  } catch (Exception e) {

                      tx = e;

                  }

                  Assert.assertNotNull(tx.getMessage());

                  Assert.assertEquals(ArithmeticException.class, tx.getClass());

                  Assert.assertEquals("除數不能為0!", tx.getMessage());

          }

          junit4中使用Test中的expected屬性達到相同的功能,代碼量小很多.

              @Test(expected = ArithmeticException.class)

          public void testDevideByZero() throws Exception {

                  cal.devide(1, 0); // 應該拋出異常

          }

          7. 使用@Test(timeout = 2000) 注解預期某些操作應該在指定時間內完成,否則測試失敗。    單位是毫秒。

          8. 測試運行器:可以使用@RunWith注解使用的runner.

          Junit4中內置的運行器有:

          a) 附帶兼容junit3.x運行器

          org.junit.internal.runners.Junit38ClassRunner

          b) 參數化運行器,可設定一組參數,每次運行測試時自動在指定位置給予不同的參數。

          org.junit.runners.Parameterized

          c) Suite運行器,如同Junit3.x中的TestSuite, 用于任意組合測試.

          org.junit.runner.Suite

          9. 參數化運行器:

          a) 使用注解@RunWith(value = Parameterized.class) 指定參數化運行器,

          b) 定義好一個方法,返回一組參數數據,使用注解@Parameterized.Parameters

          c) 測試類構造方法中為各個參數賦值(構造方法是由Junit調用的)

          d) 方法必須是public,static,void,no-arg,返回一個Collection。

          e) 方法中每個元素必須是一個一維數組,數組中第一個為預期值,之后參數一,參數二等。

          @RunWith(value = Parameterized.class)

          public class ParamCalculatorTest {



              private Calculator cal;

              private int expected;

              private int para1;

              private int para2;



              @Parameterized.Parameters

              public static Collection<Integer[]> getParamData() {

                 Integer[][] data = new Integer[][] { { 5, 3, 2 }, { 3, 1, 2 }, { 2, 1, 1 } };

                  return Arrays.asList(data);

              }



              @Before

              public void init() {

                  cal = new Calculator();

              }



          public ParamCalculatorTest(int expected, int para1, int para2) {

                  this.expected = expected;

                  this.para1 = para1;

                  this.para2 = para2;

              }



              @Test

              public void testAdd() {

                  int result = cal.add(para1, para2);

                  Assert.assertEquals(expected, result);

          }



              @After

              public void destory() {

              }

          }



          10.Suite運行器:在Junit4中,如果想同時運行多個測試,需要使用兩個注解:

          @RunWith(value = Suite.class)
          @SuiteClasses

          使用以上兩個注解會通過Suite運行器來執行測試,在SuiteClasses中指定測試類,也可以繼續指定Suite,這樣Junit會在去查找里面的測試類并執行。

              @RunWith(value = Suite.class)

          @SuiteClasses( { CalculatorTest.class, MyStackTest.class })

          public class SuiteCalculatorMyStackTest {

              … …

          }

          posted @ 2012-11-02 14:16 abin 閱讀(1290) | 評論 (0)編輯 收藏

          myEclipse項目轉成Eclipse開發

          公司拿到手的項目開發平臺都不統一。有的是myEclipse開發的,有的是Eclipse for J2EE開發的。

          這里說一種把myEclipse項目轉成Eclipse項目繼續開發


          1.  請首先確保你的eclipse是javaee版本的,或者已經安裝看wtp插件


          2.  然后修改eclipse工程下的.project文件:

          3.在<natures></natures>中加入
              <nature>org.eclipse.wst.common.project.facet.core.nature</nature>
              <nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
              <nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
          4. 在<buildSpec>< ildSpec>中加入
              <buildCommand>
                  <name>org.eclipse.wst.common.project.facet.core.builder</name>
                  <arguments>
                  </arguments>
              </buildCommand>
              <buildCommand>
                  <name>org.eclipse.wst.validation.validationbuilder</name>
                  <arguments>
                  </arguments> 
               </buildCommand>
          5. 刷新項目,項目->右擊->Properties->Project Facets->Modify Project,選擇Java和Dynamic Web Module配置Context Root 和Content Directory 以及源碼路徑
          6. 第5步沒有的話,找到項目的.setting目錄,修改org.eclipse.wst.common.component  里面的
          <wb-module   deploy-name= "Demo ">
          <wb-resource   deploy-path= "/ "   source-path= "/WebRoot "/>

          這兩個即可,deploy-name   為工程名,source-   path= "/WebRoot "eclipse下默認為WebContent修改為WebRoot


          svn
          http://subclipse.tigris.org/update_1.6.x


          -Xms512m -Xmx1024m -XX:PermSize=128m -XX:MaxNewSize=256m -XX:MaxPermSize=256m
          posted @ 2012-11-01 09:38 abin 閱讀(4343) | 評論 (0)編輯 收藏

          1. 查看processes和sessions參數

          SQL> show parameter processes

          NAME                                 TYPE        VALUE
          ------------------------------------ ----------- ------------------------------
          aq_tm_processes                      integer     1
          db_writer_processes                  integer     1
          job_queue_processes                  integer     10
          log_archive_max_processes            integer     2
          processes                            integer     150

           

          SQL> show parameter sessions

          NAME                                 TYPE        VALUE
          ------------------------------------ ----------- ------------------------------
          java_max_sessionspace_size           integer     0
          java_soft_sessionspace_limit         integer     0
          license_max_sessions                 integer     0
          license_sessions_warning             integer     0
          logmnr_max_persistent_sessions       integer     1
          mts_sessions                         integer     165
          sessions                             integer     170
          shared_server_sessions               integer     165
          SQL>

           

          2. 修改processes和sessions值

          SQL> alter system set processes=300 scope=spfile;

          系統已更改。

          SQL> alter system set sessions=335 scope=spfile;

          系統已更改。

          3. 修改processes和sessions值必須重啟oracle服務器才能生效

          ORACLE的連接數(sessions)與其參數文件中的進程數(process)有關,它們的關系如下:

          sessions=(1.1*process+5)

           

           查詢數據庫當前進程的連接數:

           select count(*) from v$process;

            查看數據庫當前會話的連接數:

            select count(*) from v$session;

            查看數據庫的并發連接數:

            select count(*) from v$session where status='ACTIVE';

            查看當前數據庫建立的會話情況:

            select sid,serial#,username,program,machine,status from v$session;

           查詢數據庫允許的最大連接數:

            select value from v$parameter where name = 'processes';

            或者:show parameter processes;

            修改數據庫允許的最大連接數:

            alter system set processes = 300 scope = spfile;

            (需要重啟數據庫才能實現連接數的修改)

            重啟數據庫:

            shutdown immediate;

            startup;

            查看當前有哪些用戶正在使用數據:

            select osuser,a.username,cpu_time/executions/1000000||'s',sql_fulltext,machine

            from v$session a,v$sqlarea b

            where a.sql_address = b.address

            order by cpu_time/executions desc;

            備注:UNIX 1個用戶session對應一個操作系統process,而Windows體現在線程。

            啟動oracle

            su - oracle

            sqlplus system/pwd as sysdba   //進入sql

            startup                                      //啟動數據庫

            lsnrctl start                               //啟動監聽

            sqlplus "/as sysdba"

            shutdown immediate;

            startup mount;

            alter database open;

          posted @ 2012-10-31 09:47 abin 閱讀(1973) | 評論 (0)編輯 收藏

          posted @ 2012-10-29 22:42 abin 閱讀(1007) | 評論 (0)編輯 收藏

          一:安裝
            1,如果是LINUX系統,可以到官方網址http://memcached.org/進行下載,安裝教程網上一大堆,這里不再敘述。
            2,如果是WINDOWS系統

               - 到http://code.jellycan.com/memcached/下載穩定版。

               - 下載后解壓到某個盤下面,比如在c:\memcached,在終端(也即cmd命令界面)下輸入 ‘c:\memcached\memcached.exe -d install’ 安裝。

               - 再輸入: ‘c:\memcached\memcached.exe -d start’ 啟動。

               - 修改memcache的內存大小,可以在注冊表里找到HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/memcached Server,修改ImagePath的值為
          “C:/memcached/memcached.exe” -d runservice -m 512
            NOTE: Windows版本一般用作開發調試只用,不建議在產品環境中使用。

          二:JAVA連接使用Memcached
            1, 下載memcached客戶端開發包,地址https://github.com/gwhalin/Memcached-Java-Client
            2,下面是一個連接并使用的簡單例子

           

          package com.ea.online.memcache;

          import java.util.Date;

          import com.danga.MemCached.MemCachedClient;
          import com.danga.MemCached.SockIOPool;

          public class MyClass {

              // create a static client as most installs only need
              // a single instance
              protected static MemCachedClient mcc = new MemCachedClient();

              protected static SockIOPool pool = null;
              // set up connection pool once at class load
              static {

                  // Server list
                  String[] servers = { "localhost:11211" };

                  // Specify memcached capacity
                  Integer[] weights = { 3, 3, 2 };

                  /*
                   * String[] serverlist = { "cache0.server.com:12345",
                   * "cache1.server.com:12345" }; Integer[] weights = { new
                   * Integer(5), new Integer(2) }; int initialConnections = 10; int
                   * minSpareConnections = 5; int maxSpareConnections = 50; long
                   * maxIdleTime = 1000 * 60 * 30; // 30 minutes long maxBusyTime = 1000 *
                   * 60 * 5; // 5 minutes long maintThreadSleep = 1000 * 5; // 5 seconds
                   * int socketTimeOut = 1000 * 3; // 3 seconds to block on reads int
                   * socketConnectTO = 1000 * 3; // 3 seconds to block on initial
                   * connections. If 0, then will use blocking connect (default) boolean
                   * failover = false; // turn off auto-failover in event of server down
                   * boolean nagleAlg = false; // turn off Nagle's algorithm on all
                   * sockets in pool boolean aliveCheck = false; // disable health check
                   * of socket on checkout
                   *
                   * SockIOPool pool = SockIOPool.getInstance();
                   * pool.setServers(serverlist);
                   * pool.setWeights(weights);
                   * pool.setInitConn(initialConnections);
                   * pool.setMinConn(minSpareConnections);
                   * pool.setMaxConn(maxSpareConnections); pool.setMaxIdle(maxIdleTime);
                   * pool.setMaxBusyTime(maxBusyTime);
                   * pool.setMaintSleep(maintThreadSleep);
                   * pool.setSocketTO(socketTimeOut); pool.setNagle(nagleAlg);
                   * pool.setHashingAlg(SockIOPool.NEW_COMPAT_HASH);
                   * pool.setAliveCheck(true); pool.initialize();
                   */

                  // grab an instance of our connection pool
                  pool = SockIOPool.getInstance();

                  // set the servers and the weights
                  pool.setServers(servers);
                  pool.setWeights(weights);

                  // Specify main thread maintain frequency
                  pool.setMaintSleep(30);

                  // set some TCP settings
                  // disable nagle
                  pool.setNagle(false);
                  // set the read timeout to 3 secs
                  pool.setSocketTO(3000);
                  // and don't set a connect timeout
                  pool.setSocketConnectTO(0);

                  // initialize the connection pool
                  pool.initialize();


              }

              // from here on down, you can call any of the client calls
              public static void main(String[] args) {
                  // Test expired
                  mcc.set("foo", "This is a test String", new Date(
                          new Date().getTime() + 3000));
                  String bar = mcc.get("foo").toString();
                  System.out.println("test-->" + bar);
                  while (true) {
                      try {
                          Thread.sleep(1000);
                      } catch (InterruptedException e) {
                          // TODO Auto-generated catch block
                          e.printStackTrace();
                      }
                      System.out.println(mcc.get("foo"));
                  }
                  // pool.shutDown();
              }
          }

           

           

          詳細使用可以借鑒這篇文章:http://sillycat.iteye.com/blog/563615

          三:結合AOP編程
            1,對于memcached與spring aop的集成網上又是一堆,這里不提了。
            2,對于memcached與guice aop的集成可參考http://code.google.com/p/google-guice/wiki/AOP
            3,對于需要通過手動實現動態代理的方式來實現AOP的可以參考 http://www.aygfsteel.com/DoubleJ/archive/2008/03/04/183796.html

          四:一個簡單的環繞通知切面,不可運行,僅作參考

          public Around implements MethodInterceptor {
           ....
              public Object invoke(MethodInvocation mi, Object[] args) {
                  Object obj = null;
                  //從Memcached中獲取
                  obj = mcc.get(this.class.getName() + mi.getMethodName() + args.hashcode());
                  if(obj != null) {
                      return obj;
                  }
                
                  obj = method.invoke(args);
                
                  //存入Memcached
                  mcc.set(this.class.getName() + mi.getMethodName() + args.hashcode, obj, expiredDate);
                  return obj;
              }
           ....

          posted @ 2012-10-26 22:54 abin 閱讀(1186) | 評論 (0)編輯 收藏

          內存溢出與數據庫鎖表的問題,可以說是開發人員的噩夢,一般的程序異常,總是可以知道在什么時候或是在什么操作步驟上出現了異常,而且根據堆棧信息也很容易定位到程序中是某處出現了問題。內存溢出與鎖表則不然,一般現象是操作一般時間后系統越來越慢,直到死機,但并不能明確是在什么操作上出現的,發生的時間點也沒有規律,查看日志或查看數據庫也不能定位出問題的代碼。

          更嚴重的是內存溢出與數據庫鎖表在系統開發和單元測試階段并不容易被發現,當系統正式上線一般時間后,操作的并發量上來了,數據也積累了一些,系統就容易出現內存溢出或是鎖表的現象,而此時系統又不能隨意停機或重啟,為修正BUG帶來很大的困難。

          本文以筆者開發和支持的多個項目為例,與大家分享在開發過程中遇到的Java內存溢出和數據庫鎖表的檢測和處理解決過程。

          2.內存溢出的分析
          內存溢出是指應用系統中存在無法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大于虛擬機能提供的最大內存。為了解決Java中內存溢出問題,我們首先必須了解Java是如何管理內存的。Java的內存管理就是對象的分配和釋放問題。在Java中,內存的分配是由程序完成的,而內存的釋放是由垃圾收集器(Garbage Collection,GC)完成的,程序員不需要通過調用GC函數來釋放內存,因為不同的JVM實現者可能使用不同的算法管理GC,有的是內存使用到達一定程度時,GC才開始工作,也有定時執行的,有的是中斷式執行GC。但GC只能回收無用并且不再被其它對象引用的那些對象所占用的空間。Java的內存垃圾回收機制是從程序的主要運行對象開始檢查引用鏈,當遍歷一遍后發現沒有被引用的孤立對象就作為垃圾回收。

          引起內存溢出的原因有很多種,常見的有以下幾種:

          l         內存中加載的數據量過于龐大,如一次從數據庫取出過多數據;

          l         集合類中有對對象的引用,使用完后未清空,使得JVM不能回收;

          l         代碼中存在死循環或循環產生過多重復的對象實體;

          l         使用的第三方軟件中的BUG;

          l         啟動參數內存值設定的過小;

          3.內存溢出的解決
          內存溢出雖然很棘手,但也有相應的解決辦法,可以按照從易到難,一步步的解決。

          第一步,就是修改JVM啟動參數,直接增加內存。這一點看上去似乎很簡單,但很容易被忽略。JVM默認可以使用的內存為64M,Tomcat默認可以使用的內存為128MB,對于稍復雜一點的系統就會不夠用。在某項目中,就因為啟動參數使用的默認值,經常報“OutOfMemory”錯誤。因此,-Xms,-Xmx參數一定不要忘記加。

          第二步,檢查錯誤日志,查看“OutOfMemory”錯誤前是否有其它異常或錯誤。在一個項目中,使用兩個數據庫連接,其中專用于發送短信的數據庫連接使用DBCP連接池管理,用戶為不將短信發出,有意將數據庫連接用戶名改錯,使得日志中有許多數據庫連接異常的日志,一段時間后,就出現“OutOfMemory”錯誤。經分析,這是由于DBCP連接池BUG引起的,數據庫連接不上后,沒有將連接釋放,最終使得DBCP報“OutOfMemory”錯誤。經過修改正確數據庫連接參數后,就沒有再出現內存溢出的錯誤。

          查看日志對于分析內存溢出是非常重要的,通過仔細查看日志,分析內存溢出前做過哪些操作,可以大致定位有問題的模塊。

          第三步,安排有經驗的編程人員對代碼進行走查和分析,找出可能發生內存溢出的位置。重點排查以下幾點:

          l         檢查代碼中是否有死循環或遞歸調用。

          l         檢查是否有大循環重復產生新對象實體。

          l         檢查對數據庫查詢中,是否有一次獲得全部數據的查詢。一般來說,如果一次取十萬條記錄到內存,就可能引起內存溢出。這個問題比較隱蔽,在上線前,數據庫中數據較少,不容易出問題,上線后,數據庫中數據多了,一次查詢就有可能引起內存溢出。因此對于數據庫查詢盡量采用分頁的方式查詢。

          l         檢查List、MAP等集合對象是否有使用完后,未清除的問題。List、MAP等集合對象會始終存有對對象的引用,使得這些對象不能被GC回收。

          第四步,使用內存查看工具動態查看內存使用情況。某個項目上線后,每次系統啟動兩天后,就會出現內存溢出的錯誤。這種情況一般是代碼中出現了緩慢的內存泄漏,用上面三個步驟解決不了,這就需要使用內存查看工具了。

          內存查看工具有許多,比較有名的有:Optimizeit Profiler、JProbe Profiler、JinSight和Java1.5的Jconsole等。它們的基本工作原理大同小異,都是監測Java程序運行時所有對象的申請、釋放等動作,將內存管理的所有信息進行統計、分析、可視化。開發人員可以根據這些信息判斷程序是否有內存泄漏問題。一般來說,一個正常的系統在其啟動完成后其內存的占用量是基本穩定的,而不應該是無限制的增長的。持續地觀察系統運行時使用的內存的大小,可以看到在內存使用監控窗口中是基本規則的鋸齒形的圖線,如果內存的大小持續地增長,則說明系統存在內存泄漏問題。通過間隔一段時間取一次內存快照,然后對內存快照中對象的使用與引用等信息進行比對與分析,可以找出是哪個類的對象在泄漏。

          通過以上四個步驟的分析與處理,基本能處理內存溢出的問題。當然,在這些過程中也需要相當的經驗與敏感度,需要在實際的開發與調試過程中不斷積累。

          總體上來說,產生內存溢出是由于代碼寫的不好造成的,因此提高代碼的質量是最根本的解決辦法。有的人認為先把功能實現,有BUG時再在測試階段進行修正,這種想法是錯誤的。正如一件產品的質量是在生產制造的過程中決定的,而不是質量檢測時決定的,軟件的質量在設計與編碼階段就已經決定了,測試只是對軟件質量的一個驗證,因為測試不可能找出軟件中所有的BUG。

           

          --------------------------------------------------------------------------------------------------------------------------------

           

          原因有很多種,比如:

          1.數據量過于龐大;死循環 ;靜態變量和靜態方法過多;遞歸;無法確定是否被引用的對象;

          2.虛擬機不回收內存(內存泄漏);

              說白了就是程序運行要用到的內存大于虛擬機能提供的最大內存就發生內存溢出了。 內存溢出的問題要看業務和系統大小而定,對于某些系統可能內存溢出不常見,但某些系統還是很常見的解決的方法,

          一個是優化程序代碼,如果業務龐大,邏輯復雜,盡量減少全局變量的引用,讓程序使用完變量的時候釋放該引用能夠讓垃圾回收器回收,釋放資源。
          二就是物理解決,增大物理內存,然后通過:-Xms256m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m的修改

          一、內存溢出類型
          1 、 java.lang.OutOfMemoryError: PermGen space

          JVM 管理兩種類型的內存,堆和非堆。堆是給開發人員用的上面說的就是,是在 JVM 啟動時創建;非堆是留給 JVM 自己用的,用來存放類的信息的。它和堆不同,運行期內 GC 不會釋放空間。如果 web app 用了大量的第三方 jar 或者應用有太多的 class 文件而恰好 MaxPermSize 設置較小,超出了也會導致這塊內存的占用過多造成溢出,或者 tomcat 熱部署時侯不會清理前面加載的環境,只會將 context 更改為新部署的,非堆存的內容就會越來越多。

          2 、 java.lang.OutOfMemoryError: Java heap space

          第一種情況是個補充,主要存在問題就是出現在這個情況中。其默認空間 ( 即 -Xms) 是物理內存的 1/64 ,最大空間 (-Xmx) 是物理內存的 1/4 。如果內存剩余不到 40 %, JVM 就會增大堆到 Xmx 設置的值,內存剩余超過 70 %, JVM 就會減小堆到 Xms 設置的值。所以服務器的 Xmx 和 Xms 設置一般應該設置相同避免每次 GC 后都要調整虛擬機堆的大小。假設物理內存無限大,那么 JVM 內存的最大值跟操作系統有關,一般 32 位機是 1.5g 到 3g 之間,而 64 位的就不會有限制了。

          注意:如果 Xms 超過了 Xmx 值,或者堆最大值和非堆最大值的總和超過了物理內存或者操作系統的最大限制都會引起服務器啟動不起來。

          垃圾回收 GC 的角色

          JVM 調用 GC 的頻度還是很高的,主要兩種情況下進行垃圾回收:

          當應用程序線程空閑;另一個是 java 內存堆不足時,會不斷調用 GC ,若連續回收都解決不了內存堆不足的問題時,就會報 out of memory 錯誤。因為這個異常根據系統運行環境決定,所以無法預期它何時出現。

          根據 GC 的機制,程序的運行會引起系統運行環境的變化,增加 GC 的觸發機會。

          為了避免這些問題,程序的設計和編寫就應避免垃圾對象的內存占用和 GC 的開銷。顯示調用 System.GC() 只能建議 JVM 需要在內存中對垃圾對象進行回收,但不是必須馬上回收,

          一個是并不能解決內存資源耗空的局面,另外也會增加 GC 的消耗。

          二、 JVM 內存區域組成
          簡單的說 java中的堆和棧

          java把內存分兩種:一種是棧內存,另一種是堆內存

          1。在函數中定義的基本類型變量和對象的引用變量都在函數的棧內存中分配;

          2。堆內存用來存放由 new創建的對象和數組

          在函數(代碼塊)中定義一個變量時, java就在棧中為這個變量分配內存空間,當超過變量的作用域后, java會自動釋放掉為該變量所分配的內存空間;在堆中分配的內存由 java虛擬機的自動垃圾回收器來管理

          堆的優勢是可以動態分配內存大小,生存期也不必事先告訴編譯器,因為它是在運行時動態分配內存的。缺點就是要在運行時動態分配內存,存取速度較慢;

          棧的優勢是存取速度比堆要快,缺點是存在棧中的數據大小與生存期必須是確定的無靈活 性。

          java 堆分為三個區: New 、 Old 和 Permanent

          GC 有兩個線程:

          新創建的對象被分配到 New 區,當該區被填滿時會被 GC 輔助線程移到 Old 區,當 Old 區也填滿了會觸發 GC 主線程遍歷堆內存里的所有對象。 Old 區的大小等于 Xmx 減去 -Xmn

          java棧存放

          棧調整:參數有 +UseDefaultStackSize -Xss256K,表示每個線程可申請 256k的棧空間

          每個線程都有他自己的 Stack

          三、 JVM如何設置虛擬內存
          提示:在 JVM中如果 98%的時間是用于 GC且可用的 Heap size 不足 2%的時候將拋出此異常信息。

          提示: Heap Size 最大不要超過可用物理內存的 80%,一般的要將 -Xms和 -Xmx選項設置為相同,而 -Xmn為 1/4的 -Xmx值。

          提示: JVM初始分配的內存由 -Xms指定,默認是物理內存的 1/64; JVM最大分配的內存由 -Xmx指定,默認是物理內存的 1/4。

          默認空余堆內存小于 40%時, JVM就會增大堆直到 -Xmx的最大限制;空余堆內存大于 70%時, JVM會減少堆直到 -Xms的最小限制。因此服務器一般設置 -Xms、 -Xmx相等以避免在每次 GC 后調整堆的大小。

          提示:假設物理內存無限大的話, JVM內存的最大值跟操作系統有很大的關系。

          簡單的說就 32位處理器雖然可控內存空間有 4GB,但是具體的操作系統會給一個限制,

          這個限制一般是 2GB-3GB(一般來說 Windows系統下為 1.5G-2G, Linux系統下為 2G-3G), 而 64bit以上的處理器就不會有限制了

          提示:注意:如果 Xms超過了 Xmx值,或者堆最大值和非堆最大值的總和超過了物理內 存或者操作系統的最大限制都會引起服務器啟動不起來。

          提示:設置 NewSize、 MaxNewSize相等, “new”的大小最好不要大于 “old”的一半,原因是 old區如果不夠大會頻繁的觸發 “主 ” GC ,大大降低了性能

          JVM使用 -XX:PermSize設置非堆內存初始值,默認是物理內存的 1/64;

          由 XX:MaxPermSize設置最大非堆內存的大小,默認是物理內存的 1/4。

          解決方法:手動設置 Heap size

          修改 TOMCAT_HOME/bin/catalina.bat

          在“ echo “Using CATALINA_BASE: $CATALINA_BASE””上面加入以下行:

          1. JAVA_OPTS=”-server -Xms800m -Xmx800m -XX:MaxNewSize=256m”   

          四、性能檢查工具使用
          定位內存泄漏:

          JProfiler 工具主要用于檢查和跟蹤系統(限于 Java 開發的)的性能。 JProfiler 可以通過時時的監控系統的內存使用情況,隨時監視垃圾回收,線程運行狀況等手段,從而很好的監視 JVM 運行情況及其性能。


          1. 應用服務器內存長期不合理占用,內存經常處于高位占用,很難回收到低位;

          2. 應用服務器極為不穩定,幾乎每兩天重新啟動一次,有時甚至每天重新啟動一次;

          3. 應用服務器經常做 Full GC(Garbage Collection),而且時間很長,大約需要 30-40秒,應用服務器在做 Full GC的時候是不響應客戶的交易請求的,非常影響系統性能。

          因為開發環境和產品環境會有不同,導致該問題發生有時會在產品環境中發生, 通常可以使用工具跟蹤系統的內存使用情況,在有些個別情況下或許某個時刻確實 是使用了大量內存導致 out of memory,這時應繼續跟蹤看接下來是否會有下降,

          如果一直居高不下這肯定就因為程序的原因導致內存泄漏。

          五、不健壯代碼的特征及解決辦法
          1 、盡早釋放無用對象的引用。好的辦法是使用臨時變量的時候,讓引用變量在退出活動域后,自動設置為 null ,暗示垃圾收集器來收集該對象,防止發生內存泄露。

          對于仍然有指針指向的實例, jvm 就不會回收該資源 , 因為垃圾回收會將值為 null 的對象作為垃圾,提高 GC 回收機制效率;

          2 、我們的程序里不可避免大量使用字符串處理,避免使用 String ,應大量使用 StringBuffer ,每一個 String 對象都得獨立占用內存一塊區域;

          1. String str = “aaa”;   
          2.   
          3. String str2 = “bbb”;   
          4.   
          5. String str3 = str + str2;// 假如執行此次之后 str ,str2 以后再不被調用 , 那它就會被放在內存中等待 Java 的 gc 去回收 , 程序內過多的出現這樣的情況就會報上面的那個錯誤 , 建議在使用字符串時能使用 StringBuffer 就不要用 String, 這樣可以省不少開銷;   

          3 、盡量少用靜態變量,因為靜態變量是全局的, GC 不會回收的;

          4 、避免集中創建對象尤其是大對象, JVM 會突然需要大量內存,這時必然會觸發 GC 優化系統內存環境;顯示的聲明數組空間,而且申請數量還極大。

          這是一個案例想定供大家警戒:

          使用jspsmartUpload作文件上傳,現在運行過程中經常出現java.outofMemoryError的錯誤,用top命令看看進程使用情況,發現內存不足2M,花了很長時間,發現是jspsmartupload的問題。把jspsmartupload組件的源碼文件(class文件)反編譯成Java文件,如夢方醒:

          1. m_totalBytes = m_request.getContentLength();        
          2. m_binArray = new byte[m_totalBytes];      

          變量m_totalBytes表示用戶上傳的文件的總長度,這是一個很大的數。如果用這樣大的數去聲明一個byte數組,并給數組的每個元素分配內存空間,而且m_binArray數組不能馬上被釋放,JVM的垃圾回收確實有問題,導致的結果就是內存溢出。

          jspsmartUpload為什末要這樣作,有他的原因,根據RFC1867的http上傳標準,得到一個文件流,并不知道文件流的長度。設計者如果想文件的長度,只有操作servletinputstream一次才知道,因為任何流都不知道大小。只有知道文件長度了,才可以限制用戶上傳文件的長度。為了省去這個麻煩,jspsmartUpload設計者直接在內存中打開文件,判斷長度是否符合標準,符合就寫到服務器的硬盤。這樣產生內存溢出,這只是我的一個猜測而已。

          所以編程的時候,不要在內存中申請大的空間,因為web服務器的內存有限,并且盡可能的使用流操作,例如

          1. byte[] mFileBody = new byte[512];   
          2.          Blob vField= rs.getBlob("FileBody");   
          3.       InputStream instream=vField.getBinaryStream();   
          4.       FileOutputStream fos=new FileOutputStream(saveFilePath+CFILENAME);   
          5.          int b;   
          6.                       while( (b =instream.read(mFileBody)) != -1){   
          7.                         fos.write(mFileBody,0,b);   
          8.                          }   
          9.         fos.close();   
          10.       instream.close();  

          5 、盡量運用對象池技術以提高系統性能;生命周期長的對象擁有生命周期短的對象時容易引發內存泄漏,例如大集合對象擁有大數據量的業務對象的時候,可以考慮分塊進行處理,然后解決一塊釋放一塊的策略。

          6 、不要在經常調用的方法中創建對象,尤其是忌諱在循環中創建對象。可以適當的使用 hashtable , vector 創建一組對象容器,然后從容器中去取那些對象,而不用每次 new 之后又丟棄

          7 、一般都是發生在開啟大型文件或跟數據庫一次拿了太多的數據,造成 Out Of Memory Error 的狀況,這時就大概要計算一下數據量的最大值是多少,并且設定所需最小及最大的內存空間值。

          posted @ 2012-10-25 23:16 abin 閱讀(639) | 評論 (0)編輯 收藏

          在hibernate中,用hql語句查詢實體類,采用list方法的返回結果為一個List,該List中封裝的對象分為以下三種情況:
          1.查詢全部字段的情況下,如"from 實體類",list中封裝的對象為實體類本身,各屬性都將得到填充。
          2.只查詢一個字段,默認情況下,list中封裝的是Object對象。
          3.查詢兩個或兩個以上的字段,默認情況下,list中封裝的是Object[],長度與所查詢的字段數一致。

          對于后兩種情況,用標簽遍歷時不太方便,因為無法直接轉換成實體類的對象。比較簡單的解決方法是:

          の:在hql中使用select new 包名.類名(屬性1,屬性2……) from 實體類,同時在實體類中添加帶參的構造方法,參數的個數和順序與(屬性1,屬性2……) 保持一致,這樣我們得到的list中存放的依然是實體類的對象,所查詢到的屬性得到了填充,使用起來更為方便。

            の:hql查詢多表部分字段,select new 包名.表1實體類名(表1.屬性1,表2.屬性2……) from 表1實體類,表2實體類 where 表1.ID=表2.ID(即相關聯的字段),同時在要返回的表1實體類中添加表2的屬性和帶參的構造方法,參數的個數和順序與(表1.屬性1,表2.屬性 2……) 保持一致

          例如要查詢Problem 中的pid,score,title,totalAccept,totalSubmission,unSee

          public class Problem {  
              private int pid;  
              private int score;  
              private int timeLimit;  
              private int memoryLimit;  
              private int totalAccept;  
              private int totalSubmission;  
              private int unSee;  
              private String title;  
              private String description;  
              private String input;  
              private String output;  
                
              public Problem(int pid, int score,String title, int totalAccept, int totalSubmission,  
                       int unSee) {  
                  super();  
                  this.pid = pid;  
                  this.score = score;  
                  this.totalAccept = totalAccept;  
                  this.totalSubmission = totalSubmission;  
                  this.unSee = unSee;  
                  this.title = title;  
              }  
              //省略getter 和 setter   
          }  
          查詢語句如下
                Query query=session.createQuery("select new Problem(pid,score,title,totalAccept,totalSubmission,unSee) from Problem order by pid");  
                  //query.setFirstResult(firstResult); //分頁函數   
                  //query.setMaxResults(maxResutl);   
                
                  List<Problem> problems=query.list();//返回的還是Problem對象 









          關于hibernate的問題: 
          我現在有條 
          hql="select s.id,s.name,t.id,t.name from User s,Useraddress t where t.id=s.id" 

          這條sql里面的User和Useraddress是兩個實體類,現在組合查詢分別取出來兩個實體類里面的兩個字段,然后我想再建立一個實體類Result,里面定義這四個結果集里面的字段,能不能執行完這條hql,正好把這個結果集對應到實體類Result里面呢,Result這個實體類,沒寫映射文件Result.hbm.xml. 
          希望能幫下忙 

          2種做法 
          創建一個class temp 
          有屬性sid,name,tid,sname,tname 
          創建一個構造函數 
          public temp(sid,name,tid,sname,tname) 



          1.hql中 
          List<temp> 

          select new temp(s.id,s.name,t.id,t.name) from User s,Useraddress t where t.id=s.id 

          2.List 
          記錄的每一行是object[] 遍歷 
          object[0] ==s.id 
          object[1] ==s.name 
          object[2] ==t.id 
          object[3] ==t.name 

           



          感謝glamey兄弟的文章,正好解決了當前遇到的問題。原文鏈接如下:http://glamey.iteye.com/blog/721019
                  假設我們現在有一個DTO,其屬性包括兩張表的屬性,我們現在需要將sql語句查詢得到的內容轉為一個DTO對象,其解決方法如下:  

          String sql = "select u.userName as userName ,p.title as title ,p.addTime as addTime from user as u,post as p where u.id=p.userId"  
          Query q = factory.getCurrentSession().createSQLQuery(sql).setResultTransformer(Transformers.aliasToBean(PostVO.class));

                上面select中as后面的內容必須和PostVO中屬性名一致,這樣就可以返回一個針對PostVO的一個集合。 
                  其實大家可以看下hibernate這一部分的源碼就會發現,主要是使用了AliasToBeanResultTransformer這個類,通過sql的查詢,會返回數組,然后hibernate根據數據表的映射,自動幫我們來set對應的字段屬性,所以標紅的部分務必要跟VO中的屬性值一直,要不然會報錯的。 
                  如果需要的話,大家也可以重寫這個類。例如VOResultTransformer。然后在dao中更改成:  

          setResultTransformer(new VOResultTransformer(PostVO.class));

            另外,除了以上glamey的方法外,還有一種方法:  
          Query q = session.createQuery("select new com.hibernate.MsgInfo(m.id, m.cont, m.topic.title, m.topic.category.name) from Msg m");
          List<MsgInfo> list=q.list();

               其中,MsgInfo是DTO。值得注意的是,第二種方法中DTO必須提供帶參數的構造方法,并且HQL語句中屬性的位置要與構造方法中的位置一一對應。 
          posted @ 2012-10-25 14:32 abin 閱讀(21372) | 評論 (4)編輯 收藏

          package net.abin.lee.basic;

          public class Can implements Cloneable{
           private int id;
           private String address;
           public Can() {
           }
           public Can(int id, String address) {
            super();
            this.id = id;
            this.address = address;
           }
           public Object clone()throws CloneNotSupportedException{
            return super.clone();
           }
           public int hashCode(){
            final int prime=31;
            int result=1;
            result=prime*result+id;
            result=prime*result+((address==null?0:address.hashCode()));
            return result;
           }
           public int getId() {
            return id;
           }
           public void setId(int id) {
            this.id = id;
           }
           public String getAddress() {
            return address;
           }
           public void setAddress(String address) {
            this.address = address;
           }
           
          }










          package net.abin.lee.basic;

          import junit.framework.TestCase;

          public class UserTest extends TestCase{
           public void test1() throws CloneNotSupportedException{
            User user1=new User("12","abin",3);
            User user2=user1;
            User user3=(User)user1.clone();
            System.out.println("user1=user2 :"+(user1==user2));
            System.out.println("user1equalsuser2 :"+(user1.equals(user2)));
            
            System.out.println("user1=user3 :"+(user1==user3));
            System.out.println("user1equalsuser3 :"+(user1.equals(user3)));
            
           }
           @Override
           protected void runTest() throws Throwable {
            System.out.println("55");
            super.runTest();
           }
          }

          posted @ 2012-10-24 13:27 abin 閱讀(430) | 評論 (0)編輯 收藏

          僅列出標題
          共50頁: First 上一頁 23 24 25 26 27 28 29 30 31 下一頁 Last 
          主站蜘蛛池模板: 鹤壁市| 湛江市| 海口市| 青州市| 鸡东县| 综艺| 招远市| 泰州市| 通许县| 凤凰县| 庄浪县| 青冈县| 蕉岭县| 黄陵县| 大兴区| 承德县| 邢台市| 岑溪市| 平安县| 沙田区| 杂多县| 疏附县| 疏勒县| 吉首市| 汨罗市| 神农架林区| 八宿县| 临高县| 鄂托克旗| 苗栗市| 四会市| 且末县| 资兴市| 方山县| 丹寨县| 河间市| 洪泽县| 内乡县| 巧家县| 韩城市| 磴口县|