定時組件quartz系列<二>quartz的集羣原理

一、基本信息:html

     Quartz是一個開源的做業調度框架,它徹底由java寫成,並設計用於J2Se和J2EE應用中。它提供了巨大的靈活性而不犧牲簡單性。你可以用它 來爲執行一個做業而建立簡單的或複雜的調度。它有不少特徵,如:數據庫支持,集羣,插件,EJB做業預構建,JavaMail及其它,支持cron- like表達式等等。其中集羣配置通常比較複雜,那麼在Quartz中如何配置它的集羣特性呢?

2 Quartz的集羣配置:
     2.1 實現集羣的基本原理
          Quartz是經過藉助關係數據庫和JDBC做業存儲來實現集羣管理的。
         
     一、原理:     
          集羣經過故障切換和負載平衡的功能,能給調度器帶來高可用性和伸縮性。目前集羣只能工做在JDBC-JobStore(JobStore TX或者JobStoreCMT)方式下,從本質上來講,是使集羣上的每個節點經過共享同一個數據庫來工做的(Quartz經過啓動兩個維護線程來維護數據庫狀態實現集羣管理,一個是檢測節點狀態線程,一個是恢復任務線程)。
        負載平衡是自動完成的,集羣的每一個節點會盡快觸發任務。當一個觸發器的觸發時間到達時,第一個節點將會得到任務(經過鎖定),成爲執行任務的節點。
                故 障切換的發生是在當一個節點正在執行一個或者多個任務失敗的時候。當一個節點失敗了,其餘的節點會檢測到而且標 識在失敗節點上正在進行的數據庫中的任務。任何被標記爲可恢復(任務詳細信息的"requests recovery"屬性)的任務都會被其餘的節點從新執行。沒有標記可恢復的任務只會被釋放出來,將會在下次相關觸發器觸發時執行。
     二、集羣管理用到的表
          --任務詳細信息表
                         
    CREATE TABLE qrtz_job_details
    (
    JOB_NAME VARCHAR2(80) NOT NULL,
    JOB_GROUP VARCHAR2(80) NOT NULL,
    DESCRIPTION VARCHAR2(120) NULL,
    JOB_CLASS_NAME VARCHAR2(128) NOT NULL,
    IS_DURABLE VARCHAR2(1) NOT NULL,
    IS_VOLATILE VARCHAR2(1) NOT NULL,
    IS_STATEFUL VARCHAR2(1) NOT NULL,
    REQUESTS_RECOVERY VARCHAR2(1) NOT NULL, --可恢復標記
    JOB_DATA BLOB NULL,
    PRIMARY KEY (JOB_NAME,JOB_GROUP)
    );


          
--觸發器與任務關聯表

                         
     CREATE TABLE qrtz_fired_triggers
    (
    ENTRY_ID VARCHAR2(95) NOT NULL,
    TRIGGER_NAME VARCHAR2(80) NOT NULL,
    TRIGGER_GROUP VARCHAR2(80) NOT NULL,
    IS_VOLATILE VARCHAR2(1) NOT NULL,
    INSTANCE_NAME VARCHAR2(80) NOT NULL,
    FIRED_TIME NUMBER(13) NOT NULL,
    STATE VARCHAR2(16) NOT NULL,
    JOB_NAME VARCHAR2(80) NULL,
    JOB_GROUP VARCHAR2(80) NULL,
    IS_STATEFUL VARCHAR2(1) NULL,
    REQUESTS_RECOVERY VARCHAR2(1) NULL, --可恢復標記
    PRIMARY KEY (ENTRY_ID)
    );

                  --調度器狀態表

                         
     CREATE TABLE qrtz_scheduler_state
    (
    INSTANCE_NAME VARCHAR2(80) NOT NULL, --調度器實例ID
    LAST_CHECKIN_TIME NUMBER(13) NOT NULL, --上次檢查時間
    CHECKIN_INTERVAL NUMBER(13) NOT NULL, --檢查時間間隔
    RECOVERER VARCHAR2(80) NULL, --恢復調度器
    PRIMARY KEY (INSTANCE_NAME)
    );

          

     2.2 集羣配置
        通 過設置"org.quartz.jobStore.isClustered"屬性爲"true"來激活集羣特性。在集羣中的每個實例都必須有一 個惟一的"instance id" ("org.quartz.scheduler.instanceId" 屬性), 可是應該有相同的"scheduler instance name" ("org.quartz.scheduler.instanceName"),也就是說集羣中的每個實例都必須使用相同的 quartz.properties 配置文件。除了如下幾種例外,配置文件的內容其餘都必須相同:

 不一樣的線程池大小,
 不一樣的"org.quartz.scheduler.instanceId"屬性值(這個能夠很容易作到,設定爲"AUTO"便可)。
 注意: 永遠不要在不一樣的機器上運行集羣,除非他們的時鐘是使用某種形式的同步服務(守護)很是有規律的運行(時鐘必須在一分一秒內)來達到同步。還有: 永遠不要觸發一個非集羣的實例,若是其餘的實例正在同一個數據庫表上運行。你將使你的數據嚴重腐蝕,出現非預期行爲。
 示例及詳細配置說明,請參照附錄Quartz配置文件說明。java


