この章では、2つ目のスタンドアロンTimesTenデータベースおよびアクティブ・スタンバイ・ペアを作成し、第3章「キャッシュ・インフラストラクチャの設定」で作成したキャッシュ・グリッドにこれらのメンバーをアタッチする場合のタスクについて説明します。内容は次のとおりです。
次に、ttGridキャッシュ・グリッドのメンバーになる2つ目のスタンドアロンTimesTenデータベースのcachealone2 DSNの定義を示します。
[cachealone2] DataStore=/users/OracleCache/alone2 PermSize=64 OracleNetServiceName=orcl DatabaseCharacterSet=WE8ISO8859P1
ttIsqlユーティリティを開始して、cachealone2 DSNにインスタンス管理者として接続し、データベースを作成します。次に、キャッシュ・マネージャ・ユーザーcacheuserを作成します。この例では、このユーザーの名前はOracleキャッシュ管理ユーザーと同じです。次に、キャッシュ表ユーザーorattを作成します。このユーザーの名前は、TimesTenデータベースにキャッシュされるOracle表を所有するOracleスキーマ・ユーザーと同じです。
% ttIsql cachealone2 Command> CREATE USER cacheuser IDENTIFIED BY timesten; Command> CREATE USER oratt IDENTIFIED BY timesten;
インスタンス管理者としてttIsqlユーティリティを使用して、例3-8に示されている処理を実行するために必要な権限をキャッシュ・マネージャ・ユーザーcacheuserに付与します。
Command> GRANT CREATE SESSION, CACHE_MANAGER, CREATE ANY TABLE TO cacheuser; Command> exit
ttIsqlユーティリティを起動して、cachealone2 DSNにキャッシュ・マネージャ・ユーザーとして接続します。ttCacheUidPwdSet組込みプロシージャをコールして、キャッシュ管理ユーザーの名前およびパスワードを設定します。
% ttIsql "DSN=cachealone2;UID=cacheuser;PWD=timesten;OraclePWD=oracle"
Command> call ttCacheUidPwdSet('cacheuser','oracle');
キャッシュ・マネージャ・ユーザーとしてttGridNameSet組込みプロシージャをコールすることによって、2つ目のスタンドアロン・データベースをttGridキャッシュ・グリッドに関連付けます。
Command> call ttGridNameSet('ttGrid');
ttGridキャッシュ・グリッドは、最初のスタンドアロンTimesTenデータベースから作成されました。グリッドはすでに存在するため、再度作成する必要はありません。
必要に応じて、「TimesTenデータベースとOracle Database間での接続テスト」に示した手順を使用して、2つ目のスタンドアロンTimesTenデータベースとOracle Database間の接続性をテストできます。
キャッシュ・マネージャ・ユーザーとしてttCacheStart組込みプロシージャをコールすることによって、2つ目のスタンドアロン・データベースでキャッシュ・エージェントを起動します。
Command> call ttCacheStart;
次に、キャッシュ・マネージャ・ユーザーとしてデータベースにキャッシュ・グループを作成します。たとえば、次の文では、oratt.subscriber表をキャッシュする動的AWTグローバル・キャッシュ・グループsubscriber_accountsが作成されます。
CREATE DYNAMIC ASYNCHRONOUS WRITETHROUGH GLOBAL CACHE GROUP subscriber_accounts FROM oratt.subscriber (subscriberid NUMBER(10) NOT NULL PRIMARY KEY, name VARCHAR2(100) NOT NULL, minutes_balance NUMBER(5) NOT NULL, last_call_duration NUMBER(4) NOT NULL)
キャッシュされたOracle表oratt.subscriberの定義の詳細は、「グローバル・キャッシュ・グループ」を参照してください。
AWTキャッシュ・グループが作成されている場合は、キャッシュ・マネージャ・ユーザーとしてttRepStart組込みプロシージャをコールすることによって、TimesTenデータベースでレプリケーション・エージェントを起動します。
Command> call ttRepStart;
グローバル・キャッシュ・グループが作成されている場合、グローバル・キャッシュ・グループのキャッシュ表を更新するには、関連付けられているキャッシュ・グリッドにデータベースをアタッチする必要があります。データベースをグリッドにアタッチすると、データベースをグリッド・メンバーにすることができます。その結果、グリッド内のデータベース間で、グローバル・キャッシュ・グループのキャッシュ表内にあるキャッシュ・インスタンスの一貫性を保持できます。
関連付けられているttGridキャッシュ・グリッドに2つ目のスタンドアロン・データベースをアタッチするには、キャッシュ・マネージャ・ユーザーとしてttGridAttach組込みプロシージャをコールします。スタンドアロンのTimesTenデータベースのノード番号は1です。
次の例で、alone2はグリッド・メンバーを一意に識別するために使用される名前を、sys2は2つ目のスタンドアロン・データベースが存在するTimesTenシステムのホスト名を、5002は2つ目のスタンドアロン・データベースのキャッシュ・エージェント・プロセスのTCP/IPポートを示しています。
Command> call ttGridAttach(1,'alone2','sys2',5002); Command> exit
高可用性を実現するために、読取り専用キャッシュ・グループまたはAWTキャッシュ・グループのキャッシュ表に対してアクティブ・スタンバイ・ペアのレプリケーション・スキームを構成します。
これらのキャッシュ・グループ・タイプのいずれかからキャッシュ表をレプリケートするアクティブ・スタンバイ・ペアを使用すると、フェイルオーバーおよびリカバリの一部として、データ損失の可能性を最小限に抑えて、TimesTenデータベースのロールを自動的に変更できます。キャッシュ・グループ自体は、Oracle Databaseの停止からのリジリエンスを提供するため、システムの可用性がさらに強化されます。 詳細は、『Oracle TimesTen In-Memory Database TimesTen to TimesTen開発者および管理者ガイド』のキャッシュ・グループを含むアクティブ・スタンバイ・ペアの管理に関する説明を参照してください。
アクティブ・スタンバイ・ペアのレプリケーション・スキームを構成すると、TimesTenデータベースの高可用性を実現できます。 グリッド・メンバーを複数配置すると、TimesTenキャッシュ・グリッドの高可用性を実現できます。 Oracle Real Application Clusters(RAC)を構成すると、Oracle Databaseの高可用性を実現できます。 Oracle RAC環境でOracle In-Memory Database Cacheを使用する方法の詳細は、「RAC環境でのOracle In-Memory Database Cacheの使用」を参照してください。
Oracle表をキャッシュするTimesTenデータベースに対してアクティブ・スタンバイ・ペアを構成するには、次のタスクを実行します。
次に、ttGridキャッシュ・グリッドのメンバーになるアクティブ・スタンバイ・ペアのアクティブ・マスター・データベースのcacheactive DSNの定義を示します。
[cacheactive] DataStore=/users/OracleCache/cacheact PermSize=64 OracleNetServiceName=orcl DatabaseCharacterSet=WE8ISO8859P1
ttIsqlユーティリティを開始して、cacheactive DSNにインスタンス管理者として接続し、データベースを作成します。次に、キャッシュ・マネージャ・ユーザーcacheuserを作成します。この例では、このユーザーの名前はOracleキャッシュ管理ユーザーと同じです。次に、キャッシュ表ユーザーorattを作成します。このユーザーの名前は、TimesTenデータベースにキャッシュされるOracle表を所有するOracleスキーマ・ユーザーと同じです。
% ttIsql cacheactive Command> CREATE USER cacheuser IDENTIFIED BY timesten; Command> CREATE USER oratt IDENTIFIED BY timesten;
インスタンス管理者としてttIsqlユーティリティを使用して、例3-8に示されている処理を実行し、ADMIN権限を必要とするアクティブ・スタンバイ・ペアのレプリケーション・スキームを作成するために必要な権限をキャッシュ・マネージャ・ユーザーcacheuserに付与します。
Command> GRANT CREATE SESSION, CACHE_MANAGER,
> CREATE ANY TABLE, ADMIN TO cacheuser;
Command> exit
ttIsqlユーティリティを起動して、cacheactive DSNにキャッシュ・マネージャ・ユーザーとして接続します。ttCacheUidPwdSet組込みプロシージャをコールして、キャッシュ管理ユーザーの名前およびパスワードを設定します。
% ttIsql "DSN=cacheactive;UID=cacheuser;PWD=timesten;OraclePWD=oracle"
Command> call ttCacheUidPwdSet('cacheuser','oracle');
キャッシュ・マネージャ・ユーザーとしてttGridNameSet組込みプロシージャをコールすることによって、アクティブ・マスター・データベースをttGridキャッシュ・グリッドに関連付けます。
Command> call ttGridNameSet('ttGrid');
ttGridキャッシュ・グリッドは、最初のスタンドアロンTimesTenデータベースから作成されました。グリッドはすでに存在するため、再度作成する必要はありません。
必要に応じて、「TimesTenデータベースとOracle Database間での接続テスト」に示した手順を使用して、アクティブ・マスター・データベースとOracle Database間の接続性をテストできます。
キャッシュ・マネージャ・ユーザーとしてttCacheStart組込みプロシージャをコールすることによって、アクティブ・マスター・データベースでキャッシュ・エージェントを起動します。
Command> call ttCacheStart;
次に、キャッシュ・マネージャ・ユーザーとしてデータベースにキャッシュ・グループを作成します。たとえば、次の文では、oratt.subscriber表をキャッシュする動的AWTグローバル・キャッシュ・グループsubscriber_accountsが作成されます。
CREATE DYNAMIC ASYNCHRONOUS WRITETHROUGH GLOBAL CACHE GROUP subscriber_accounts FROM oratt.subscriber (subscriberid NUMBER(10) NOT NULL PRIMARY KEY, name VARCHAR2(100) NOT NULL, minutes_balance NUMBER(5) NOT NULL, last_call_duration NUMBER(4) NOT NULL)
キャッシュされたOracle表oratt.subscriberの定義の詳細は、「グローバル・キャッシュ・グループ」を参照してください。
キャッシュ・マネージャ・ユーザーとして、CREATE ACTIVE STANDBY PAIR文を使用して、アクティブ・マスター・データベースにアクティブ・スタンバイ・ペアのレプリケーション・スキームを作成します。
次の例では、cacheact、cachestandおよびsubscrはそれぞれ、アクティブ・マスター・データベース、スタンバイ・マスター・データベースおよび読取り専用サブスクライバ・データベースのチェックポイント・ファイルおよびトランザクション・ログ・ファイルのファイル名接頭辞です。また、sys3、sys4およびsys5はそれぞれ、アクティブ・マスター・データベース、スタンバイ・マスター・データベースおよび読取り専用サブスクライバ・データベースが存在するTimesTenシステムのホスト名です。
Command> CREATE ACTIVE STANDBY PAIR cacheact ON "sys3", cachestand ON "sys4" > SUBSCRIBER subscr ON "sys5";
キャッシュ・マネージャ・ユーザーとしてttRepStart組込みプロシージャをコールすることによって、アクティブ・マスター・データベースでレプリケーション・エージェントを起動します。 次に、ttRepStateSet組込みプロシージャをコールすることによって、データベースをアクティブ・マスターとして宣言します。
Command> call ttRepStart;
Command> call ttRepStateSet('active');
グローバル・キャッシュ・グループが作成されている場合、グローバル・キャッシュ・グループのキャッシュ表を更新するには、関連付けられているキャッシュ・グリッドにデータベースをアタッチする必要があります。データベースをグリッドにアタッチすると、データベースをグリッド・メンバーにすることができます。その結果、グリッド内のデータベース間で、グローバル・キャッシュ・グループのキャッシュ表内にあるキャッシュ・インスタンスの一貫性を保持できます。
関連付けられているttGridキャッシュ・グリッドにアクティブ・マスター・データベースをアタッチするには、キャッシュ・マネージャ・ユーザーとしてttGridAttach組込みプロシージャをコールします。 アクティブ・マスター・データベースのノード番号は1です。
例で使用される各要素の意味は、次のとおりです。
cacheactは、アクティブ・マスター・データベースのグリッド・ノードを一意に識別するために使用される名前です。
cachestandは、スタンバイ・マスター・データベースのグリッド・ノードを一意に識別するために使用される名前です。
sys3は、アクティブ・マスター・データベースが存在するTimesTenシステムのホスト名です。
sys4は、スタンバイ・マスター・データベースが存在するTimesTenシステムのホスト名です。
5003は、アクティブ・マスター・データベースのキャッシュ・エージェント・プロセス用のTCP/IPポートです。
5004は、スタンバイ・マスター・データベースのキャッシュ・エージェント・プロセス用のTCP/IPポートです。
Command> call ttGridAttach(1,'cacheact','sys3',5003,'cachestand','sys4',5004); Command> exit
次に、ttGridキャッシュ・グリッドのメンバーになるアクティブ・スタンバイ・ペアのスタンバイ・マスター・データベースのcachestandby DSNの定義を示します。
[cachestandby] DataStore=/users/OracleCache/cachestand PermSize=64 OracleNetServiceName=orcl DatabaseCharacterSet=WE8ISO8859P1
インスタンス管理者として、スタンバイ・マスター・データベースのシステムからttRepAdmin -duplicateユーティリティ・コマンドを実行することによって、スタンバイ・マスター・データベースをアクティブ・マスター・データベースの複製として作成します。 アクティブ・マスター・データベースのインスタンスとスタンバイ・マスター・データベースのインスタンスのインスタンス管理者ユーザー名は同じである必要があります。
スタンバイ・マスター・データベースにはOracle Databaseとの接続性があるため、アクティブ・マスター・データベースのキャッシュ表がスタンバイ・マスター・データベースのキャッシュ表として複製されるように、-keepCGオプションを使用します。
例で使用される各要素の意味は、次のとおりです。
-fromオプションには、アクティブ・マスター・データベースのチェックポイント・ファイルおよびトランザクション・ログ・ファイルのファイル名接頭辞を指定します。
-hostオプションには、アクティブ・マスター・データベースが存在するTimesTenシステムのホスト名を指定します。
-uidオプションおよび-pwdオプションには、アクティブ・マスター・データベースに定義され、ADMIN権限が付与されているTimesTen内部ユーザーのユーザー名およびパスワードを指定します。
-cacheuidオプションおよび-cachepwdオプションには、Oracleキャッシュ管理ユーザーの名前およびパスワードを指定します。
cachestandbyは、スタンバイ・マスター・データベースのDSNです。
% ttRepAdmin -duplicate -from cacheact -host "sys3" -uid cacheuser -pwd timesten -cacheuid cacheuser -cachepwd oracle -keepCG cachestandby
ttIsqlユーティリティを起動して、cachestandby DSNにキャッシュ・マネージャ・ユーザーとして接続します。ttCacheUidPwdSet組込みプロシージャをコールして、キャッシュ管理ユーザーの名前およびパスワードを設定します。
% ttIsql "DSN=cachestandby;UID=cacheuser;PWD=timesten;OraclePWD=oracle"
Command> call ttCacheUidPwdSet('cacheuser','oracle');
ttGridキャッシュ・グリッドは、最初のスタンドアロンTimesTenデータベースから作成されました。グリッドはすでに存在するため、再度作成する必要はありません。
ttRepAdmin -duplicate -keepCGユーティリティ・コマンドによってスタンバイ・マスター・データベースがttGridキャッシュ・グリッドに関連付けられるため、この関連付けを明示的に行う必要はありません。
必要に応じて、「TimesTenデータベースとOracle Database間での接続テスト」に示した手順を使用して、スタンバイ・マスター・データベースとOracle Database間の接続性をテストできます。
キャッシュ・マネージャ・ユーザーとしてttCacheStart組込みプロシージャをコールすることによって、スタンバイ・マスター・データベースでキャッシュ・エージェントを起動します。
Command> call ttCacheStart;
キャッシュ・マネージャ・ユーザーとしてttRepStart組込みプロシージャをコールすることによって、スタンバイ・マスター・データベースでレプリケーション・エージェントを起動します。
Command> call ttRepStart;
グローバル・キャッシュ・グループが作成されている場合、グローバル・キャッシュ・グループのキャッシュ表を更新するには、関連付けられているキャッシュ・グリッドにデータベースをアタッチする必要があります。データベースをグリッドにアタッチすると、データベースをグリッド・メンバーにすることができます。その結果、グリッド内のデータベース間で、グローバル・キャッシュ・グループのキャッシュ表内にあるキャッシュ・インスタンスの一貫性を保持できます。
関連付けられているttGridキャッシュ・グリッドにスタンバイ・マスター・データベースをアタッチするには、キャッシュ・マネージャ・ユーザーとしてttGridAttach組込みプロシージャをコールします。 スタンバイ・マスター・データベースのノード番号は2です。 アクティブ・マスター・データベースおよびスタンバイ・マスター・データベースのキャッシュ・エージェントには、アクティブ・マスター・データベースの構成時に指定したTCP/IPポートと同じTCP/IPポートを使用します。
例で使用される各要素の意味は、次のとおりです。
cacheactは、アクティブ・マスター・データベースのグリッド・ノードを一意に識別するために使用される名前です。
cachestandは、スタンバイ・マスター・データベースのグリッド・ノードを一意に識別するために使用される名前です。
sys3は、アクティブ・マスター・データベースが存在するTimesTenシステムのホスト名です。
sys4は、スタンバイ・マスター・データベースが存在するTimesTenシステムのホスト名です。
5003は、アクティブ・マスター・データベースのキャッシュ・エージェント・プロセス用のTCP/IPポートです。
5004は、スタンバイ・マスター・データベースのキャッシュ・エージェント・プロセス用のTCP/IPポートです。
Command> call ttGridAttach(2,'cacheact','sys3',5003,'cachestand','sys4',5004); Command> exit
次に、アクティブ・スタンバイ・ペアの読取り専用サブスクライバ・データベースのrosubscriber DSNの定義を示します。
[rosubscriber] DataStore=/users/OracleCache/subscr PermSize=64 DatabaseCharacterSet=WE8ISO8859P1
インスタンス管理者として、読取り専用サブスクライバ・データベース・システムからttRepAdmin -duplicateユーティリティ・コマンドを実行することによって、読取り専用サブスクライバ・データベースをスタンバイ・マスター・データベースの複製として作成します。 スタンバイ・マスター・データベースのインスタンスと読取り専用サブスクライバ・データベースのインスタンスのインスタンス管理者ユーザー名は同じである必要があります。
読取り専用サブスクライバ・データベースにはOracle Databaseとの接続性がないため、スタンバイ・マスター・データベースのキャッシュ表が読取り専用サブスクライバ・データベースの通常の表として複製されるように、-noKeepCGオプションを使用します。 この結果、読取り専用サブスクライバ・データベースはキャッシュ・グリッドに関連付けられなくなります。
例で使用される各要素の意味は、次のとおりです。
-fromオプションには、スタンバイ・マスター・データベースのチェックポイント・ファイルおよびトランザクション・ログ・ファイルのファイル名接頭辞を指定します。
-hostオプションには、スタンバイ・マスター・データベースが存在するTimesTenシステムのホスト名を指定します。
-uidオプションおよび-pwdオプションには、スタンバイ・マスター・データベースに定義され、ADMIN権限が付与されているTimesTen内部ユーザーのユーザー名およびパスワードを指定します。
rosubscriberは、読取り専用サブスクライバ・データベースのDSNです。
% ttRepAdmin -duplicate -from cachestand -host "sys4" -uid cacheuser -pwd timesten -noKeepCG rosubscriber
キャッシュ・マネージャ・ユーザーとしてttRepStart組込みプロシージャをコールすることによって、読取り専用サブスクライバ・データベースでレプリケーション・エージェントを起動します。
% ttIsql "DSN=rosubscriber;UID=cacheuser;PWD=timesten" Command> call ttRepStart; Command> exit
キャッシュされたOracle表oratt.subscriberの定義の詳細は、「グローバル・キャッシュ・グループ」を参照してください。
キャッシュされたOracle表oratt.subscriberのデータは、次のとおりです。
SUBSCRIBERID NAME MINUTES_BALANCE LAST_CALL_DURATION
------------ ---------------- --------------- ------------------
1001 Jane Anderson 75 15
1004 Robert Phillips 60 20
1005 William Ackerman 40 10
1009 Sandy Little 90 30
グローバル・キャッシュ・グループsubscriber_accountsのTimesTenキャッシュ表oratt.subscriberは、5つすべてのTimesTenデータベース(cachealone1、cachealone2、cacheactive、cachestandby、rosubscriber)で最初は空になっています。
Command> SELECT * FROM oratt.subscriber; 0 rows found.
TimesTenデータベースcachealone1で次のSELECT文を発行して、キャッシュされたOracle表からTimesTenキャッシュ表に1つのキャッシュ・インスタンスを動的にロードします。
Command> SELECT * FROM oratt.subscriber WHERE subscriberid = 1004; < 1004, Robert Phillips, 60, 20 >
この結果、スタンドアロン・データベース・グリッド・メンバーcachealone1は、サブスクライバIDが1004のキャッシュ・インスタンスの所有権を持ちます。このキャッシュ・インスタンスは、他のいずれのグリッド・メンバーにも存在しません。
次に、TimesTenデータベースcachealone2で次のSELECT文を発行して、キャッシュされたOracle表からTimesTenキャッシュ表にキャッシュ・インスタンスを1つ動的にロードします。
Command> SELECT * FROM oratt.subscriber WHERE subscriberid = 1004; < 1004, Robert Phillips, 60, 20 >
この結果、スタンドアロン・データベース・グリッド・メンバーcachealone2は、サブスクライバIDが1004のキャッシュ・インスタンスの所有権をグリッド・メンバーcachealone1から取得します。 これで、このキャッシュ・インスタンスはcachealone1には存在しなくなり、他のいずれのグリッド・メンバーにも存在しなくなります。
次に、TimesTenデータベースcacheactiveで次のINSERT文を発行して、新しいキャッシュ・インスタンスをTimesTenキャッシュ表に挿入します。
Command> INSERT INTO oratt.subscriber VALUES (1012, 'Charles Hill', 80, 16);
この結果、アクティブ・マスター・データベース・グリッド・ノードcacheactiveは、サブスクライバIDが1012のキャッシュ・インスタンスの所有権を持ちます。 このキャッシュ・インスタンスは、スタンバイ・マスター・データベースcachestandbyおよび読取り専用サブスクライバ・データベースrosubscriberにレプリケートされます。 このキャッシュ・インスタンスは、他のいずれのグリッド・メンバーにも存在しません。 また、この挿入処理は、キャッシュされたOracle表oratt.subscriberにも自動的に伝播されます。
スタンバイ・マスター・データベースまたは読取り専用サブスクライバ・データベースでは、キャッシュ・インスタンスの所有権を直接取得できません。 これらのデータベースは読取り専用であるため、動的ロード処理にも手動ロード処理にも、動的ロードを実行するSELECT文を含めることができません。
グリッド・メンバー間のローカル・キャッシュ・グループのキャッシュ表では、データは共有されません。 グリッド・メンバーごとに、ローカル・キャッシュ・グループの数が異なることがあります。 ある2つのグリッド・メンバーでローカル・キャッシュ・グループの定義が同じである場合、一方のグリッド・メンバー内のキャッシュ表のデータが他方のグリッド・メンバー内のキャッシュ表のデータと重複することがあります。 ローカル・キャッシュ・グループでは、キャッシュ・インスタンスがキャッシュ表を所有するという概念がありません。
グローバル・キャッシュ・グループを含むデータベースがキャッシュ・グリッドにアタッチされている場合、後続のデータベースを同じグリッドにアタッチし、グリッド・メンバーにすることができるのは、そのデータベースに含まれているグローバル・キャッシュ・グループの定義が、グリッドにアタッチされているデータベースのグローバル・キャッシュ・グループの定義と同じときのみです。 後続のデータベースに含まれているグローバル・キャッシュ・グループの数が、グリッドにアタッチされているデータベースより多いかまたは少ない場合、後続のデータベースを同じグリッドにアタッチすることはできません。 データベースごとに、ローカル・キャッシュ・グループの数が異なり、データベース間で定義が一致しない場合があります。
キャッシュ・グリッドにアタッチされているTimesTenデータベースに動的AWTグローバル・キャッシュ・グループを新しく作成する場合は、データベースでレプリケーション・エージェントを停止しておきます。 グローバル・キャッシュ・グループを作成した後にレプリケーション・エージェントを再起動します。 新しいグローバル・キャッシュ・グループは、手動でロードすることも動的にロードすることもできません。また、そのキャッシュ表は、すべてのグリッド・メンバーで同じ定義を使用してキャッシュ・グループが作成されるまで更新できません。 スタンドアロン・データベースおよびアクティブ・マスター・データベースに、その新しいグローバル・キャッシュ・グループを手動で作成します。 スタンバイ・マスター・データベースおよび読取り専用サブスクライバ・データベースの場合は、ttDestroyユーティリティを使用してデータベースを削除し、ttRepAdmin -duplicateユーティリティ・コマンドを使用してデータベースを再作成して、これらのデータベースに新しいグローバル・キャッシュ・グループが含まれるようにします。