3 附錄
          3.1 Quartz配置文件說明
               3.1.1 Quartz配置文件基本說明
               3.1.2 Quartz配置文件詳細說明
                    3.1.2.1  Scheduler主要屬性的配置
                        
    # Scheduler主要屬性的通常定義模式以下:
    #
    # org.quartz.scheduler.instanceName = SCHED_NAME
    # org.quartz.scheduler.instanceId = INSTANCE_ID
    # org.quartz.scheduler.threadName = THREAD_NAME
    # org.quartz.scheduler.rmi.export = false
    # org.quartz.scheduler.rmi.proxy = false
    # org.quartz.scheduler.rmi.registryHost = localhost
    # org.quartz.scheduler.rmi.registryPort = 1099
    # org.quartz.scheduler.rmi.createRegistry = never
    # org.quartz.scheduler.userTransactionURL = USER_TX_LOCATION
    # org.quartz.scheduler.wrapJobExecutionInUserTransaction = JOBS_IN_USER_TX
    # org.quartz.scheduler.idleWaitTime = IDLE_WAIT_TIME
    # org.quartz.scheduler.dbFailureRetryInterval = DB_FAILURE_RETRY_INTERVAL
    # org.quartz.scheduler.classLoadHelper.class = CLASS_LOAD_HELPER_CLASS
    # org.quartz.context.key.SOME_KEY = SOME_VALUE



                 3.1.2.2   線程池(ThreadPool)的配置

                        
    # 定製一個線程池的通常模式以下:
    #
    # org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
    # org.quartz.threadPool.threadCount = THREAD_COUNT
    # org.quartz.threadPool.threadPriority = THREAD_PRIO
    #
    # 簡單線程池(SimpleThreadPool)的選項參數:
    #
    # org.quartz.threadPool.makeThreadsDaemons = DAEMON_THREADS
    # org.quartz.threadPool.threadsInheritGroupOfInitializingThread = INHERIT_GRP
    # org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = INHERIT_LDR
    #
    # or
    #
    # org.quartz.threadPool.class = com.mycompany.goo.FooThreadPool
    # org.quartz.threadPool.somePropOfFooThreadPool = someValue
    #

          

                      3.1.2.3 任務存儲(JobStore)的配置
                        
    # 定義一個任務存儲的通常模式以下:
    #
    # org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
    # org.quartz.jobStore.misfireThreshold = MISFIRE_THRESHOLD
    #
    # or
    #
    # org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.<JobStoreClass>
    # JobStoreClass 是下面其中的一個:
    # - JobStoreTX 用於單機(standalone-Quartz)實現
    # - JobStoreCMT 用於基於應用服務器容器管理事務(appserver-based container-managed transaction )的Quartz 實現
    #
    # org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.<DriverDelegateClass>
    # DriverDelegateClass 是下面其中的一個:
    # - StdJDBCDelegate (用於許多 JDBC-compliant drivers)
    # - MSSQLDelegate (用於 Microsoft SQL Server drivers)
    # - PostgreSQLDelegate (用於 PostgreSQL drivers)
    # - WebLogicDelegate (用於 WebLogic drivers)
    # - oracle.OracleDelegate (用於 Oracle drivers)
    #
    # org.quartz.jobStore.useProperties = USE_PROPERTIES
    # org.quartz.jobStore.dataSource = DS_NAME
    # org.quartz.jobStore.tablePrefix = TABLE_PREFIX
    # org.quartz.jobStore.isClustered = IS_CLUSTERED
    # org.quartz.jobStore.selectWithLockSQL = LOCKING_SELECT_STATEMENT
    # org.quartz.jobStore.dontSetAutoCommitFalse = DONT_TURN_OFF_AUTO_COMMIT
    # org.quartz.jobStore.maxMisfiresToHandleAtATime = MAX_MISFIRE_HANDLE
    # org.quartz.jobStore.txIsolationLevelSerializable = SERIALIZABLE_ISOLATION
    #
    # 若是你使用JobStoreCMT,你還須要下面的參數:
    #
    # org.quartz.jobStore.nonManagedTXDataSource = NON_MANAGED_TX_DS_NAME
    #
    # 而且若是你使用JobStoreCMT,下面的參數是可選的:
    #
    # org.quartz.jobStore.dontSetNonManagedTXConnectionAutoCommitFalse = DONT_TURN_OFF_AUTO_COMMIT
    # org.quartz.jobStore.txIsolationLevelReadCommitted = READ_COMMITTED_ISOLATION
    #
    #
    # 或者,使用一個用戶自定義JobStore實現:
    #
    # org.quartz.jobStore.class = com.mycompany.goo.FooJobStore
    # org.quartz.jobStore.somePropOfFooJobStore = someValue
    #
    #

   


                     3.1.2.4 數據源的配置  
                        
    # (只有當使用JDBCJobStore時須要, 或者一個插件須要JDBC)
    # -- 若是你的Scheduler很是忙碌,好比在必定的線程池內執行相同數目的任務,那麼你應讓數據源的鏈接數等於線程數 + 1
    #
    # 數據源定義的通常模式以下:
    #
    # org.quartz.dataSource.NAME.driver = DRIVER_CLASS_NAME
    # org.quartz.dataSource.NAME.URL = DB_URL
    # org.quartz.dataSource.NAME.user = DB_USER
    # org.quartz.dataSource.NAME.password = DB_PASSWORD
    # org.quartz.dataSource.NAME.maxConnections = DB_POOL_SIZE
    # org.quartz.dataSource.NAME.validationQuery= VALIDATION_QUERY
    #
    # or
    #
    # org.quartz.dataSource.NAME.jndiURL = DB_JNDI_URL
    #
    # or
    # org.quartz.dataSource.NAME.jndiURL = DB_JNDI_URL
    # org.quartz.dataSource.NAME.jndiAlwaysLookup = DB_JNDI_ALWAYS_LOOKUP
    # org.quartz.dataSource.NAME.java.naming.factory.initial = JNDI_CTXT_FACTORY
    # org.quartz.dataSource.NAME.java.naming.provider.url = JNDI_PROVIDER_URL
    # org.quartz.dataSource.NAME.java.naming.security.principal = JNDI_PRINCIPAL
    # org.quartz.dataSource.NAME.java.naming.security.credentials = JNDI_CREDENTIALS
    #
    #

      上面顯示了兩種數據源定義方式:一個數據源能夠用給定的數據庫鏈接信息建立,也能夠是利用應用服務器管理生成的JNDI數據源的邏輯映射。 
 


            

                    3.1.2.5 Scheduler插件的配置
                        
    # SchedulerPlugin定義的通常模式以下:
    #
    # org.quartz.plugin.NAME.class = PLUGIN_CLASS_NAME
    #
    # 若是這個插件類有一些屬性值須要經過"setter"方法設定, 名稱和值的屬性定義以下:
    #
    # org.quartz.plugin.NAME.propName = propValue
    #
    # ..."propName" 在插件類中會有一個"setPropName"方法.可是隻支持原始數據類型(包括 Strings)。
    #

      配置插件的簡單示例:    

                        
    org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
    org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}
    org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
    
    org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
    org.quartz.plugin.jobInitializer.fileName = data/my_job_data.xml
    org.quartz.plugin.jobInitializer.overWriteExistingJobs = false
    org.quartz.plugin.jobInitializer.failOnFileNotFound = true
    
    org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
    org.quartz.plugin.shutdownhook.cleanShutdown = true

      3.1.3 示例

                        
[html] view plain copy 在CODE上查看代碼片派生到個人代碼片
  1. #============================================================  
  2.    # Configure Main Scheduler Properties  
  3.    #===========================================================  
  4.      
  5.    org.quartz.scheduler.instanceName = MyClusteredScheduler  
  6.    org.quartz.scheduler.instanceId = AUTO  
  7.      
  8.    #===========================================================  
  9.    # Configure ThreadPool  
  10.    #===========================================================  
  11.      
  12.    org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool  
  13.    org.quartz.threadPool.threadCount = 25  
  14.    org.quartz.threadPool.threadPriority = 5  
  15.      
  16.    #===========================================================  
  17.    # Configure JobStore  
  18.    #===========================================================  
  19.      
  20.    org.quartz.jobStore.misfireThreshold = 60000  
  21.      
  22.    org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX  
  23.    org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate  
  24.    org.quartz.jobStore.useProperties = false  
  25.    org.quartz.jobStore.dataSource = myDS  
  26.    org.quartz.jobStore.tablePrefix = QRTZ_  
  27.      
  28.    org.quartz.jobStore.isClustered = true  
  29.    org.quartz.jobStore.clusterCheckinInterval = 20000  
  30.      
  31.    #===========================================================  
  32.    # Configure Datasources  
  33.    #===========================================================  
  34.      
  35.    org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver  
  36.    org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@cluster:1521:dev  
  37.    org.quartz.dataSource.myDS.user = quartz  
  38.    org.quartz.dataSource.myDS.password = quartz  
  39.    org.quartz.dataSource.myDS.maxConnections = 5  
  40.    org.quartz.dataSource.myDS.validationQuery=select 0 from dual  



   
附件:建立數據庫:
    1. DROP TABLE IF EXISTS QRTZ_JOB_LISTENERS;  
    2. DROP TABLE IF EXISTS QRTZ_TRIGGER_LISTENERS;  
    3. DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;  
    4. DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;  
    5. DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;  
    6. DROP TABLE IF EXISTS QRTZ_LOCKS;  
    7. DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;  
    8. DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;  
    9. DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;  
    10. DROP TABLE IF EXISTS QRTZ_TRIGGERS;  
    11. DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;  
    12. DROP TABLE IF EXISTS QRTZ_CALENDARS;  
    13.   
    14.   
    15. CREATE TABLE QRTZ_JOB_DETAILS  
    16. (  
    17. JOB_NAME VARCHAR(200) NOT NULL,  
    18. JOB_GROUP VARCHAR(200) NOT NULL,  
    19. DESCRIPTION VARCHAR(250) NULL,  
    20. JOB_CLASS_NAME VARCHAR(250) NOT NULL,  
    21. IS_DURABLE VARCHAR(1) NOT NULL,  
    22. IS_VOLATILE VARCHAR(1) NOT NULL,  
    23. IS_STATEFUL VARCHAR(1) NOT NULL,  
    24. REQUESTS_RECOVERY VARCHAR(1) NOT NULL,  
    25. JOB_DATA BLOB NULL,  
    26. PRIMARY KEY (JOB_NAME,JOB_GROUP)  
    27. );  
    28.   
    29. CREATE TABLE QRTZ_JOB_LISTENERS  
    30. (  
    31. JOB_NAME VARCHAR(200) NOT NULL,  
    32. JOB_GROUP VARCHAR(200) NOT NULL,  
    33. JOB_LISTENER VARCHAR(200) NOT NULL,  
    34. PRIMARY KEY (JOB_NAME,JOB_GROUP,JOB_LISTENER),  
    35. FOREIGN KEY (JOB_NAME,JOB_GROUP)  
    36. REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)  
    37. );  
    38.   
    39. CREATE TABLE QRTZ_TRIGGERS  
    40. (  
    41. TRIGGER_NAME VARCHAR(200) NOT NULL,  
    42. TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    43. JOB_NAME VARCHAR(200) NOT NULL,  
    44. JOB_GROUP VARCHAR(200) NOT NULL,  
    45. IS_VOLATILE VARCHAR(1) NOT NULL,  
    46. DESCRIPTION VARCHAR(250) NULL,  
    47. NEXT_FIRE_TIME BIGINT(13) NULL,  
    48. PREV_FIRE_TIME BIGINT(13) NULL,  
    49. PRIORITY INTEGER NULL,  
    50. TRIGGER_STATE VARCHAR(16) NOT NULL,  
    51. TRIGGER_TYPE VARCHAR(8) NOT NULL,  
    52. START_TIME BIGINT(13) NOT NULL,  
    53. END_TIME BIGINT(13) NULL,  
    54. CALENDAR_NAME VARCHAR(200) NULL,  
    55. MISFIRE_INSTR SMALLINT(2) NULL,  
    56. JOB_DATA BLOB NULL,  
    57. PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),  
    58. FOREIGN KEY (JOB_NAME,JOB_GROUP)  
    59. REFERENCES QRTZ_JOB_DETAILS(JOB_NAME,JOB_GROUP)  
    60. );  
    61.   
    62. CREATE TABLE QRTZ_SIMPLE_TRIGGERS  
    63. (  
    64. TRIGGER_NAME VARCHAR(200) NOT NULL,  
    65. TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    66. REPEAT_COUNT BIGINT(7) NOT NULL,  
    67. REPEAT_INTERVAL BIGINT(12) NOT NULL,  
    68. TIMES_TRIGGERED BIGINT(7) NOT NULL,  
    69. PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),  
    70. FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)  
    71. REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)  
    72. );  
    73.   
    74. CREATE TABLE QRTZ_CRON_TRIGGERS  
    75. (  
    76. TRIGGER_NAME VARCHAR(200) NOT NULL,  
    77. TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    78. CRON_EXPRESSION VARCHAR(200) NOT NULL,  
    79. TIME_ZONE_ID VARCHAR(80),  
    80. PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),  
    81. FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)  
    82. REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)  
    83. );  
    84.   
    85. CREATE TABLE QRTZ_BLOB_TRIGGERS  
    86. (  
    87. TRIGGER_NAME VARCHAR(200) NOT NULL,  
    88. TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    89. BLOB_DATA BLOB NULL,  
    90. PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP),  
    91. FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)  
    92. REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)  
    93. );  
    94.   
    95. CREATE TABLE QRTZ_TRIGGER_LISTENERS  
    96. (  
    97. TRIGGER_NAME VARCHAR(200) NOT NULL,  
    98. TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    99. TRIGGER_LISTENER VARCHAR(200) NOT NULL,  
    100. PRIMARY KEY (TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_LISTENER),  
    101. FOREIGN KEY (TRIGGER_NAME,TRIGGER_GROUP)  
    102. REFERENCES QRTZ_TRIGGERS(TRIGGER_NAME,TRIGGER_GROUP)  
    103. );  
    104.   
    105.   
    106. CREATE TABLE QRTZ_CALENDARS  
    107. (  
    108. CALENDAR_NAME VARCHAR(200) NOT NULL,  
    109. CALENDAR BLOB NOT NULL,  
    110. PRIMARY KEY (CALENDAR_NAME)  
    111. );  
    112.   
    113.   
    114.   
    115. CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS  
    116. (  
    117. TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    118. PRIMARY KEY (TRIGGER_GROUP)  
    119. );  
    120.   
    121. CREATE TABLE QRTZ_FIRED_TRIGGERS  
    122. (  
    123. ENTRY_ID VARCHAR(95) NOT NULL,  
    124. TRIGGER_NAME VARCHAR(200) NOT NULL,  
    125. TRIGGER_GROUP VARCHAR(200) NOT NULL,  
    126. IS_VOLATILE VARCHAR(1) NOT NULL,  
    127. INSTANCE_NAME VARCHAR(200) NOT NULL,  
    128. FIRED_TIME BIGINT(13) NOT NULL,  
    129. PRIORITY INTEGER NOT NULL,  
    130. STATE VARCHAR(16) NOT NULL,  
    131. JOB_NAME VARCHAR(200) NULL,  
    132. JOB_GROUP VARCHAR(200) NULL,  
    133. IS_STATEFUL VARCHAR(1) NULL,  
    134. REQUESTS_RECOVERY VARCHAR(1) NULL,  
    135. PRIMARY KEY (ENTRY_ID)  
    136. );  
    137.   
    138. CREATE TABLE QRTZ_SCHEDULER_STATE  
    139. (  
    140. INSTANCE_NAME VARCHAR(200) NOT NULL,  
    141. LAST_CHECKIN_TIME BIGINT(13) NOT NULL,  
    142. CHECKIN_INTERVAL BIGINT(13) NOT NULL,  
    143. PRIMARY KEY (INSTANCE_NAME)  
    144. );  
    145.   
    146. CREATE TABLE QRTZ_LOCKS  
    147. (  
    148. LOCK_NAME VARCHAR(40) NOT NULL,  
    149. PRIMARY KEY (LOCK_NAME)  
    150. );  
    151.   
    152.   
    153. INSERT INTO QRTZ_LOCKS values('TRIGGER_ACCESS');  
    154. INSERT INTO QRTZ_LOCKS values('JOB_ACCESS');  
    155. INSERT INTO QRTZ_LOCKS values('CALENDAR_ACCESS');  
    156. INSERT INTO QRTZ_LOCKS values('STATE_ACCESS');  
    157. INSERT INTO QRTZ_LOCKS values('MISFIRE_ACCESS');  
    158.   
    159.   
    160. commit;  
相關文章
相關標籤/搜索