X

A blog about Oracle Technology Network Japan

Recent Posts

OCI

オラクルのMaximum Security Architectureで実現するデータベースのセキュリティ

※本記事は、Sean CahillによるOracle’s Maximum Security Architecture for Database Securityを翻訳したものです セキュリティ制御されるべき領域 御社の機密データを守り、世界中で急増している多数の新しいプライバシー規制に準拠するには、Oracle Databaseの保護が非常に大切です。御社のデータ――たとえば知的財産、財務データ、顧客やスタッフの個人情報、さらにそれらを組み合わせたデータ(この形を取ることが多い)――は、きわめて貴重です。データには価値があるので、盗難や誤用から守る必要があります。 データを本当に守ろうと思ったら、鍵をかけて埋めてしまえばいいのかもしれませんが、そうしたデータは業務での利用を目的としていますから、ユーザーやアプリケーションはそのデータを使用したり、データベースに接続したりしなければなりません。セキュリティ制御によってデータを保護し、御社のポリシーに従ってデータへのアクセスを制限することが必要です。 そのためには、次の3つの手順が求められます。 1.システムを評価して、現在の状態を見極め、修正プランを策定します。 システムは適切に構成されているか。  パッチは定期的に適用されているか。  ユーザー権限はどのように管理されているか(付与されている権限は必要最低限か)。 システムにはどのような種類の機密データがどれほど保存されているか。  Oracle Databaseのお客様であれば、データベースを評価し、改善とリスク軽減の対象となる箇所を特定するのに必要な機能やユーティリティは、ご購入済みのOracle Databaseにあらかじめ用意されています。 2.ポリシーに従っていないデータ・アクセスを検知し、データ・アクセスでの異常を特定します。データベースでは、ほぼすべての動作が繰り返されるため、異常の発見は多くの場合、データ盗難の疑いがあることを最前線で示すものとなります。 3.データベース制御メカニズムを経由していないデータ・アクセス、つまりネットワークを介したトラフィックの傍受、下方にあるデータ・ストレージ層の読取り、データベース・エクスポートやバックアップの誤用を防止します。制御メカニズムを経由したアクセスについては、その状況を見極めて、データにアクセスしたアカウントを特定するだけでなく、不適切なデータ・アクセスをブロックします。 オラクルでは、こうしたセキュリティ制御のそれぞれの目的に合致する、業界屈指の機能を用意しています。オラクルのチームは、制御の目的が実質的に何であれ、御社がふさわしい技術的対策を見つけられるように支援します。 データベースはどのようにして攻撃されるのか データベースは機密情報の宝庫であり、データを盗みだそうとする人はほぼ必ず、データベース内のデータを悪事の標的にします。この種の攻撃から身を守る方法について考える前に、攻撃がどのように発生するのかを見てみましょう。 データベースは単独で機能しているわけではありません。常に使用されている状態であるため、リスクにさらされることも概して多くなります。データベースには、ユーザーとアプリケーションがアクセスします。多くの場合、テスト用や開発用、さまざまな目的でのステージング用のデータベース・コピーがあります。データベースはストレージ・メディアにデータを保持しつつ、オペレーティング・システムや周辺機器を備えたサーバーで実行されます。管理者がすべてを管理し、大きな権限を与えられているため、ハッカーにとって管理者は狙いどころです。管理者アカウントへの不正アクセスに成功したハッカーは、昇格された権限を手に入れることになり、ほとんどの場合、制御不能でやりたい放題になります。 管理者アカウントを手に入れることはできなくても、エンドユーザー・アカウントを乗っ取ることができる場合が多々あります。与えられている権限は少ないですが、いくらかのデータにはアクセスできたり、SQLインジェクション攻撃によって、目的の管理者アクセスを手に入れるための足がかりとして利用できたりします。 アプリケーションも魅力あるターゲットです。データベースやデータベース・サーバーと比べて公開されている部分が多く、企業のファイアウォールの外から使用できることもあります。 ファイアウォールといえば、社内ネットワークへの侵入に成功した攻撃者が、ネットワークを行き来するデータを攻撃する場合があります。この種の攻撃は、データベースへの直接のアクセスと比べて、はるかに検知しにくくなります。 もう1つのよくある攻撃は、表には出てこないデータファイル、データベース・バックアップ、データベース・エクスポートへの攻撃です。この場合も、攻撃に成功したサイバー犯罪者は、データベースにログインしようとしなくても、データベース全体のデータを盗むことができる可能性があるのです。 上記のようなことが成功しなくても、データベースにパッチ未適用の脆弱性があるかもしれません。多くの場合、そのような脆弱性を悪用するための、自動化された攻撃ツールキットが作成されているものです。 そして、本番用以外のデータベース・コピーについても忘れるわけにはいきません。多くのシステムでは、テスト用および開発用のインスタンスは本番用のクローンですが、セキュリティ対策はほぼなされていません。 では、このような攻撃すべてに立ち向かうにはどうすればよいのか 効果的なデータベース・セキュリティ戦略があれば、複数の異なるセキュリティ制御を採り入れ、そのすべてを連携させることができます。オラクルのセキュリティ制御を、先述したカテゴリ、つまり評価、検知、防止、そしてデータ主導型セキュリティに分けて説明しましょう。データ主導型セキュリティとは、リレーショナル・データベース内のアプリケーション・データへのアクセスをきめ細かく制御することに主眼を置いた、セキュリティ制御の特別なカテゴリです。 まずは、Oracle Database Security Assessment Tool(DBSAT)を使用して、データベースの構成を評価し、ベスト・プラクティスからどれほど乖離しているかを調べます。データベースの構成に問題があると、他の制御も効果が薄れる可能性があります。 次に、ユーザーとアプリケーションについて思い出してください。皆がデータベースにログインすることを考えると、Centrally Managed Users(CMU)を使用するのがよいかもしれません。CMUはデータベース機能の1つで、データベースをMicrosoft Active Directoryに接続します。また、Enterprise User Security(EUS)の使用を検討してもよいかもしれません。EUSはデータベースとオラクル独自のディレクトリ・サービスとをつなげるデータベース機能です。いずれの場合も、データベースのユーザーとロールは、データベースから離れてLDAPディレクトリの下に置かれます。 パスワードよりも強力なものを使ってユーザーを認証したいという場合もあるかもしれません。Oracle DatabaseはRadius、Kerberos、PKI証明書による認証をサポートしています。DBSATに話を戻しましょう。ユーザーは誰なのか、どのような権限を持っているかについて知る必要がある場合、DBSATからその情報を得ることができます。 ユーザーが持っている権限に加えて、実際にどの権限を使用しているのかを知りたい場合は、権限分析(PA)が役立ちます。権限分析を使用すると、使用されていない権限とロールを特定して、ユーザー・アカウントから削除できるため、アカウントへの不正アクセスがあったときに攻撃対象となり得る領域を狭めることができます。 データベース・クライアントがデータベースにデータを送信し始め、データを取得してレポートを作成したり分析したりするようになると、送受信時のデータの保護についても心配しなければなりません。ここではネットワークの暗号化が有効です。 また、どのような種類のデータがデータベースに格納されているのか知りたい場合は、DBSATを使用して、機密データを探すことができます。 そのデータは最終的にはディスク、バックアップ、エクスポートに保存されるため、そこでデータを攻撃から保護する必要があります。ここは、Oracle Advanced Securityの一部である透過的データ暗号化(TDE)の出番です。TDEはオペレーティング・システム上、ストレージ・デバイス内、バックアップ・ファイルとエクスポート・ファイル内のデータを暗号化します。データを暗号化するとき、つまり1つまたは複数の暗号化鍵があり、鍵を保護し、安全に送信する必要があるときには、Oracle Key Vault(OKV)を使用します。OKVはエンタープライズ・アーキテクチャ内のOracle Databaseを認識して、TDE鍵をローテーションしやすくし、古いバックアップやファイルをリストアする必要があるときは、以前に使用された鍵を保護します。 管理者にはデータにアクセスする権限が与えられていることを思い出してください。そのような管理者も保護する必要があります。それには、Oracle Database Vault(DV)を使用します。Database Vaultは、データベース管理の役割を、データベース内のデータへのアクセスから切り離します。Database Vaultには不正にアクセスされたアプリケーション・サーバーからの保護機能もあり、アプリケーションのアカウントをロックして、アプリケーションの正常な状態のデータのみにアクセスできるようにします。 アプリケーション外からのデータ・アクセスがある場合、クレジット・カード番号や納税者番号などの機密度の高いデータ列には、保護を追加したいと思うかもしれません。この場合は、Oracle Advanced Securityの一部であるData Redactionを使用して、データベースを離れて送信される間であってもデータを隠すことができます。 さらに、データベースの本番用以外のクローンについては、Oracle Data Masking and Subsetting Packの一部であるData Maskingを使用して、単純に機密データを削除し、セキュリティ上のリスクにならない本物そっくりの“安全な”データに差し替え、アプリケーションの開発とテストはそのまま続けることができます。 データベースを保護するためにさまざまな対策を講じてきましたが、侵入やデータの盗難の疑いを確実に検知することも重要です。そのためには、データベース内に監査を構成し、一元管理された監査ボルトに監査イベントを送信して、分析、レポート作成、アラートの生成を行う必要があります。 ここでは、Oracle Audit Vault and Database Firewallの一部であるDatabase Firewallを使用して、異常やポリシー違反がないか、着信接続要求とSQL文を検証します。必要な場合はさらに一歩進んで、ポリシー違反の動作をファイアウォールによって実際にブロックします。当然ですが、Database FirewallのイベントはAudit Vaultサーバーに送信され、分析、レポート作成、アラート生成に使用されます。 最後になりますが、アプリケーション・ユーザー向けにデータを行や列レベルできめ細かく制御することができます。ここで利用できるオラクルの機能には、Real Application Security(RAS)やOracle Label Securityなど、さまざまなものがあります。このセル・レベルのアクセス制御によって、複数のアプリケーションを開発して、アプリケーション・ユーザーによるデータ・アクセスの認可モデルを統一し、アプリケーション開発に要する時間と労力を減らすことができます。 連携して動作するこれらすべての制御が、Maximum Security Architectureです。これまで紹介したもののほとんどはデータベースの機能であり、Enterprise Editionのお客様であればどなたでも使用できます。追加費用がかかるオプションや製品も一部あります。   クラウドでのMaximum Security Architecture クラウドのすばらしい点の1つは、用意されているそのオプションです。御社のデータベースがOracle Cloudで稼働している場合、Oracle Data Safeも利用できます。Data Safeには、DBSAT、Audit Vault、Data Maskingと同等の、Oracle Databaseを保護するための複数の機能があります。 Database Vaultや透過的データ暗号化のようなオプションもクラウドで提供されており、ほとんどのクラウド・サービス(Oracle Autonomous Databaseなど)は、追加料金不要でサブスクリプションに含まれています。多くの場合、自動で有効になり、構成されます。 クラウドでMaximum Security Architectureを実装するほうが簡単だということです。 忘れるべきでないのは、大半のサイバー攻撃の目的は、御社のもっとも価値ある資産、つまりデータを入手することです。その資産を保護するために、Maximum Security Architectureをガイドとして使用してください。 Maximum Security Architectureについての詳しい情報は、Oracle Database SecurityのWebページをご覧になるか、オラクルの電子書籍をダウンロードしてください。

※本記事は、Sean CahillによるOracle’s Maximum Security Architecture for Database Securityを翻訳したものです セキュリティ制御されるべき領域 御社の機密データを守り、世界中で急増している多数の新しいプライバシー規制に準拠するには、Oracle Databaseの保護が非常に大切です。御社のデータ――たとえば知的財産、財務データ、顧客や...

Autonomous Database

Autonomous Databaseの最新情報をお届けします

※本記事は、Keith Laker (Senior Principal Product Mamager)による"Autonomous Database Newsletter - February 18-2020"と"Autonomous Database Newsletter - February 26-2020"を翻訳したものです。Oracle Autonomous Database Cloudについての最新情報はこちら(Speaker Deckサイト)に日本語スライド資料も公開していますのであわせてご覧ください。   共有ExadataインフラストラクチャでのAutonomous Database ようこそ。共有ExadataインフラストラクチャでのAutonomous Databaseに関する最初のカスタマー・ニュースレターをお届けします。このニュースレターでは、以下の新しい機能およびテーマを取り上げます。 Oracle Database Vaultの提供開始 「Always Free」のADB(Autonomous Database)で新たに利用可能となったAPEX 19.2 複数DBのサポート ADB対応の新しいGraph Server より容易になった移行 新たなデータセンター プライベート・エンドポイントに対応 クイック・リンク oracle.comの自律型データベースに関する最新情報ページもどうぞご確認ください。   トップへ戻る   (共有インフラストラクチャのみ) NEW - Autonomous DatabaseでのOracle Database Vaultの使用 Oracle Database Vaultを使用すると、Autonomous Databaseのセキュリティを強化することができます。具体的には、データベースの特権ユーザーによるアプリケーション・データへのアクセスの制限、内部関係者および部外者による脅威の軽減、一般的なコンプライアンス要件への対応といった、他にはないセキュリティ制御機能を獲得することができます。 詳細情報 ドキュメント:Autonomous Data Warehouse(ADW)でのOracle Database Vaultの使用:こちらをクリック ドキュメント:Autonomous Transaction Processing(ATP)でのOracle Database Vaultの使用:こちらをクリック スライド:OOW2018 - オートノマス、そしてその先へ:自律型データベース時代のセキュリティ:こちらをクリック ドキュメント:Database Vaultに関するDatabase 19cドキュメント:こちらをクリック その他の情報 ビデオ:Database Vaultの概要 - こちらをクリック PDF:Database Vault FAQ - こちらをクリック PDF:Database Vaultのデータシート - こちらをクリック PDF:Oracle Database Vaultの概要 - こちらをクリック PDF:Oracle Database Vaultのベスト・プラクティス - こちらをクリック PDF:Oracle Database Vault:DBAのベスト・プラクティス - こちらをクリック こちらもご覧ください ビデオ:Database Vault - 職務分掌の適用 - こちらをクリック ビデオ:Database Vault - 信頼パス・アクセス制御の導入 - こちらをクリック ビデオ:Database Vaultの詳細なユースケース2 - Operations Control、Database Vaultシミュレーション・モード - こちらをクリック   トップへ戻る   (共有インフラストラクチャのみ) NEW - Always Free Autonomous DatabaseでAPEX 19.2が利用可能に Always Free Autonomous DatabaseにてOracle APEX 19.2を利用することで、ワールドクラスのデータ中心型アプリケーションの構築とデプロイの両方において、事前構成済みで、フル・マネージドの、安全な環境を獲得することができます。オンプレミスで開発されたOracle APEXアプリケーションを、無料版のAutonomous DatabaseにあるOracle APEXにデプロイすることも簡単です。   詳細情報 Application Expressとは:こちらをクリック ドキュメント:APEX 19cのGetting Started Guide:こちらをクリック ドキュメント:ADWでの、Oracle Application Expressを使用したアプリケーション構築:こちらをクリック ドキュメント:ATPでの、Oracle Application Expressを使用したアプリケーション構築:こちらをクリック こちらもご覧ください こちらで、架空の会社AnyCo Corpの簡単な人事アプリケーションを作成し、データベース・テーブルに保存された部門情報や従業員情報を管理してみましょう。 ビデオ:スプレッドシートを使用してわずか2分でAPEXアプリケーションを作成する方法をこちらでご紹介しています。 ハンズオン・ラボ:APEXハンズオン・ラボの一覧は、こちらをご覧ください。   トップへ戻る   (共有インフラストラクチャのみ) NEW - リージョンによっては、データベースの複数バージョンの利用が可能に データベースのプロビジョニングまたはクローニングを実施しているリージョンによっては、Autonomous DatabaseがOracle Databaseの複数のバージョンに対応できるようになりました。この対応はリージョンごとに異なります。また複数バージョンに対応していないリージョンもあります。 複数バージョンが利用可能な場合、データベースのプロビジョニングやクローニングの際には、Oracle Databaseのバージョンを選択します。 詳細情報 ドキュメント:ADWに対応するOracle Databaseのバージョンと可用性(リージョン別):こちらをクリック ドキュメント:ATPに対応するOracle Databaseのバージョンと可用性(リージョン別):こちらをクリック   Oracle Database 19cにてADBを使用している場合は、以下のとおり、そのデータベースで利用できる機能が他にもあります。 ドキュメント:Oracle Database 19cでのADWの機能:こちらをクリック ドキュメント:Oracle Database 19cでのATPの機能:こちらをクリック。   トップへ戻る   (共有インフラストラクチャのみ) NEW - Oracle Graph Server and Client 20.1が利用可能に Oracle Graph Server and Client 20.1は、Autonomous Databaseにて使用できるソフトウェア・パッケージです。このパッケージには、Autonomous Databaseのプロパティ・グラフ機能での作業に必要な、インメモリ・アナリスト(PGX)およびクライアント・ライブラリが含まれています。 グラフ分析を用いることで、ソーシャル・ネットワーク、IoT、ビッグ・データ、データウェアハウス、また銀行での不正の検出、全方位的な顧客情報、スマート製造などを扱うアプリケーションの複雑なトランザクション・データにおいて、関連性やパターンを見つけることができます。  詳細情報 edelivery.oracle.comからダウンロードが可能です。こちらをクリックしてください。 ドキュメント:インストール方法については、こちらをクリックし、「1.7 Using Oracle Graph with the Autonomous Database」のセクションをご覧ください。 Web:oracle.comのGraph Serverページ:こちらをクリック その他の情報 スライド:エキスパートでない方向けの優しいグラフ分析:こちらをクリック スライド:グラフ分析で新しいインサイトを獲得するには:こちらをクリック   トップへ戻る   (共有インフラストラクチャのみ) NEW - ADBへの移行を容易にする機能 1.データベース常駐接続プーリング(DRCP) DRCPを使用してADBの接続プールにアクセスすることで、多くのクライアント接続に必要な主要データベース・リソースの数を大幅に削減することができます。Autonomous Databaseでのデータベース常駐接続プーリングの使用に関する詳細は、以下を参照してください。 ドキュメント:ADW こちらをクリック ドキュメント:ATP こちらをクリック   2.MAX_STRING_SIZEの値の設定 ADWのデータベースでは、デフォルトでMAX_STRING_SIZEがEXTENDEDに設定されています。古いOracle Databaseまたはアプリケーションからの移行では、MAX_STRING_SIZEをSTANDARDに設定します。MAX_STRING_SIZEの設定に関する詳細は、以下を参照してください。 ドキュメント:ADW こちらをクリック ドキュメント:ATP こちらをクリック   3.同時文の数 同時文の最大数が増えました。詳しくは、Autonomous Data Warehouseの事前定義済みのデータベース・サービス名に関する以下の記事を参照してください。 ドキュメント:ADW こちらをクリック ドキュメント:ATP こちらをクリック   トップへ戻る   (共有インフラストラクチャのみ) NEW - より多くのデータセンターがオンライン上に 以下のデータセンターでも、Autonomous Databaseを利用できるようになりました。 サウジアラビア・ジェッダ 日本・大阪 オーストラリア・メルボルン オランダ・アムステルダム 各データセンターのサービスの状況については、こちらをクリックしてご確認ください。これらの新しいリージョンへの登録方法については、こちらを参照してください。リージョンを切り替えるには、コンソールにある「Region」メニューを使用します。詳しくは、こちらを参照してください。   トップへ戻る   (共有インフラストラクチャのみ) NEW - Autonomous Databaseがプライベート・エンドポイントに対応 仮想クラウド・ネットワーク(VCN)にあるプライベート・エンドポイントを指定して、Autonomous Databaseへのアクセスを制限することが可能になりました。プライベート・アクセスの構成は、Autonomous Databaseのプロビジョニングまたはクローニングの際に実施され、これによりAutonomous Databaseとのすべてのトラフィックをパブリック・インターネットから切り離すことができます。 プロビジョニングまたはクローニングの際に、Autonomous Databaseへのプライベート・アクセスを指定することも可能です。これには、以下のとおり、作成/クローニングのダイアログの「Choose network access」セクションにて、「Virtual cloud network」を選択します。 画像adb_private_vcn.pngの説明   プライベート・エンドポイントを有効にするには、以下の3つのステップを実行します。これらのステップは、Autonomous Databaseのプロビジョニングまたはクローニングの前に実施する必要があります。 Autonomous Databaseを置くリージョンにて、VCNを作成します。 VCN内にサブネットを設定します(デフォルトのDHCPオプションにて設定)。 VCN内にネットワーク・セキュリティ・グループ(NSG)を少なくとも1つ指定します(Autonomous Databaseの送信および受信ルールを指定するために使用)。 注:プライベート・エンドポイントは現在、オラクルのすべてのデータセンターに展開されつつあります。2月26日現在の利用可能なデータセンターは、以下のとおりです。 アムステルダム アッシュバーン フランクフルト ジェッダ ロンドン メルボルン 大阪 フェニックス ソウル 東京 トロント これ以外のデータセンターでも、まもなく利用可能になります。   詳細情報   ドキュメント:ADWにてプライベート・エンドポイントを設定:こちらをクリック ドキュメント:ATPにてプライベート・エンドポイントを設定:こちらをクリック ブログ:共有ExadataインフラストラクチャでのAutonomous Databaseでプライベート・エンドポイントを使用可能になりました:こちらをクリック       こちらもご覧ください ドキュメントには、ネットワーク・シナリオのサンプルが2つ用意されています。 サンプル1:Oracle Cloud Infrastructure VCNから接続 サンプル2:ご利用のデータセンターからAutonomous Databaseに接続   ドキュメント:ADWでのプライベート・エンドポイントの構成例:こちらをクリック ドキュメント:ATPでのプライベート・エンドポイントの構成例:こちらをクリック     トップへ戻る   oracle.com ADW ATP ドキュメント ADW ATP TCO計算ツール サーバーレス 専用サーバー クラウド・コスト試算ツール Autonomous Database ADBの新機能 Autonomous Database スキーマ・アドバイザー Autonomous Database       カスタマー・フォーラム ADW ATP      

※本記事は、Keith Laker (Senior Principal Product Mamager)による"Autonomous Database Newsletter - February 18-2020"と"Autonomous Database Newsletter - February 26-2020"を翻訳したものです。Oracle Autonomous Database...

基本からわかる!高性能×高可用性データベースシステムの作り方 第15回 最低限度のData Guard環境を手作業で構成するには

基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ Oracle Databaseのレプリケーション機能にはいくつかありますが、障害に備えるためレプリケーション機能としてはData Guardフィジカル・スタンバイおよびその拡張であるActive Data Guardが第一選択肢です。手作業でData Guardを構成する場合、最初にデータベースの複製を作成する工程が最も手間がかかります。Oracle Database 18c以降ではdbcaコマンドを使用するとこの複製工程を大幅に簡略化することができます。Data Guardを構成するには最低限何を設定すればよいかを解説します。 Data Guardフィジカル・スタンバイの動作原理 Data Guardフィジカル・スタンバイは物理バックアップ・リカバリの応用でデータベースのレプリカを作成します。 Data Guardの前にまず、物理バックアップ・リカバリの仕組みをおさらいしましょう。 データベースに更新が発生すると、その情報はREDOログの形でオンラインREDOログ・ファイルに記録されます。これはデータ・ブロックにどのような変更が行われたかの記録です。データベースのフル・バックアップ、つまり全データ・ブロックのバックアップが取得してあれば、それを書き戻して(リストア)、REDOログを適用(リカバリ)すれば、REDOログが存在する時点までのデータベースの状態を復元することができます。 Data Guardフィジカル・スタンバイは、レプリケーション元のデータベース(プライマリ・データベース)のフル・バックアップを別のサーバーにリストアし、そこでプライマリ・データベースで生成されたREDOログを適用し続けることでプライマリ・データベースとデータ・ブロックの中身の構造まで全く同じになるデータベースを複製することができます。Data Guard用語では複製したレプリケーション先のデータベースをスタンバイ・データベースと呼びます。   Data Guardでは、プライマリ・データベースでREDOログ情報がSystem Global AreaのREDOログ・バッファに書き込まれるとスタンバイ・データベースに転送しようとします。そのため、いくつかあるレプリケーション機能の中でも、Data Guardが最も転送遅延が小さくなります。転送遅延が小さいため、レプリケーション先に更新が伝搬したことが確認できるまでCOMMITが確定しないという同期転送モードを持っているのもData Guardだけです。 Data Guardの仕組みをもう少し詳細に見ていきましょう。Data Guardは大別すると2つの機能に分解できます。1つはREDOログの送受信(REDO転送サービス)で、もう1つは受信したREDOログの適用(適用サービス)です。Data Guardの構成とは、これら2つの機能を設定することです。   1つ目の設定はREDOログの送受信に関する設定です。プライマリ・データベースではREDOログ送信に関する設定を行います。スタンバイ・データベースではREDOログ受信に関する設定を行います。受信したREDOログ情報はスタンバイREDOログ・ファイルに格納されます。CREATE DATABASEで作成したプライマリ・データベースではREDOログ情報はオンラインREDOログ・ファイルに格納されますが、スタンバイREDOログ・ファイルはデータベース作成時点では存在していないのでこれを作成する必要があります。スタンバイREDOログ・ファイルもオンラインREDOログ・ファイルと同様に固定長固定数のファイル群で、循環して上書きされます。スタンバイREDOログ・ファイルの内容も上書きされる前にアーカイブREDOログ・ファイルに書き出されていきます。 2つ目の設定はリカバリです。スタンバイREDOログ・ファイルおよびアーカイブREDOログ・ファイルに記録されたREDOログ情報をデータファイルに適用します。REDOログの送受信とリカバリは独立して動作します。つまり、リカバリ・プロセスを停止している場合でもREDOログの送受信は継続しています。 Active Data GuardというのはData Guardフィジカル・スタンバイの発展形で、スタンバイ・データベースをリカバリしながらもREAD ONLYでオープンすることができる機能です。 Data Guardフィジカル・スタンバイを手作業で構成 Oracle Enterprise Manager Cloud Controlが構成されているオンプレミス環境や、Oracle Cloud InfrastructureのDatabase Cloud ServiceではWebのGUIからData Guardが簡単に構成できるようになっていますが、ここでは手作業でコマンド操作して構成する方法を解説します。Data Guard環境の構築で最も手間がかかる工程は、最初にプライマリ・データベースの複製を作る(違う名前でデータベースをリストアする)ところです。Oracle Database 18c以降のDatabase Configuration Assistant(dbcaコマンド)を使用すると、Data Guardスタンバイ・データベース用の複製を簡単に作成できるようになっています。 Data Guardの構築は大別すると3つの工程になります。 1.    プライマリ・データベースでの設定 プライマリ・データベースからスタンバイ・データベースを複製するにあたり、スタンバイ・データベースに設定が引き継がれる項目をプライマリ・データベースで設定しておきます。 2.    スタンバイ・データベースでの設定 プライマリ・データベースからスタンバイ・データベースの複製を作成します。その後、プライマリ・データベースの設定を引き継がない項目をスタンバイ・データベースで設定します。 3.    REDO転送サービスの設定とリカバリ開始 Data GuardのREDOログ送受信の設定を双方に行います(REDO転送サービスの開始)。そして、スタンバイ・データベースでリカバリを開始します(リカバリ・サービスの開始)。 それでは各工程を見ていきましょう。 1.    プライマリ・データベースでの設定 1.1.     アーカイブ・ログ・モード Data Guardはアーカイブ・ログ・モードである必要があります。アーカイブ・ログ・モードへの変更はData Guard構築でプライマリ・データベースの停止が発生する唯一の工程です。しかし本番運用されているデータベースならばすでにアーカイブ・ログ・モードになっていることが想定されるので、Data Guardは実質的に無停止で構成することが可能です。 $ srvctl stop database -db ... $ sqlplus / as sysdba SQL> startup mount SQL> alter database archivelog; SQL> select LOG_MODE from v$database; LOG_MODE ------------------------------------ ARCHIVELOG SQL> exit $ srvctl start database -db ...   1.2.     FORCE LOGGING Data GuardはREDOログ情報に乗らない変更は伝搬しません。そのため、NO LOGGINGが指定されている操作でもREDOログを生成するFORCE LOGGINGモードにします。 SQL> alter database force logging; SQL> select force_logging from v$database; FORCE_LOGGING -------------------- YES 1.3.     STANDBY_FILE_MANAGEMENT プライマリ・データベースで新しいデータファイルが生成されたとき、それをスタンバイ・データベースでも自動生成する設定を行います。 SQL> alter system set STANDBY_FILE_MANAGEMENT='AUTO' scope=both sid='*'; 1.4.     スタンバイREDOログ・ファイル スタンバイ・データベースで受信されたREDOログ情報はスタンバイREDOログ・ファイルに格納されます。スタンバイREDOログ・ファイルはスタンバイ・データベースにあればよいのですが、Data Guardを構成する場合はいずれプライマリとスタンバイの役割を入れ替える(スイッチオーバー)ことになるので、あらかじめプライマリ・データベースにも作成します。プライマリ・データベースで作成したスタンバイREDOログ・ファイルは、dbcaで複製するとスタンバイ・データベースにもその構成が引き継がれます。 Oracleインスタンスは自分が書き込む専用のREDOログのストリームを持っており、これをREDOスレッドと呼びます。RAC構成では複数のOracleインスタンスがあるので、REDOスレッドはOracleインスタンスの数だけあります(V$LOG.THREAD#)。   スタンバイREDOログ・ファイルの構成はオンラインREDOログ・ファイルの構成から導出しますので、まずオンラインREDOログ・ファイルの構成を調べます。CDB$ROOTにログインしてV$LOGビューからREDOスレッドとメンバーの構成、そしてファイルのサイズを調べます。 SQL> select thread#,group#,bytes from v$log;    THREAD#     GROUP#      BYTES ---------- ---------- ----------          1          1 1073741824          1          2 1073741824          2          3 1073741824          2          4 1073741824   作成するスタンバイREDOログ・ファイルは、各REDOスレッドにオンラインREDOログのメンバー数+1個のメンバーを作成します。各ファイル・サイズはオンラインREDOログ・ファイルと同じにします。GROUP番号はオンラインREDOログおよびスタンバイREDOログあわせて一意な番号を指定します。 SQL> alter database add standby logfile thread 1 group 5 size 1073741824, group 6 size 1073741824, group 7 size 1073741824; SQL> alter database add standby logfile thread 2 group 8 size 1073741824, group 9 size 1073741824, group 10 size 1073741824; 2.    スタンバイ・データベースでの設定 2.1.     dbcaでプライマリ・データベースをオンライン複製 Data Guardの構築で最も手間がかかる工程は、データベースを違う名前(DB_UNIQUE_NAME)で複製を作るところです。 Oracle Databaseはデータベースの名前が3階層あります。CDBおよびnon-CDBの名前で2階層(DB_NAMEとDB_UNIQUE_NAME)、そしてPluggable Databaseの名前で1階層(PDB_NAME)です。Data Guardを構成するデータベース群は、それぞれDB_UNIQUE_NAMEが一意になっています。DB_NAMEとPDB_NAMEは共通です。DB_UNIQUE_NAMEが管理操作上のデータベースを区別する識別子です。データベースのファイル・パスに含まれる「データベースの名前」や、srvctlコマンドの-dbオプションで指定する「データベースの名前」というのはDB_UNIQUE_NAMEを指しています。そのため、複製を作る前にDB_UNIQUE_NAMEを決めておく必要があります。   手作業でデータベースを複製するには、DB_UNIQUE_NAMEを変えてOracleインスタンスを起動するための初期化パラメータファイルの用意や各種ログ・ファイルが生成されるディレクトリの作成などが必要です。これらをdbcaで大幅に簡略化します。 dbcaにプライマリ・データベースへの接続情報を指定し、内部的にはRMANを使用してオンライン・フル・バックアップを取得し直接スタンバイ・データベース用のストレージにリストアします。スタンバイ・データベース用のOracleインスタンスの初期化パラメータは基本的にはプライマリ・データベースのものを継承します。変更のあるパラメータはdbcaのオプションで指定します。 $ export LANG=C $ export NLS_LANG=American_America.US7ASCII $ dbca -silent -createDuplicateDB -createAsStandby      -gdbName DB_NAME.DB_DOMAIN      -sysPassword SYSユーザーのパスワード      -primaryDBConnectionString scan-host-name:port/SERVICE_NAMES      -dbUniqueName DB_UNIQUE_NAME      -sid ORACLE_SID接頭辞      -initParams db_create_file_dest=+DATA, db_recovery_file_dest=+RECO      -databaseConfigType RAC      -adminManaged      -nodelist node3,node4   分類 dbcaのオプション 意味 プライマリ・データベースへの接続情報 -gdbName グローバル・データベース名 DB_NAME.DB_DOMAIN -sysPassword SYSユーザーのパスワード -primaryDBConnectionString Oracle Netの接続情報 CDB$ROOTに接続するのでサービス名はDB_UNIQUE_NAME.DB_DOMAIN スタンバイ・データベース側の識別子の指定 -dbUniqueName DB_UNIQUE_NAME -sid ORACLE_SID接頭辞 RACの場合はこれに1,2,3...と数値が付加される -initParams プライマリ・データベースの初期化パラメータから変更するもの RAC構成 -databaseConfigType RAC/RAC One Node構成の指定 -adminManaged RACのクラスタ・タイプの指定 -nodelist RACインスタンスを起動するノードの指定 dbcaで複製が完了するとスタンバイ・データベースになれる状態(V$DATABASE.DATABASE_ROLE=PHYSICAL_STANDBY)になっておりOPEN READ ONLYでアクセスできる状態になっています。また、Oracle Grid Infrastructure上に構成されている環境ではdbcaの完了でクラスタのリソース登録まで行われるので、srvctlコマンドでOracleインスタンスの操作ができるようになっています。 SQL> select OPEN_MODE,DATABASE_ROLE from v$database; OPEN_MODE       DATABASE_ROLE --------------- -------------------- READ ONLY       PHYSICAL STANDBY 2.2.     BCTファイル(Optional) Data Guardフィジカル・スタンバイはスタンバイ・データベースでもデータファイルのバックアップを取得することができます。Block Change Trackingファイルを設定しておけば高速増分バックアップも可能です。これはプライマリ・データベースで設定されていてもスタンバイ・データベースには引き継がれないので、必要であればスタンバイ・データベースであらためて設定が必要です。 SQL> alter database enable block change tracking; SQL> select status from V$BLOCK_CHANGE_TRACKING; STATUS ---------- ENABLED 2.3.     FLASHBACK ON(Optionalただし実質的に必須) Data GuardのREDO転送およびリカバリ自体はFlashback Databaseが設定されていなくても動作します。ただし、スタンバイ・データベースへのフェイルオーバーのテストや、スタンバイ・データベースを切り離してアプリケーションのテストなどに使用すると、プライマリ・データベースとはREDOログの内容がずれているのでそのままではREDOログ適用の再同期ができなくなります。これをFlashback Databaseを使用せずに再同期させるには、REDOログがずれる前に取得したフル・バックアップをリストアするか、現在のプライマリ・データベースから複製しなければなりません。つまりスタンバイ・データベースの再構築が必要になります。これを簡単に再同期できるようにするためには、Flashback Databaseの機能を使用しREDOログの内容がずれる前の時刻まで戻します。そのため、Data Guardをまともに運用しようとするならばFlashback Databaseの設定は実質的に必須です。 SQL> alter database flashback on; SQL> select flashback_on from v$database; FLASHBACK_ON -------------------- YES 3.    REDO転送サービスの設定とリカバリ開始 3.1.     tnsnames.ora REDOログの転送先の情報はtnsnames.oraファイルのエントリを使用します。書式はアプリケーションが接続するときの書き方と同じで、Oracleリスナーのアドレスとサービス名を指定します。REDO転送の宛先のサービス名はCDB$ROOTのサービス、つまりデータベースのデフォルト・サービス名であるDB_UNIQUE_NAME.DB_DOMAINになります。 スタンバイ・データベース側にもプライマリ・データベースへの接続情報を作成しておきます。つまり、Data Guardを構成する全データベースへの接続情報をあらかじめ全ノードのtnsnames.oraに記述しておきます。 primary_database_net_alias =   (DESCRIPTION =     (ADDRESS = (PROTOCOL = TCP)(HOST = scan-host-name-primary)(PORT = scan-port))     (CONNECT_DATA =       (SERVER = DEDICATED)       (SERVICE_NAME = primary_SERVICE_NAMES)     )   ) standby_database_net_alias =   (DESCRIPTION =     (ADDRESS = (PROTOCOL = TCP)(HOST = scan-host-name-standby)(PORT = scan-port))     (CONNECT_DATA =       (SERVER = DEDICATED)       (SERVICE_NAME = standby_SERVICE_NAMES)     )   ) 3.2.     REDOログ転送サービスの初期化パラメータ REDOログ送受信の設定はOracleインスタンスの初期化パラメータに設定します。プライマリとスタンバイの役割で設定するパラメータが異なりますが、プライマリとスタンバイの役割はいつか入れ替わるので、あらかじめすべての初期化パラメータをプライマリとスタンバイの両方に設定しておきます。Data Guardに関連する初期化パラメータはすべてALTER SYSTEM SET ... SCOPE=BOTHで動的に設定できます。   3.2.1.    アーカイブREDOログ・ファイルの出力先 プライマリとスタンバイ両方でLOG_ARCHIVE_DEST_1を設定しておきます。ここに指定するDB_UNIQUE_NAMEは自データベースの名前です。出力先はDB_RECOVERY_FILE_DESTを使用します。 SQL> alter system set DB_RECOVERY_FILE_DEST_SIZE=195G scope=spfile sid='*'; SQL> alter system set DB_RECOVERY_FILE_DEST='+RECO' scope=spfile sid='*'; SQL> alter system set LOG_ARCHIVE_DEST_1='LOCATION=USE_DB_RECOVERY_FILE_DEST VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=db_unique_name' scope=spfile sid='*'; SQL> alter system set LOG_ARCHIVE_DEST_STATE_1='ENABLE' scope=spfile sid='*'; 3.2.2.    スタンバイ・データベース REDOログ送受信の許可と、アーカイブREDOログ・ファイルをリモートから取得する場合の接続先を指定します。LOG_ARCHIVE_CONFIGのDG_CONFIGにはData Guardを構成するすべてのデータベースのDB_UNIQUE_NAMEを列挙します。FAL_SERVERはリモートのデータベース、つまりプライマリ・データベースへ接続するtnsnames.oraのエントリを指定します。 SQL> ALTER SYSTEM SET  LOG_ARCHIVE_CONFIG='DG_CONFIG=(primary_DB_UNIQUE_NAME,standby_DB_UNIQUE_NAME)' scope=spfile sid='*'; SQL> ALTER SYSTEM SET FAL_SERVER='primary_alias' scope=spfile sid='*'; プライマリとスタンバイの役割はいつか入れ替わるので、あらかじめプライマリ・データベースにもFAL_SERVERは設定しておきます。 3.2.3.    プライマリ・データベース REDOログ送受信の許可と、REDOログ送信先を指定します。REDOログ送信先の指定にはアーカイブREDOログ・ファイルの出力先の指定と同様にLOG_ARCHIVE_DEST_nを使用します。 SQL> ALTER SYSTEM SET  LOG_ARCHIVE_CONFIG='DG_CONFIG=(primary_DB_UNIQUE_NAME,standby_DB_UNIQUE_NAME)' scope=spfile sid='*'; SQL> ALTER SYSTEM SET  LOG_ARCHIVE_DEST_2='SERVICE=standby_database_net_alias                        ASYNC                        VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE)                        DB_UNIQUE_NAME=standby_DB_UNIQUE_NAME' scope=spfile sid='*'; SQL> ALTER SYSTEM SET LOG_ARCHIVE_DEST_STATE_2='ENABLE' scope=spfile sid='*'; LOG_ARCHIVE_DEST_nの指定でREDOログ転送サービスの動作モードが変わります。これは設定の一例です。詳しくはOracle Databaseのマニュアル「Data Guard概要および管理」を参照してください。 スタンバイとプライマリの役割はいつか入れ替わるので、スタンバイ・データベースにもあらかじめLOG_ARCHIVE_DEST_nを設定しておきます。 ALTER SYSTEM SETで設定が完了した瞬間に、REDOログの送受信が開始されます。 3.3.     リカバリ開始 スタンバイ・データベースでリカバリを開始します。dbcaで複製が完了するとREAD ONLYでOPENした状態になっていました。これでリカバリを開始するとActive Data Guardになります。OPEN_MODEがREAD ONLY WITH APPLYになります。 SQL> select OPEN_MODE,DATABASE_ROLE from v$database; OPEN_MODE            DATABASE_ROLE -------------------- -------------------- READ ONLY            PHYSICAL STANDBY SQL> RECOVER MANAGED STANDBY DATABASE DISCONNECT; SQL> select OPEN_MODE,DATABASE_ROLE from v$database; OPEN_MODE            DATABASE_ROLE -------------------- -------------------- READ ONLY WITH APPLY PHYSICAL STANDBY 3.4.     スタンバイ・データベースの状態遷移 スタンバイ・データベースをREAD ONLY WITH APPLY状態にするActive Data GuardはEnterprise Editionの有償ライセンス・オプションです。READ ONLYでOPENせずにMOUNT状態にするData Guardフィジカル・スタンバイとの状態遷移はコマンドで操作します。 通常はData Guard(MOUNT)かActive Data Guard(OPEN READ ONLY)のどちらか片方に決め打ちして運用するので、起動手順としてはどちらもOracleインスタンス起動 → リカバリ開始になります。Oracleインスタンスの起動オプションが異なります。   まとめ 今回はData Guardフィジカル・スタンバイとその拡張であるActive Data Guardの動作原理と、手作業の場合に最低限なにを設定すればData Guardが構築できるかまでを解説しました。REDO転送モードの設定は要件に応じてマニュアルを参照してください。 Data GuardはREDO転送サービスと適用サービスの設定を行えば終わりというわけにはいきません。プライマリとスタンバイの役割の切り替え(ロール変換)などの運用を検討する必要があります。ですが今回は構築まで! 基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ  

基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ Oracle Databaseのレプリケーション機能にはいくつかありますが、障害に備えるためレプリケーション機能としてはData Guardフィジカル・スタンバイおよびその拡張であるActive Data...

もしもみなみんがDBをクラウドで動かしてみたら 第17回 課金と停止について - Autonomous Database/DBCS/ExaCS

window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-159254751-1'); もしもみなみんがDBをクラウドで動かしてみたら 連載Indexページ ※本記事は2020/02/25時点のものになります みなさん、こんにちは。 今回のテーマは、Oracle Cloud上でOracle DatabaseのPaaSサービスを利用する際に気になる、課金周りや環境の停止についてです。関連するよく聞かれることとして、「利用していない間は課金を抑えたいのですが、停止すると課金は止まりますか?」「スケーリングでOCPUを0にするのと、環境の『停止』は何が違うのですか」などがあります。実は、サービスによってこのあたりの動作や意味合いが変わってきます。そこを深堀すべく、今回はOracle Database のPaaS全サービス、Autonomous Database – Shared Infrastructure/Dedicated Infrastructure、Database Cloud Service- Virtual Machine/Bare Metal、Exadata Cloud Serviceを対象に解説していきます。 ※本記事の内容は記事執筆時の情報となります。課金周りの最新情報はこちらのドキュメントをご確認ください。 ・Oracle PaaS and IaaS Universal Credits Service Descriptions 英語版 ・Oracle Cloud Infrastructure ドキュメント 英語版 / 日本語版   各サービスの課金単位 各サービスを利用する上で、サービスごとに課金の対象や考え方が異なってきます。まずは、各サービスごとの課金に関わるコンポーネントについてまとめます。 Database Cloud Service - Virtual Machine (DBCS-VM) VMのコンピュート部分は、エディションごとにOCPU単価が異なり、利用するシェイプでOCPU数が決まります。メモリやネットワーク帯域幅などもシェイプ毎に決まります。コンピュート部分とは別に、ローカル・ストレージとしてBlock Volumeが利用されます。このBlock Volumeには、S/W用の領域(/u01=約200GB)+データベース利用領域(ASMのDATAディスク・グループとRECOディスク・グループ)が含まれます。課金対象のサイズは、データベース利用領域のサイズ(利用可能なストレージ)として選択するサイズではなく、Total Storage(総ストレージ)のサイズになるのでご注意ください。また、データベースの自動バックアップ用の領域としてObject Storageが利用されるので、ここも含めて考えましょう。 ・Oracle Cloud Infrastructure ドキュメント 英語 / 日本語 ・価格ページ  Database Cloud Service- Bare Metal (DBCS-BM) DBCS-BMは、VM同様エディションごとにOCPU単価が決まっていますが、シェイプではなく追加キャパシティとして指定する値で課金対象のOCPU数が決まります。インフラ部分はシェイプで固定になります。なお、DBCS-BMのインフラ部分にはデフォルトで2 OCPU分が含まれます。データベースの自動バックアップ用の領域には、Object Storageが利用されます。 ・Oracle Cloud Infrastructure ドキュメント 英語 / 日本語 ・価格ページ  Exadata Cloud Service (ExaCS)     ExaCSは、有効なOCPUとして指定している数がOCPU課金対象となります。このOCPUを有効にする対象は、ノード毎ではなくクラスタ全体に対して有効にするOCPUになります。例えば、コンピュートが2台作られるQuarterやBaseシェイプで"24"とした場合には、1コンピュートあたり12が割り当てられます。ストレージなどInfrastructure部分は、ExaCSのシェイプの選択で決まります。データベースの自動バックアップ用の領域には、Object Storageが利用されるので、ここも含めて考えましょう。 ・Oracle Cloud Infrastructure ドキュメント 英語 / 日本語 ・価格ページ    Autonomous Database – Shared Infrastructure (ADB-S) Autonomous Data Warehouse(ADW) /Autonomous Transaction Processing(ATP)でおなじみのShared InfrastructureのAutonomous Database(ADB-S)は、有効にするOCPUとして指定している数がOCPU課金対象となります。ストレージ部分は、実利用しているサイズではなくExadata Storageとして利用可能とするサイズが対象となります。データベースの自動バックアップ用の領域はサービス利用料金に含まれるので別途計上はされませんが、手動でバックアップを取得する場合に利用する領域はObject Storageの課金対象となります。 Autonomous Database – Dedicated Infrastructure (ADB-D) Autonomous Databaseをインフラ占有型で利用可能なDedicated Infrastructure(ADB-D)は、OCPU部分は有効にするOCPUとして指定している数の合計数がOCPU課金対象となります。ストレージなどInfrastructure部分は、利用するシェイプの選択で決まります。データベースの自動バックアップ用の領域はサービス利用料金に含まれるので別途計上はされませんが、手動でバックアップを取得する場合に利用する領域はObject Storageの課金対象となります。 ・Oracle Cloud Infrastructure ドキュメント 英語 / 日本語 ・Autonomous Data Warehouse 価格ページ / Autonomous Transactional Processing 価格ページ   課金を止めるには ・OCPUの課金 OCPUの課金に関しては、その環境に割り当てているOCPU数=利用可能なOCPU数が課金対象となります。課金を止めたいときには、DBCS-VMやAutonomous Databaseは停止することでOCPU課金も停止します。DBCS-BMやExaCSは、OCPUを0にスケールダウンすることでOCPU課金が停止します。 ・Database Cloud Service (DBCS)– VMでOCPU課金を停止する場合 ・Autonomous DatabaseでOCPU課金を停止する場合 ・Exadata Cloud Service(ExaCS)でOCPU課金を停止する場合   OCPUの課金を停止している間もストレージ上にはデータが存在=ストレージを利用していることになるので、ストレージ部分の課金は継続します。データをローカル・ストレージに保持していることのメリットは、利用するときにはデータロード不要で起動してすぐにデータを扱える状態にできることだと思います。なおAutonomous Databaseの自動スケーリングの課金の考え方は、第15回 Autonomous Databaseの自動スケーリングを設定してみようをご参照ください。 ・ローカルのストレージ/Infrastructureの課金 ストレージ部分は全サービスで共通で、システム(サービス・インスタンス)を作成してから終了するまでは課金が継続されます。そのため、ストレージの課金を止めたいときには終了=環境の削除が必要になります。その際にデータ保持が必要であれば、Object Storageなどのリモート・ストレージにバックアップを取得したり複製環境を残しておくなどして、データの退避を検討する形になります。課金を止めるのではなく抑えるという観点だと、Autonomous Database - Shared Infrastructureの場合は利用状況に応じて必要なストレージ容量を割り当てる=スケールアップ・ダウンが可能なので、ストレージをあまり使っていない状況であれば、スケール・ダウンで減額も可能です。専有型のExaCSDBCS-BMの場合は、利用シェイプによってストレージ含むInfrastructureサイズが決まり、利用可能なリソースが最初から割り当てられる=有効になるので、増減なしの固定で終了時まで課金が継続されます。注意点としては、ExaCSやAutonomous Database - Dedicated Infrastructureは48時間という最低利用期間が設けられているため、48時間未満の利用時間で削除したとしても48時間分は課金が発生します。49時間以降は、利用した分だけ=終了するまでの時間単位での課金になります。   停止とOCPUを0にスケールダウンすることとの違いは? 前述したようにOCPUの課金を止める=課金対象外としたい際に、環境の停止で出来るサービスとできないサービスがあります。この違いを一言でいうと、OCPUの割り当て対象がなにかで違います。   コンピュートやDB単位でOCPUを割り当てるサービスは、システムを停止することでOCPU課金が止まります。DBシステム全体にOCPUを割り当てるサービスは、割り当てているOCPU数を減らす(0にする)ことで課金が止まります。 たとえばExaCSはOCPUの割り当て対象はDBシステム全体に対してなので、コンソールから停止を実行(ExaCSの場合は1コンピュートの停止)しても課金は継続されるので、課金を停止したい場合には割り当てているOCPU数を減らします。DBCS-VMは、コンピュートに対してOCPUが割り当てられているので、RAC環境で片ノード(コンピュート)を停止すると、そのコンピュートの課金は停止するようになっています。 まとめ 複数サービスをご利用いただいている方だと、今回の内容のようなサービスごとの考え方の違いになれるのは、なかなか難しいかと思います。今回まとめさせていただいたように、Oracle Cloud上のOracle DatabaseのPaaSサービスは提供形態や管理体系などがサービスによって異なるため、課金周りや停止の考え方にもサービス毎に考え方が異なっています。今回の記事が、課金まわりだけでなく、サービス形態の違いを理解するうえでもご参考にしていただければ幸いです。   関連リンク ・Oracle PaaS and IaaS Universal Credits Service Descriptions 英語版 ・Oracle Cloud Infrastructure ドキュメント 英語版 / 日本語版 もしもみなみんがDBをクラウドで動かしてみたら 連載Indexページ

もしもみなみんがDBをクラウドで動かしてみたら 連載Indexページ ※本記事は2020/02/25時点のものになります みなさん、こんにちは。 今回のテーマは、Oracle Cloud上でOracle DatabaseのPaaSサービスを利用する際に気になる、課金周りや環境の停止についてです。関連するよく聞かれることとして、「利用していない間は課金を抑えたいのですが、停止すると課金は止まりますか?」「ス...

Cloud Security

DDoS保護をクラウド・プロバイダ頼みにしてはいけない

Paul Toal Distinguished Solution Engineer(Cyber Security) 分散型サービス拒否(DDoS)攻撃は昔からある攻撃で、少なくとも2000年にはその存在が確認されています。しかしDDoS攻撃とはいったいどのようなものなのでしょうか。ネット上にもその定義はさまざま掲載されていますが、端的に説明するなら、これは複数のソースから開始される攻撃で、その意図は、オンライン・サービスの処理能力を大量のデータで溢れさせ、通常のトラフィックを不可能にさせることにあります。詳しくは、こちらを参照してください。 DDoS攻撃は、企業や組織に非常に大きな混乱をもたらし得るものです。攻撃の時間は数秒から数時間までさまざまで、その対象がオンライン店舗であれ、物流企業であれ、金融機関であれ、その攻撃の間は、オンラインでのサービス提供が疎外される可能性があります。有名なオンライン・サービスに影響を与え、人々の注目を集めるような大々的なDDoS攻撃も発生しています。ここ数年はモノのインターネット(IOT)を背景として、DDoS攻撃が再び活性化しており、オンライン接続された何百万もの小型コンピュータが複数攻撃ソースの形成に利用されています。 多くの企業や組織がクラウド・サービスへ移行している現代では、そのクラウド・プロバイダでカバーされている対策範囲を理解しておくことが重要です。一部のプロバイダは、有料サービスとして、またはそのクラウド・サービスの一部として、DDoS保護を提供しています。Oracle Cloud Infrastructure(OCI)が提供する保護については、こちらでも説明されていますが、以下にその抜粋を掲載いたします。   分散型サービス拒否(DDoS)保護:次世代の「Oracle Cloud Infrastructure」の一部として、すべてのオラクル・データセンターでは、大規模およびレイヤー3/4のDDoS攻撃の検出と緩和が自動化されます。これは、攻撃が長く続く場合でもオラクル・ネットワーク・リソースの可用性を確保する上で役立ちます。   ということです。では、オラクルがDDoS保護を提供しているとすれば、OCIを利用するお客様は保護されており、それで心配はないということでしょうか。残念ながら、それで万事解決とはなりません。上記で何がカバーされているかを正確に理解するためには、DDoS攻撃への理解をもう少し深め、さまざまなタイプのDDoS攻撃を考察する必要があります。 私はDDoS攻撃について考えるとき、3つのタイプの攻撃を念頭に置きます。そしてそのすべてがサービスをオフラインにし得るものです。   DNSベースのDDoS攻撃 第1のタイプはDNSベースの攻撃です。この場合、攻撃者はDNSサーバーを溢れさせ、IPアドレスへの正規のリクエストに応答できない状態にします。たとえば私がwww.oracle.comにアクセスしようとしても、このドメインに関連付けられているDNSサーバーが私のマシンにwww.oracle.comのIPアドレスを伝えることができないため、私はこのサイトにアクセスできなくなります。この段階では、WebサイトをホストしているWebサーバーはまったく攻撃されていません。単にインターネットの電話帳を攻撃しているのみです。 アプリケーションベースの攻撃 第2のタイプは、オンラインのコンテンツやサービスをホストしているサーバーを直接攻撃するものです。どのサーバーにも、処理できるリクエストの量に限界があります。ここでの攻撃者の目的は、大量のリクエストと接続でアプリケーションを溢れさせ、正規のトラフィックに応答できないようにすることにあります。 ネットワークベースの攻撃 第3のタイプはネットワークベースの攻撃です。「DDoS攻撃」と聞いてたいていの人が思い浮かべるのもこの攻撃です。これは、ネットワーク・パイプを溢れさせるものです。攻撃者が悪意あるトラフィックを大量に送り、パイプが詰まってしまえば、適切なリクエストがそこを通れなくなってしまいます。 では、OCIはこれらの攻撃パターンのどこに対応しており、利用者とOracle Cloud Infrastructure、それぞれの責任範囲はどこまでなのでしょう。 オラクルがOCIに関連してDDoS保護について述べるとき、これはネットワークベースの攻撃、つまり多くの人がボリュームベースの攻撃と考えるものを対象としています。OCIでは、全顧客のアドレス空間全体を監視しており、大規模なボリュームベースの攻撃が確認されると、それらをブロックして悪意あるトラフィックを排除するためのツールおよびプロセスを実行します。これは、(OSI参照モデルの)レイヤー3/4で実施されます。このようにオラクルでは、OCIのすべての顧客を対象に、3つの攻撃タイプのうちの1つに標準で対応しています。しかし他の2つの攻撃タイプについては、どうでしょう。これらに対応するには、どうすればよいでしょうか。 DNSベースの攻撃に対しては、DNSプロバイダ(つまり、オラクルか否かに関係なく、プライマリDNSサービスの提供に利用しているプロバイダ)のDDoS保護能力を確認する必要があります。オラクルでは、OCIのサービスの一環として、顧客のプライマリDNSプロバイダまたはセカンダリDNSプロバイダとして利用可能なDNSサービスを用意しています。OCI DNSは、複数の大陸に戦略的に配置されている複数のデータセンターのグローバル・エニーキャスト・ネットワークで、さまざまな冗長インターネット・トランジット・プロバイダを活用して究極の回復性とDDoS攻撃からの保護を実現します。 アプリケーションベースの攻撃に対しては、アプリケーション自体を保護する対策を講じる必要があります。しかしここでも、利用できるテクノロジーやサービスがあります。OCIでは、クラウド・セキュリティ・ポートフォリオの一環として、Web Application Firewall(WAF)を提供しています。WAFは(OSI参照モデルの)レイヤー7で動作し、ボットネット、アプリケーション攻撃、およびDDoS攻撃からアプリケーションレイヤーを保護します。これは、OCIにホストされているアプリケーションだけでなく、インターネットに接続するすべてのWebアプリケーションの保護に使用できます。レートの制限やアクセス制御などの機能を使用して、DDoS攻撃からWebアプリケーションを保護することができます。実際のOCI WAFをご覧になりたい場合は、こちらにて、おもなユースケースのデモンストレーションをご覧ください。 以下は、攻撃タイプとその対策をまとめた表です。     ご覧のとおりDDoS攻撃は多面的であるため、この脅威を低減させるには、大半のセキュリティ対策と同様、多層防御戦略を講じる必要があります。すでに適切なセキュリティ対策を実施している場合も、必要な施策を現在検討中の場合も、この記事がDDoS攻撃と対策について、またもちろん、そうした対策にオラクルがお役に立てることについて、ご理解いただくためのヒントとなれば幸いです。 ※本記事は、 Paul Toal : Distinguished Solution Engineer(Cyber Security) による"Don't just rely on your Cloud Provider for DDoS protection"を翻訳したものです。

Paul Toal Distinguished Solution Engineer(Cyber Security) 分散型サービス拒否(DDoS)攻撃は昔からある攻撃で、少なくとも2000年にはその存在が確認されています。しかしDDoS攻撃とはいったいどのようなものなのでしょうか。ネット上にもその定義はさまざま掲載されていますが、端的に説明するなら、これは複数のソースから開始される攻撃で、その意図は、...

Kubernetes

GitLab CI/CDパイプラインとContainer Engine for Kubernetesを統合する

Gilson Melo Senior Principal Product Manager   オラクルのパブリック・クラウドは、オープン・ソース・テクノロジーとそうしたテクノロジーをサポートするコミュニティに対応しています。クラウド・ネイティブ・テクノロジーおよびDevOps手法へのシフトが加速するなか、当社は多くの企業や組織から、クラウド・プロバイダーによる構築か否かに関係なく、クラウドのロックインを回避し、必要な処理を実行できる、パフォーマンスと信頼性の高いクラウドを求める声に接してきました。Oracle Cloud InfrastructureでのGitLabの運用は、DevOpsプラットフォームにおいて、1つのアプリケーションでDevOpsの全ライフサイクルをカバーできる選択肢となります。 GitLab CI/CDとOracle Cloud GitLabは、単一のアプリケーションとして提供される、完全にオープン・ソースのDevOpsプラットフォームです。これにより、開発、セキュリティ、およびオペレーションの各チームによる協調的なソフトウエア構築に根本的な変革をもたらすことができます。またGitLab CI/CDパイプライン自動DevOps機能とOracle Cloud InfrastructureのContainer Engine for Kubernetesとを統合することで、クラウドにてコードを構築、テスト、デプロイ、モニターできる、信頼性と拡張性に優れた総合的なワークフロー・プラットフォームを持つことができます。 Container Engine for Kubernetesは、クラウドでのKubernetesクラスタのデプロイ、管理、および拡張を支援するサービスです。このサービスを利用することで、企業や組織はOracle Cloud Infrastructureで運用しているサービスとKubernetesとを統合して、動的にコンテナ化されたアプリケーションを構築することができます。 CI/CDワークフロー 共有リポジトリにあるチームのコードは、継続的インテグレーション(CI)により統合できます。開発者がプル・リクエストを使って新しいコードを共有すると、そのリクエストをトリガーとして、パイプラインにてコードの構築、テスト、検証が実施され、その後リポジトリにマージされます。CIは、開発サイクルの早い段階でのエラーの発見、統合上の課題の削減、構成上の問題の回避に効果的です。 継続的デリバリ(CD)は、CIで検証済みのコードが、構造化されたデプロイメント・パイプラインを通じて間違いなくアプリケーションにデリバリされるようにするものです。またCDは、各変更がリリース可能であるようにし、各リリースのリスクを低減し、より多くの価値を高い頻度で提供し、顧客から迅速かつ頻繁にフィードバックを得られるようにするものです。 こうしたCIとCDを組み合わせることで、迅速かつ効果的な構築が可能になります。この組み合わせは、開発プロセスの最適化にとって非常に重要です。 始めるには まずは、Container Engine for KubernetesにてGitLab CI/CDサービスを構築およびデプロイするために必要なコンポーネントを確認しましょう。Container Engine for KubernetesにGitLabをインストールするには、Oracle Cloud Infrastructure(OCI)とkubectlコマンド・ラインをインストールおよび設定している、デスクトップ(クラウドVMまたはオンプレミス)が必要です。 さらに、インストールを進めるには、以下のコンポーネントも必要です。 バージョン1.14.8以降のKubernetes バージョン2.14以降のHelm/Tiller ローカルの仮想クラウド・ネットワーク(VCN)セキュリティ・リストで公開されている、Kubernetesのポッドとワーカー・ノードに対応するサブネットCIDRおよびポート デプロイメント・プロセス Oracle Container Engine for KubernetesにGitLabをデプロイするには、デプロイメント・ガイドを確認し、以下のステップを実施します。 次のコマンドを実行します。その際、「example.com」の部分を実際のDNSに変更します。Helmにて別のネームスペースにGitLabのリソースをインストールしたい場合は、「--install」の後に「--namespace NEW_NAME_SPACE」を追加します。 helm repo add gitlab https://charts.gitlab.io/ helm repo update helm upgrade --install gitlab gitlab/gitlab --set externalUrl=http://gitlab.example.com \ --timeout 600s \ --set global.hosts.domain=example.com \ --set certmanager-issuer.email=me@example.com プロビジョニング・プロセスが完了したら、次のコマンドを実行してGitLabに割り当てる外部IPアドレスを指定します。 kubectl get services gitlab-nginx-ingress-controller ステップ1のDNSエントリ(例:gitlab.example.com)でGitLabを指定します。お使いのDNSゾーン管理サービスを使用して、DNSレコード・エントリを更新します。これを実施しないと、ステップ5にて「default backend - 404」というエラー・メッセージが表示されます。404エラー・メッセージが表示された場合は、DNSエントリを修正して、GitLab Runnerポッドを再作成します。 DNSゾーン・レコードが作成されたら、次のコマンドを使用して、ダッシュボードでの接続に必要なbase64ルート・パスワードを取得します。 kubectl get secret <name>-gitlab-initial-root-password -ojsonpath='{.data.password}' | base64 --decode ; echo " すべてのポッドが稼働するまで待ち、その後次のステップに進みます。以下のスクリーンショットは、Helmを通じてインストールされるポッドの一覧になります。 ブラウザを開き、DNSアドレスを入力し、その後にrootのユーザー名とbase64パスワードを使用します。 既存のContainer Engine for Kubernetesクラスタ情報をGitLabに追加します。Admin Areaメニューにて「Kubernetes」を選択し、「Add Kubernetes cluster」に続いて「Add existing cluster」タブをクリックし、次の情報を入力します。 Name:~/.kube/configファイルにあるクラスタ名を入力します。 Environment scope:「*」を入力します。 API URL:次のコマンドを実行してAPI URLを取得します。 kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}' CA Certificate:kubectl get secretsを実行します。リスト化されたsecretの1つに「default-token-xxxxx」に類似した名前があるはずです。そのトークン名をコピーし、次のコマンドに使用します。次のコマンドを実行して証明書を取得します。 kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode Token:GitLabでは、特定のネームスペースに対してスコープされるサービス・トークンを使用して、Kubernetesの認証を実施します。使用されるトークンは、クラスタ管理者権限を持つサービス・アカウントに属している必要があります。このサービス・アカウントを作成するには、次の手順を実行します。 次の内容にて、gitlab-admin-service-account.yamlという名前で、ファイルを作成します。 apiVersion: v1 kind: ServiceAccount metadata: name: gitlab-admin namespace: kube-system --- apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: gitlab-admin roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: gitlab-admin namespace: kube-system 次のコマンドを実行して、このサービス・アカウントとクラスタのロール・バインディングをクラスタに適用します。 kubectl apply -f gitlab-admin-service-account.yaml 結果は次のとおりです。 serviceaccount "gitlab-admin" created clusterrolebinding "gitlab-admin" created Gitlab管理者サービス・アカウント用のトークンを取り出します。 kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}') 「Add Kubernetes Cluster」をクリックします。インスタンス・クラスタが追加されます。 インスタンス・クラスタにて、次のコンポーネントをインストールします。 Helm Tiller Ingress Cert-Manager Prometheus GitLab Runner Ingressがインストールされると、新しいパブリックのOracle Cloud Infrastructureロードバランサがプロビジョニングされます。 UIに提示されているとおりにベース・ドメインをロードバランサのパブリックIPアドレスに変更し(例:OCI_Public_IP.nip.io)、「Save Changes」をクリックします。詳しくは、GitLabのドキュメントを参照してください。 以上です。これで、GitLab CI/CDパイプラインのインストールとContainer Engine for Kubernetesとの統合が完了しました。ここからは、GitLab CI/CDのワークフローのテストに移ります。 Oracle Cloud InfrastructureレジストリにてGitLab CI/CDパイプラインを使用 ここでは例として、GitLab CI/CDワークフローを使用して、プライベートOracle Cloud Infrastructureのレジストリ・リポジトリからイメージをプルし、これを再構築し、新しいビルド名にてレジストリにプッシュ・バックする方法を紹介します。 レジストリ・リポジトリにプライベート・イメージがある場合は、次のステップまでスキップしてください。プライベート・イメージがない場合は、Dockerイメージを作成してプライベート・レジストリ・リポジトリにこれをアップロードし、KubernetesのSecretを作成します(Secret情報には、レジストリのユーザー名とパスワードを使用します)。これらのステップについては、次のチュートリアルを参照してください。 Push an Image to Oracle Cloud Infrastructure Registry Pull an Image from Oracle Cloud Infrastructure Registry when Deploying a Load-Balanced Application to a Cluster 次の変数をGitLabに追加します。「Settings」 > 「CI/CD」の順に進み、「Variables」を開いて、次の変数のキーと値を追加します。 OKE_REGISTRY:レジストリ・リージョンのエンドポイント(例:iad.ocir.io) OKE_REGISTRY_IMAGE:レジストリ・イメージ(例:iad.ocir.io/tenancy_name/imagename:build) OKE_REGISTRY_NEW_IMAGE:ビルド・プロセスの後にレジストリにプッシュされる、レジストリ・イメージの新しいビルド・バージョン(例:iad.ocir.io/tenancy_name/imagename:new_image) OKE_REGISTRY_PASSWORD:Oracle Cloud Infrastructureの認証トークン詳しくは、こちらのドキュメントを参照してください。 OKE_REGISTRY_USER:Oracle_Cloud_Infrastructure_tenancy_name/usernam 内部のブランク・プロジェクトを作成します(例:gitlab-docker-ocir-oke)。 新しいファイルを2つ(「Dockerfile」と「.gitla-ci.yml」)作成します。これらは、GitLabをContainer Engine for Kubernetesおよびレジストリで運用するための基本的な例にすぎません。実際に作成する際は、必要に応じて修正してください。 .gitlab-ci.yml docker-build-master:   # Official docker image.   image: docker:latest   stage: build   services:     - name: docker:19.03.0-dind       entrypoint: ["env", "-u", "DOCKER_HOST"]       command: ["dockerd-entrypoint.sh"]   variables:     #CI_DEBUG_TRACE: "true"     DOCKER_HOST: tcp://localhost:2375/     DOCKER_DRIVER: overlay2     DOCKER_TLS_CERTDIR: ""   before_script:     - docker login -u "$OKE_REGISTRY_USER" -p "$OKE_REGISTRY_PASSWORD" $OKE_REGISTRY   script:     - docker info      - docker build  --pull -t "$OKE_REGISTRY_IMAGE" .     - docker tag "$OKE_REGISTRY_IMAGE" "$OKE_REGISTRY_NEW_IMAGE"     - docker push "$OKE_REGISTRY_NEW_IMAGE"   only:     - master   docker-build:   # Official docker image.   image: docker:latest   stage: build   services:     - docker:19.03.0-dind   before_script:     - docker login -u "$OKE_REGISTRY_USER" -p "$OKE_REGISTRY_PASSWORD" $OKE_REGISTRY   script:     - docker info     - docker build  --pull -t "$OKE_REGISTRY_IMAGE" .     - docker tag "$OKE_REGISTRY_IMAGE" "$OKE_REGISTRY_NEW_IMAGE"     - docker push "$OKE_REGISTRY_NEW_IMAGE"   except:     - master Dockerfile FROM nginx VOLUME /usr/share/nginx/html これらのファイルを作成し、保存すると、GitLab Auto DevOpsによりパイプラインがトリガーされます。これにより、レジストリ・イメージがプルされ、新しいイメージが作成され、名前「$OKE_REGISTRY_NEW_IMAGE」を使用してそのイメージがタグ付けされて、レジストリにプッシュされます。 レジストリ・ダッシュボードを更新すると、新しいイメージが表示されます。   セットアップとテストは以上です。これで、GitLab CI/CDパイプラインのデプロイとContainer Engine for Kubernetesおよびレジストリとの統合が完了しました。 まとめ Container Engine for KubernetesとGitLab CI/CDの統合ワークフローとを組み合わせることで、本番対応の堅牢かつ拡張性の高いDevOpsプラットフォームを獲得できます。詳細については、「Container Engine for Kubernetesの概要」およびGitlabのWebサイトを参照してください。Container Engine for KubernetesでのGitlabの運用を体験したい場合は、Oracle Cloud Infrastructureのアカウントを取得していただければ、すぐにテストを開始できます。 ※本記事は、Max Verun (Principal Product Manager)による"Using the GitLab CI/CD Pipelines Integrated Workflow To Build, Test, Deploy, and Monitor Your Code with Container Engine for Kubernetes and Registry"を翻訳したものです。

Gilson Melo Senior Principal Product Manager   オラクルのパブリック・クラウドは、オープン・ソース・テクノロジーとそうしたテクノロジーをサポートするコミュニティに対応しています。クラウド・ネイティブ・テクノロジーおよびDevOps手法へのシフトが加速するなか、当社は多くの企業や組織から、クラウド・プロバイダーによる構築か否かに関係なく、クラウドのロックインを...

Always Free

Oracle Databaseを始める5つの方法

Gerald Venzl Master Product Manager Oracle Databaseを触ってみたいけれど、どう始めたらいいか分からない?この記事で5つの方法をご紹介します。 LiveSQL ひとまず便利なSQLをいくつか作成して、データベースにそのとおり実行させたい、と思っていますか。そうであれば、LiveSQL.oracle.comがお役に立ちます。LiveSQLはブラウザベースのSQL作成ツールで、SQLのすばらしさをいくつか体験できるだけではなく、作成したスクリプトを保存して、他の人と共有することもできます。チュートリアルとサンプルの総合的なライブラリもあります。Oracle Databaseの使用経験がまったくなく、これから始めてみようとする人なら誰でも、LiveSQLを気に入るでしょう。 Dockerイメージ Oracle Databaseを自分のマシンに入れたいが、セットアップや構成に頭を悩ませるのは遠慮したいという場合は、オラクルが提供しているDockerイメージが便利です。自分のマシン(MacかWindows)にDockerをインストールし、オラクルのDocker GitHubリポジトリからイメージを1度作成すれば、残りの作業はDockerが引き受けてくれます。その後覚えておく必要があるのは、これだけです。 docker run -name oracle -p 1521:1521 oracle/database:19.3.0-ee と、 docker start oracle Dockerは、ご使用のマシン上でOracle Databaseの1つまたは多数のインスタンスおよびバージョンを実行するのに適しています。運用(開始/停止/セットアップ)方法に関する知識がなくても問題ありません。その場合でも、Oracle Databaseの全機能を使用できます。 Vagrant Box VM Oracle Databaseを自分のマシンに入れたいが、仮想マシンの内部で実行したいという場合は、オラクルが提供するVagrantスクリプトが非常に役立ちます。HashiCorpのVagrantは、VirtualBox VMなどのVM環境を繰り返しプロビジョニングする場合に便利です。まず、ご使用のマシンにオラクルのVirtualBoxとHashiCorpのVagrantをインストールします。インストールが完了したら、Oracle Vagrant Boxes GitHubリポジトリからスクリプトを使用してVMをプロビジョニングすれば、あとはVagrantがすべてやってくれます。その後覚えておく必要があるのは、これだけです。 vagrant up と、 vagrant ssh Oracle Databaseを含むVirtualBox VMをスクリプトで作成し、繰り返し使用したい場合は、Vagrant Boxが適しています。Oracle Databaseのさまざまなバージョンがインストールされた、複数のVMをプロビジョニングすることもできます。VMではポート転送がデフォルトで有効になっています。つまり、ご使用のホストから直接、どのツールにでも接続できます。たとえば、Oracle SQL DeveloperからVM内部のデータベースに接続して、VMを小さな組込みサーバーのように扱うことができます。 Database Application Development VM VMを使用したいが、Vagrantの複製機能は使いたくない、または使う必要がない場合は、Oracle Database Application Development VMがぴったりです。.ovaファイルをダウンロードし、VirtualBoxにインポートして、VMを起動するだけです。VMが起動して、Linuxのグラフィカル・デスクトップが表示されます。 Oracle Database Application Development VMには、SQL DeveloperやOracle REST Data Servicesなどのツールがあらかじめインストールされているため、VMにとって必要なものが1か所ですべてそろう、優れたツールであると言えます。こちらもデフォルトでポート転送が有効になっており、ホストから直接ツールに接続できます。Application Development VMのもう1つの利点は、ハンズオン・ラボがいくつか用意されていることです。これを利用して、ひととおり試してみることができます。 Always Free Oracle Autonomous Database Oracle Databaseを使いたいが、自分のラップトップ上に置きたくはないという場合は、Always Free Oracle Autonomous Databaseが含まれるOracle Cloud Free Tierを検討してみてください。Free Tierにサインアップし、Always Free Autonomous Databaseをプロビジョニングすれば、Oracle SQL Developer Webを使用できるようになります。 オラクルによる最新かつ最高のクラウド・データベースを体験したいならば、Always Free Oracle Autonomous Databaseがベストな選択肢です。SQL Developer WebとOracle Application Express(APEX)がすぐに使えるようになっているため、インターネット・アクセスさえあれば、世界中のどこからでも、他のアプリやIDEに接続できます。そして最高にすばらしいのは、ユーザーがデータベースを必要とする限り、無期限で利用できることです。 さあ、手をこまねいている時間はありません。Oracle Databaseをさっそく使ってみてください! ※本記事は、Gerald Venzl (Master Product Manager)による"5 ways to get an Oracle Database"を翻訳したものです。

Gerald Venzl Master Product Manager Oracle Databaseを触ってみたいけれど、どう始めたらいいか分からない?この記事で5つの方法をご紹介します。 LiveSQL ひとまず便利なSQLをいくつか作成して、データベースにそのとおり実行させたい、と思っていますか。そうであれば、LiveSQL.oracle.comがお役に立ちます。LiveSQLはブラウザベースのSQ...

Java Magazine February 2020

  2020年2月 Java 13のswitch式と再実装されたSocket APIの内側 著者:Raoul-Gabriel Urma、Richard Warburton 段階的変更により、将来のメリットが今回のリリースに含まれるように   Javaにテキスト・ブロックが登場 著者:Mala Gupta 長く待ち望まれてきた複数行文字列がJava 13で実現   言語の内側:シールド型 著者:Ben Evans パターン・マッチング、列挙型およびswitch文の改善に向けて進化するJava TeaVMを使ってブラウザでJavaを動かす 著者:Andrew Oliver Javaをフロントエンドとバックエンドの両方に使ってWebアプリを構築する   ツールをよく知る 著者:Andrew Binstock 偉大なプログラマーは皆、主要ツールについての深い知識を持っている。ツールのエキスパートでないなら、必要な時間をかけること。その手はじめはここから   クイズに挑戦:1次元配列(中級者向け) 著者:Simon Roberts、Mikalai Zaikin コンストラクタを使って配列を作成する際の微妙な違い   クイズに挑戦:カスタム例外(上級者向け) 著者:Simon Roberts、Mikalai Zaikin 例外の宣言が必要になる正確な条件   クイズに挑戦:ロケールの読取りと設定(上級者向け) 著者:Simon Roberts、Mikalai Zaikin ユーザーの満足のために、正確なロケール設定を細   クイズに挑戦:関数型インタフェース(上級者向け) 著者:Simon Roberts、Mikalai Zaikin ストリームにおけるボクシングおよびアンボクシングの難解さ

  2020年2月 Java 13のswitch式と再実装されたSocket APIの内側 著者:Raoul-Gabriel Urma、Richard Warburton 段階的変更により、将来のメリットが今回のリリースに含まれるように   Javaにテキスト・ブロックが登場 著者:Mala Gupta 長く待ち望まれてきた複数行文字列がJava 13で実現   言語の内側:シールド型 著者:Ben...

クイズに挑戦:関数型インタフェース(上級者向け)

code { font-family: courier,"courier new",monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } ストリームにおけるボクシングおよびアンボクシングの難解さ 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 この設問では、プリミティブ版の関数型インタフェースを使うコードを作成したいと思います。 次のコードについて: DoubleStream ds = DoubleStream.of(1.0, 2.0, 3.0); … // line n1 System.out.print(ds.map(fun.apply(1.0)).sum()); line n1に追加することで、ストリームがもっとも効率よく処理され、コンソールに 9.0 が出力されるコードはどれですか。1つ選んでください。 Function<Double, DoubleUnaryOperator> fun = a -> d -> d + a; DoubleFunction<DoubleUnaryOperator> fun = a -> d -> d + a; DoubleFunction<DoubleFunction<Double>> fun = a -> d -> d + a; Function<Double, DoubleFunction<Double>> fun = a -> d -> d + a; 解答:この設問では、複数のトピックを扱っています。1つはプリミティブ・データタイプとJavaのジェネリクス・メカニズムとの相互作用、もう1つは複雑な関数型どうしのマッチングです。  まずは、最初のトピックの概要を見ていくところから始めます。Javaのジェネリクス・メカニズムは、オブジェクト型にのみ対応しています。すなわち、任意のSomethingについてList<Something>を定義できるのは、Somethingが何らかのObject型である場合に限られます。List<int>や、他のプリミティブタイプのListを定義することはできません。 この不便さを緩和するために、Javaのラッパー型を使うことができます。そのため、たとえばList<Integer>というような宣言を行うことができます。さらに、このようにジェネリックを扱う場合のほとんどで(ただし、常にというわけではありません)コンパイラのオートボクシングとアンボクシングの機能が働くため、オブジェクトとプリミティブとの相互変換を行うコードを明示的に書かずにプリミティブタイプを処理することができます。したがって、次のコードは問題なく動作します。 List<Integer> li = new ArrayList<>(); li.add(99); int ninetyNine = li.get(0); しかし、実際にコンパイラが生成するのは、次の形式と同等のコードです。 List<Integer> li = new ArrayList<>(); li.add(Integer.valueOf(99)); int ninetyNine = ((Integer)li.get(0)).intValue(); この2番目の形式には、見えないCPU負荷がかなりかかっている点に注意してください。 ここでは、Integerオブジェクトの生成と初期化(または、これまでに生成されたオブジェクトのプールから既存のIntegerを探す作業)が行われています。さらに、キャストも行われています。このキャストは、実際にはget(0)の戻り値に対して行われ、intValueメソッドを呼び出してプリミティブの結果を抽出しています。 通常、このCPUオーバーヘッド全体は、ソースコードの可読性(およびその結果としての保守性)改善との引き換えとなる妥当なトレードオフです。ただし、このようなトレードオフが発生すると知っておくことは重要です。パフォーマンスの低下が度重なり、このトレードオフを許容できないこともあるからです。いずれにせよ、パフォーマンスの低下が許容範囲である場合でも、この処理は常に、設問の言葉を使うなら、「あまり効率的でない」と言えます。 次に、Listなどのデータ構造を定義する場合、このボクシングおよびアンボクシングの処理を避けるのは結構難しく、通常はトレードオフが生じるだけの価値はあります。ただし、大量の計算を行っている場合、ジェネリクスではプリミティブを扱えないという制限に直面する可能性もあります。1つの入力を受け取り、1つの結果を生成する処理を定義したい場合を考えてみます。これは一般的なjava.util.function.Function<E,F>であり、操作の入力がE型、結果がF型です。ここで、この操作を使ってdouble値に対する計算を行いたいものとします。次のようなコードを試されるかもしれません。 Function<Double, Double> fdd = in -> in + 2.0; 残念ながら、これで作成されたのはDoubleオブジェクトを受け取る関数です。この関数からコンパイラは、2.0を加算する前にラッパー・オブジェクトからdoubleプリミティブを抽出するコードを生成し、その結果に対してDoubleオブジェクト・ラッパーを適用するコードを生成します。このような変換によるオーバーヘッドは、単純にdoubleプリミティブに2.0を加算する処理に比べれば膨大です。この変換機能が繰り返し使われた場合、トレードオフを許容できなくなる可能性ははるかに高くなります。 以上の制限を踏まえ、こういったボクシングおよびアンボクシングを一切行わないことで効率向上を実現するという明確な目標のもと、関数型インタフェースとStream API(およびJava 8における関数型機能のその他の要素)では、直接プリミティブを扱う特別なバージョンを提供しています。 先ほどの例に関連する機能を以下に示します。 DoubleStream:doubleプリミティブのデータを扱うことを目的としたストリーム概念 java.util.function.DoubleFunction<E>:1つのdoubleプリミティブ引数を受け取り、E型のオブジェクトを返すメソッドを定義する関数型インタフェース java.util.function.DoubleUnaryOperator:1つのdoubleプリミティブ引数を受け取り、doubleプリミティブの結果を返すメソッドを定義する関数型インタフェース これに類する機能は他にも多く提供されていますが、この設問に直接関係するのは、上に挙げた3つです。 設問の最初の重要な要素を満たすためには、ボクシングとアンボクシングを回避するか、または少なくとも最低限にとどめる答えを見つける必要があります。ボクシングとアンボクシングの処理が行われることで、設問で要求されている、効率が低下するからです。与えられたコードでは、DoubleStreamを直接作成しています。DoubleStreamはプリミティブ版のストリームであり、double値を直接扱うことから、効率に関する条件は満たされています。したがって、以降の処理で、値がプリミティブのまま扱われることを確認しなければなりません。そのためには、プリミティブを扱う関数型インタフェースが使われていることを確認する必要があります。 その他の背景についても考えてみます。すべての選択肢で、変数funを定義しようとしていることがわかります。このfunは、ds.map(fun.apply(1.0)).sum()という式のストリーム処理で使われています。 map操作では、上流ストリームの型の各項目を受け取り、指定された処理操作(これは1つの結果を生成する必要があります)を実行して、その処理操作が返す型のストリームを生成します。ここから、操作に必要ないくつかの要件を特定できます。さらにそこから、funの型と動作に必要な要件を特定できます。 funは、マップに適用される操作ではない点に注意してください。そうではなく、式fun.apply(1.0)を評価すると、map操作によって実行される操作が作成されます。言い換えるなら、fun自体は操作ではなく、動作のファクトリのようなものです。 ここではわかりやすさを優先し、mapが使うこの動作を単に「操作」と呼ぶことにします。この操作では、入力としてdoubleプリミティブを受け取り、結果としてdoubleプリミティブを生成しなければなりません。どうすればこれを実現できるでしょうか。純粋に論理的に推論すれば、map操作の入力と、上流ストリームの型との間に代入互換性がなければならないことがわかります。今回の場合、上流ストリームの型はdoubleです。そのため、doubleは動作し、Doubleもおそらく動作しますが、Doubleにはオートボクシングが必要となり非効率であるため、使うべきではありません。 それでは、下流ストリームの型はどうでしょうか。map操作では常に新しいストリームを生成します。また、sum()操作はプリミティブ・ストリームのみに存在します。いずれにせよ、Automobileオブジェクトのリストを足し合わせて1つのAutomobileを表す結果を生成することはできません。したがって、結果の値はプリミティブタイプでなければならず、doubleが自明の選択であることがわかります。実際には、APIを使ってdoubleプリミティブのストリームをintプリミティブやlongプリミティブのストリームにマップすることはできますが、この変更を行うためには、mapToIntメソッドやmapToLongメソッドが必要です。そのため、明らかにこの型であるという十分な確信を持てず、「設問に他の選択肢がないことからdoubleである」という推測に満足しない場合でも、前述の事実から確実にわかります。 つまり、操作の型は、1つのdouble引数を受け取り、doubleの結果を返すものでなければなりません。これは、DoubleUnaryOperatorインタフェースで定義されている動作です。 ここで、APIを詳細まで理解している方なら、DoubleStreamに対するmapの引数の型はDoubleUnaryOperator以外にないことはご存じでしょう(この設問では、このことを知っていなくても、論理的に考えればわかります)。しかし、重要なことは、これがオートボクシングが対処しない状況の1つであることです。Function<Double, Double>、DoubleFunction<Double>、ToDoubleFunction<Double>はいずれもDoubleUnaryOperatorとの互換性があるはずだと思うかもしれませんが、そうではありません。ここでは、DoubleUnaryOperatorを指定しなければなりません。  それでは、funの型はどうでしょうか。その型が何であれ、double引数(またはオートボクシングが適用されるDoubleも考えられますが、このバージョンは可能であれば避けたいということはわかっています)を受け取り、map操作で使われるDoubleUnaryOperatorを返す動作が実現されていなければなりません。 入力としてdoubleプリミティブを受け取り、オブジェクト型を返す関数はDoubleFunction<E>と呼ばれています。Eは戻りタイプを表します(逆に、引数としてEを受け取り、doubleプリミティブを返す関数はToDoubleFunction<E>です)。これを考えれば、funを実現する効率的な型はDoubleFunction<DoubleUnaryOperator>であることがわかります。この型は、選択肢Bで宣言されているものと一致しています。そこで、この選択肢の動作と、適切な出力が行われるかどうかを考えてみます。 選択肢Bにあるfunの定義のもとでfun.apply(1.0)を呼び出すと、double引数を受け取ってその引数に1を加算したものを返す関数が作成されます。このコードを実行すると、map操作の結果はストリーム・データ2.0、3.0、4.0(対応する入力のそれぞれに1を加算した数字)になり、その合計が要件どおりの9.0になることがわかります。この宣言が最大限に効率化されていることはわかっているため、選択肢Bが正解だと判断して差し支えありません。しかし念のため、他の選択肢はうまく動作しないか、または効率が低いことを確認してみます。 選択肢Aのfunでは、同じ論理計算が宣言されていますが、最初の入力にdoubleプリミティブではなくDoubleオブジェクトを受け取ると宣言されています。結果の関数が、引数に1.0を加算するDoubleUnaryOperatorである点は変わりません。そのため、コードはコンパイルでき、結果も9.0になります。ただし、ボクシング操作によって選択肢Bよりも効率が低いことは明らかであるため、選択肢Aは誤りです。 選択肢Cと選択肢Dではいずれも、DoubleFunction<Double>に関して定義されている操作のファクトリを定義しています。DoubleFunction<Double>は、引数としてdoubleプリミティブを受け取り、結果としてDoubleオブジェクトを返す関数を宣言します。そのため、これはコンパイルできると考える方もいらっしゃるかもしれません。しかし、たとえコンパイルできたとしても、選択肢Bよりも効率が低いことは明らかです。そのため、この段階でいずれの選択肢も誤りであることがわかります。ただし前述のように、オートボクシングのメカニズムでは、doubleとDoubleを相互に変換することはできますが、引数としてDoubleを受け取る関数を、引数としてdoubleを受け取る関数に変換することはできません。これは、単なるボクシングおよびアンボクシングの操作ではなく、関数型の変換です。その結果、選択肢CおよびDはコンパイルできないため、いずれも誤りです。 正解は選択肢Bです。   Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 Javaにテキスト・ブロックが登場 言語の内側:シールド型 TeaVMを使ってブラウザでJavaを動かす ツールをよく知る クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。 ※本記事は、Simon Roberts、Mikalai Zaikinによる”Quiz Yourself: Functional Interfaces (Advanced)“を翻訳したものです。

ストリームにおけるボクシングおよびアンボクシングの難解さ 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験...

クイズに挑戦:ロケールの読取りと設定(上級者向け)

code { font-family: courier,"courier new",monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } ユーザーの満足のために、正確なロケール設定を 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 この設問では、Localeオブジェクトを使用してロケールの読取りと設定を行いたいと思います。  次のうち、正しい選択肢はどれですか。1つ選んでください。 Localeは国と言語の両方を表すことができる Localeを作成するとき、国は必ず指定しなければならない 言語は必ず2文字で表される Localeクラスでは、Localeの新しいインスタンスを作成するのではなく、事前定義されたstatic final定数を常に使うことができる 解答:java.util.Localeクラスでは、地理的、言語的、政治的、および文化的な好みの設定を表しますが、こういった側面のすべてが必要となるわけではありません。ユーザーのニーズと好みの設定に応じて、ソフトウェアでは最適なものを提供できるようにするという考え方です。 たとえば、大半のユーザーは、ユーザー・インタフェースが第一言語または少なくとも自分が理解する言語で提示されることは絶対要件だと考えるでしょう。しかし、日付の年月日の要素が、ユーザーの国で一般的に使われる形式とは違う順序で表示されたとしても、そのソフトウェアを使おうと思ってくれるかもしれません。 その点を考えれば、JavaのLocaleオブジェクトの要素には優先順位が付けられており、言語の優先順位がもっとも高く、地域の優先順位は言語よりも低くなっている点に驚くことはないでしょう。 Localeクラスには、3つのコンストラクタがあります。1つ目は言語のみ、2つ目は言語および国、そして3つ目は、言語および国に加えてvariant要素が必須になっています。コンストラクタを以下に示します。 Locale(String language) Locale(String language, String country) Locale(String language, String country, String variant) ここまでの説明で、2つの重要なポイントに注意してください。 まず、Localeでは言語および国の両方(とさらに別の情報)を表すことができるという点です。そのため、選択肢Aは正解です。 次に、言語は優先順位がもっとも高い要素で、どのコンストラクタでも省略できないものの、地域は二次的要素であり省略できるという点です。Localeの性質を理解すれば(API機能についての知識も参考になるでしょう)、選択肢Bは誤りであることがわかります。 通常、言語は小文字2文字を使って表されます。しかし、標準(厳密に言えば、IETF BCP 47およびISO 639)とAPIドキュメントには、3文字も可能であることが記されています。3文字タグは珍しいですが、APIドキュメントではkok(コンカニ語)が例として挙げられています。さらに、サブタグでは8文字まで拡張することもできます。以上より、選択肢Cは誤りであることがわかります。 コンカニ語は、インドで約700万人が話している言語です。 設問に含まれるこの要素が、知識の丸暗記という、かなり疑わしいカテゴリに入るものであることには注目すべきです。私たちも、試験の作成者も、このような設問は好みません。率直に言えば、このトピックについての設問を、単なる事実に基づかずに作成するのはかなり難しいことです。しかし、Localeの性質と使用方法について十分実務的に理解していれば、即座に完全な自信を持って選択肢Aを選ぶことができ、他の選択肢について悩む必要はないはずです。事実そのものについての知識が必要と思われるさまざまな状況で、このようなことはよくあります。 Java 8のリリースによって、コンストラクタをパブリックAPIの一部として公開することは、多くの場合、あまりよい方法ではないという認識が広がりました。コンストラクタはオブジェクトを作成する際に必要であり、クラスの継承を使いたい場合は、privateでないコンストラクタが必要になります。しかし、パブリックAPIの一部として考えた場合、一般的に言って、コンストラクタをお勧めできないいくつかの理由があります。 その理由の1つに、newの呼出しによって、新しいオブジェクトまたは例外のいずれかしか得られないことが挙げられます。つまり、プールの中にあるオブジェクトを渡すことはできません。現在、Java(または参照ベースの任意の言語)で可変オブジェクトをプールすることは、ほとんどすべての場合において適切ではありません。しかし、可能な値がほどよい範囲である不変オブジェクトをプールしておくことは合理的で、ますます一般的なAPI機能になっています(「実行時に拡張可能な列挙型」を考えてみてください)。 不変オブジェクトの不必要な複製を最低限に抑える方法の1つとして、事前定義された定数を提供するというものがあります。Localeクラスでは、およそ8つの国およびそのバリエーションのいくつかについて、この方法がとられています。しかし、対象となっているすべての国からはほど遠く、すべての組合せにはとても及びません。そのため、選択肢Dは誤りです。 正解は選択肢Aです。   Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 Javaにテキスト・ブロックが登場 言語の内側:シールド型 TeaVMを使ってブラウザでJavaを動かす ツールをよく知る クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。 ※本記事は、Simon Roberts、Mikalai Zaikinによる”Quiz Yourself: Read and Set the Locale (Advanced)“を翻訳したものです。

ユーザーの満足のために、正確なロケール設定を 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類で...

クイズに挑戦:カスタム例外(上級者向け)

code { font-family: courier,"courier new",monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } 例外の宣言が必要になる正確な条件 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 この設問では、カスタム例外を作成したいと思います。 次のコードについて: class UnknownException extends Error {} class BusinessException1 extends Exception {} class BusinessException2 extends Exception {} class Application { public Object doId() /* point n1 */ { // line n2 } } 次に示す一連の追加を行った場合(それぞれの追加は独立して行うものとします)、正常にコンパイルできるのはどれですか。3つ選んでください。 point n1に:throws BusinessException2 line n2に:return "Hi"; point n1に:何も追加しない line n2に:throw new UnknownException() point n1に:throws Exception line n2に:throw new BusinessException1() point n1に:throws BusinessException1 line n2に:throw new BusinessException2() point n1に:throws BusinessException1 line n2に:throw new Exception() 解答:Javaでは、例外をチェック例外および非チェック例外という2つの大きなカテゴリに分類しています。ただし、JVMでは異なります(後で補足として説明します)。非チェックのカテゴリはさらに大きく2つに分けることができますが、設問とは無関係であることから、その点についてここでは触れません。 説明に補足を入れるのは少し早いですが、これは厄介な問題であるため、早く片付けてしまいます。「JVMでは異なります」というただし書きはどういう意味でしょうか。最初に言っておきますが、気にしないのであれば知る必要はありません。ただし、背景知識としては興味深いものかもしれません。Javaプログラムでは、チェック例外をスローする可能性があるコードを含むメソッドは、その事実を宣言しなければなりません。また、Java言語のルールのほとんど(アクセス可能性や代入の互換性など)は、クラス・ローダーがバイトコードに強制しています。しかし、チェック例外のルールは違います。バイトコードから見れば、すべての例外は等しいもので、どの例外でもいつでも宣言なしにスローすることができます。 java.lang.Throwableクラスは、スロー可能なもののベース・クラスで、java.lang.Errorおよびjava.lang.Exceptionという2つのサブクラスがあります。Exceptionには、java.lang.RuntimeExceptionというサブクラスがあります。Javaでは、ErrorでもRuntimeExceptionでもないすべてのThrowableはチェック例外です。 つまり、この2つのクラスとそのサブクラスは非チェック例外で、それ以外のすべてはチェック例外です。以上を踏まえると、UnknownExceptionはErrorのサブクラスであることから非チェック例外であり、BusinessException1とBusinessException2はいずれもチェック例外であることがわかります。 ところで、Javaでは、非チェック例外をスローすることについて、何の制約も課していません。つまり、非チェック例外は、メソッドがその非チェック例外をスローする可能性があるかないかにかかわらず、また、非チェック例外のスローが可能であるかないかにかかわらず、宣言しても宣言しなくても構いません。 対照的に、メソッドがコール元にチェック例外をスローできるのは、throws句でその可能性を宣言している場合に限られます。メソッドのthrows句では、スローされる可能性がある実際の例外の親を宣言するだけで十分です。子の例外は親の例外型のインスタンスであるからです。  さらに、特定の例外を列挙するthrows句は、単にそのメソッドがその例外をスローできるようにしているだけで、必ずそのメソッドがその例外をスローしなければならないということではありません。ほとんどの例外は特別な状況でスローされることから、例外が発生しない可能性もあることは明らかです。しかし、メソッドでその例外がスローされる可能性がまったくなくても構いません。例外の宣言は、将来的な変更のためや、オーバーライドするメソッドがその例外をスローできるようにするために行うことも可能です。 それでは、選択肢を確認していきます。 選択肢Aでは、チェック例外を指定したthrows句を宣言していますが、メソッドの本体でその例外がスローされる可能性はありません。先ほど触れたように、これは問題ないため、選択肢Aは正解です。 選択肢Bでは、UnknownExceptionをスローしています。これは実際にはErrorのサブクラスです(あまりよい名前ではありません)。しかし、ここでさらに重要なのは、この例外が非チェック例外であることです。 非チェック例外であるため、throws句で宣言されていてもいなくても問題ありません。つまり、選択肢Bも正解です。 選択肢Cでは、特定のチェック例外BusinessException1をスローしていますが、Exceptionをスローすると宣言しています。前述のように、BusinessException1はExceptionである(is-a関係)ため、これは問題ありません。なお、選択肢AおよびBとは異なり、この場合はthrows句を省略することはできません。したがって、選択肢Cも正解です。 選択肢Dではチェック例外BusinessException2をスローしていますが、BusinessException1をスローすると宣言しています。このthrows句は問題ありませんが、兄弟関係にあたる例外をスローできるようにするためには、これでは不十分です。十分簡単なことですが、ここで問題になるのは、2つのBusinessException型に、似たような名前と共通の親を持つということ以外には何の関係もないことです。そのため、この場合、メソッドはthrows句で宣言されていないチェック例外をスローすることになり、選択肢Dは誤りです。 選択肢Eも、選択肢Dと本質的に同じ理由で失敗します。すべてのBusinessException1はExceptionです(is-a関係)が、継承関係は一方向であるため、ExceptionはBusinessException1ではありません。したがって、スローされる可能性がある例外に対してthrows句が不十分であるため、選択肢Eは誤りです。 正解は選択肢A、B、Cです。   Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 Javaにテキスト・ブロックが登場 言語の内側:シールド型 TeaVMを使ってブラウザでJavaを動かす ツールをよく知る クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。 ※本記事は、Simon Roberts、Mikalai Zaikinによる”Quiz Yourself: Custom Exceptions (Advanced)“を翻訳したものです。

例外の宣言が必要になる正確な条件 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、...

クイズに挑戦:1次元配列(中級者向け)

code { font-family: courier,"courier new",monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } コンストラクタを使って配列を作成する際の微妙な違い 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 この設問では、1次元配列を宣言してインスタンス化し、初期化して使用したいと思います。 次のコード・ブロックについて: int[] ia = new int[2]; ia[1] = 1; for (int v : ia) System.out.print(v + " "); String[] sa = new String[2]; sa[0] = "Hi"; for (String v : sa) System.out.print(v + " "); // line n1 どのような出力になりますか。1つ選んでください。 0 1 Hi null null 1 Hi null 0 1 0 Hi null null null 1 null Hi null null 0 1 Hiの後、line n1で例外がスローされる 解答:この設問は、配列の作成と初期化について問うものです。この例では1次元配列が使われていますが、多次元配列(同様に試験対象です)も、本質的には配列の配列にすぎません。そのため、細かいことはいくつか加わりますが、ここでの議論は多次元配列にも基本的には当てはまります。 配列は、2つの方法で作成できます。具体的には、newキーワードを使ったコンストラクタ形式か、または配列リテラルを使うことができます。この設問では、コンストラクタ形式が使われています。この形式では、型の後の角括弧内に、配列の次元を指定する必要があります。 この方法を使う場合、配列に入れる値を同時に指定することはできません。 リテラル形式は波括弧を使うものであり、配列のサイズが小さい場合は特にですが、簡潔な記述となります。この方法では、同時に要素を明示的に初期化することが可能であり、実際には必要になります。 配列リテラルには、2つの構文形式が存在します。もっとも一般的なのは、次のようなものです。 new int[] {1, 1} ここで示されている一般的な形式は、「intの配列」型の式であり、その型の式が必要な、任意の状況で使用できます。そのため、たとえばメソッド呼出しの実パラメータ・リストで使用できます。次に例を示します。 doStuffWithIntArray(new int[] {1, 1}); 次のような、単純な代入にも使用できます。 int[] ia; ia = new int[] {1, 1}; 上記以外の状況で使用することもできます。 この形式では、(コンストラクタ形式とは違って)角括弧内に配列サイズを含めないことに注意してください。配列のサイズは、初期化する値のリストから推論されます。 2番目の形式の方がおなじみかもしれません。実のところ、この形式は、初期化済みの変数を宣言する際の、値の部分にのみ許可されている省略表記です。この形式を使用できるのは、次のような場合に限られます。 int[] ia = { 1, 1 }; もう1つ注意事項を挙げておきます。変数宣言では、変数名の後に角括弧を記述することも許可されています。しかし、この順序での構文はあまり一般的ではありません。宣言の「型」部分が左側にあり、「名前」の部分が右側にある方が大抵好まれているからです。しかしながら、CやC++というJavaの先駆者で使われてきたものであるため、この形式が思い浮かぶという方もいるかもしれません。次にこの形式の例を示します。 int ia[]; 設問に戻ります。今回の設問では、リテラル形式は使われていません。どちらの配列も、コンストラクタ形式を使って作成されています。そのため、生成処理の一部として要素の値を指定することはできず、表現したい特定の値は後で割り当てる必要があります。 もちろん、この設問で行われている明示的な代入では、配列のすべての値が設定されるわけではありません。設問の核心は、配列のうちで明示的な代入が行われていない要素には何の値が入っているかという点です。 実は、この「デフォルトの値は何ですか」という問いは、配列にとどまらず、一般的な状況にも当てはまります。ヒープに割り当てられるすべてのものは、デフォルトの初期化の対象となります。配列であれ、(もっとはっきり言えば)オブジェクトであれ、すべてのオブジェクトがこの対象に含まれます(ここでのポイントは、Javaの配列はオブジェクトであるということです)。このデフォルトの初期化は、メモリ割当てと切り離すことができないものです。コードからヒープに新しいオブジェクトを作成する場合、JVMはデフォルトの初期化が行われたメモリか、例外のいずれかを返します。このデフォルトの初期化が行われていない値を取得することはできません。 それでは、デフォルトの初期化とは何でしょうか。答えは簡単で、ゼロまたはゼロに似た値です。数値型とcharではゼロ、boolean値ではfalse、その他のオブジェクト参照値では、すべてNULLになります。 したがって、new int[2]では、2つのintプリミティブ値の配列の領域が確保されます。そのインデックス(添字と呼ばれることもあります)は0と1(Javaの配列インデックスは、常にゼロベースです)になり、両方の要素に値0が設定されます。そのため、この時点で、ia[0] == 0かつia[1] == 0となります。 次の行では、2つ目の要素(当然、添字は1になります)に値1が代入され、1つ目の要素はデフォルト値0のままになります。 次に、単純なループを使ってint配列の値を出力しています。2つの値、0と1があることはすでに確認しました。そのため、コードのこの部分からの出力は0 1となります(メソッド呼出しがprintlnではなくprintであることに注意してください)。 2つ目の配列も、int配列と同じように宣言され、インスタンス化されます。ここでも、1つの要素が明示的に初期化され、もう1つにはデフォルト値が含まれます。重要な違いは、この配列がオブジェクト型(具体的にはString)であるため、デフォルト値がNULLになることです。そのため、最初の状態でsa[0] == nullかつsa[1] == nullとなります。次に、添字が0の要素が文字列Hiを参照するように代入が行われます。したがって、このコードのループ部分では、Hi nullと出力されます。 以上より、選択肢Aが正解であることがわかります。 int型の配列ではなく、Integerの配列が作成されていた場合、選択肢Bが正解だったでしょう。Integerはオブジェクトで、その配列のデフォルト値はやはりNULLポインタになるからです。しかし、そうではなかったため、選択肢Bは誤りです。 選択肢Cか選択肢Dを選びたくなったのは、new Blah[x]で作成された配列には、添字が0からx-1までのx個の要素ではなく、添字が0からxまでのx+1個の要素があると考えた方かもしれません。 選択肢Eを選びたくなったのは、初期化されていない文字列にアクセスすると例外が発生するだろうと考えた方かもしれません。そう考えるのは、必ずしもおかしなことではありません。興味深いかもしれないのは、式"String is " + sa[1]を評価するとString is nullという出力が得られる一方で、"String is " + sa[1].toString()を評価すると、実はNullPointerExceptionが発生することです。いずれにしても、sa[1]の値はNULLであり、NULLを使ってオブジェクトを参照しようとすると、必ず失敗します。ただし、文字列の連結ではこの問題が回避され、例外がスローされるのではなく、出力nullが得られます。 正解は選択肢Aです。   Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 Javaにテキスト・ブロックが登場 言語の内側:シールド型 TeaVMを使ってブラウザでJavaを動かす ツールをよく知る クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。 ※本記事は、Simon Roberts、Mikalai Zaikinによる”Quiz Yourself: One-Dimensional Arrays (Intermediate)“を翻訳したものです。

コンストラクタを使って配列を作成する際の微妙な違い 著者:Simon Roberts、Mikalai Zaikin 2019年10月4日 その他の設問はこちらから 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による...

ツールをよく知る

code { font-family: courier,"courier new",monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } 偉大なプログラマーは皆、主要ツールについての深い知識を持っている。ツールのエキスパートでないなら、必要な時間をかけること。その手はじめはここから 著者:Andrew Binstock 2019年10月16日 私の仕事でよいところの1つは、偉大な開発者や真のドメイン・エキスパート、テクニカル・イノベーター、そして「魔法使い」に出会えることです。そういった人々と話す中で、偉大なプログラマーを偉大たらしめているものは何かについて、たびたび議論することができました。偉大なプログラマーを観察してわかる特性は、「コードがきれいでたくさんのテストを書く」という安直な答えで表せるものではなく、高く評価されることがほとんどないものです。つまり、真に大成するためには、疑問点を表面だけでなく、深いところまで徹底的に調査することが必要だということがわかります。 私が個人的にエキスパートを観察してわかったのは、偉大な開発者はいくつかの特性を共有しているということです。その特性を(順不同で)挙げてみます。解決しようとしている問題を完全に理解する辛抱強さ。頭の中に多くの情報を同時に蓄えておく能力。小規模なものから大規模なものにすばやく移り、再び戻る能力。そして最後に、使っている主なツールについての深い知識です。こういった特性のうち、最初と最後は自分で簡単に身につけることができるものです。その他の2つは、どちらかといえば生来の能力に近いものです。しかしもちろん、訓練や懸命な努力によって獲得することもできます。 ツールについての深い知識を得るのは、20年前よりも現在の方が難しくなっています。現在のフルスタック開発者は、数十種類のツールを恒常的に使っているかもしれません。そのため、すべてを細部までマスターするというのは現実的でなくなっています。しかし、私が熟慮したうえで指摘しておきたいのは、主なツールは完全に使いこなせるようになっている必要があるということです。 基本的なことから考えてみましょう。皆さんは完全なブラインド・タッチができるでしょうか。自分の手を見ずにタイピングができないなら、徐々に自分を大変不利な立場に追いやっていることになります。仕事が遅くなるだけではありません。非常に認識しづらい形で、タイピングがさらに必要なちょっとしたことを避けたくなるはずです。たとえば、コードが数行では収まらないことを試そうとは思わず、繰り返し行っているタスクについて、ちょっとしたスクリプトを書いて自動化しようとも思わないでしょう。たとえタイピングが不完全であっても(皆さんは手元を見ずにすべての数字をタイプできるでしょうか。!=などはどうでしょう)、筋肉の記憶を鍛えるために使った時間は、スピードと、キーボードではなく画面だけに集中できる能力という形で報われるはずです。 次に、ソフトウェア・ツールについて考えてみましょう。皆さんは、エディタやIDEのことをどのくらい知っているでしょうか。多くの開発者は、頻繁に使ういくつかのコマンドは使いこなせますが、その他のコマンドはそうではありません。コードを入力してコンパイルし、テストを実行するという枠を越える場合、メニューやマウスを使わざるを得なくなります。こういった限定的な知識には、不完全なタイピングと同じような欠点があります。すなわち、仕事が遅くなり、新しいことを試すのを目には見えない形で避けたくなります。また、簡単なタスクを完了しようとする場合も、絶えず小さな中断に見舞われます。 次号には、『The Pragmatic Programmer』の書評を掲載する予定です。   エディタやIDEを十分使いこなせるとは、どういうことでしょうか。『The Pragmatic Programmer』の20周年記念版で、David Thomas氏とAndrew Hunt氏は、真の意味で開発環境を使いこなすために必要と感じているものについて述べています。皆さんは、以下のことをすべてキーボードから行うことができるでしょうか。 カーソルを動かし、文字や単語、行、段落単位で選択する 対応するデリミタ、関数、モジュールなど、構文単位でカーソルを動かす 変更を行った後にコードのインデントを調整する コード・ブロックを1回のコマンドでコメント化およびコメント解除する 変更を元に戻す、やり直す エディタ・ウィンドウを複数のパネルに分割し、その間を移動する 特定の行番号に移動する 選択した行を並べ替える 文字列と正規表現の両方を検索し、以前の検索を繰り返す 一時的に複数のカーソルを作成し、それぞれのカーソルでテキストを編集する 現在のプロジェクトのコンパイル・エラーを表示する 現在のプロジェクトのテストを実行する 私がこのリストに付け加えたいと思っているのは、コードをコミットしてセントラル・リポジトリにプッシュすることができる、コードをコンパイルすることができる、デバッガで問題のあるコードをステップ実行することができるという点です。 いずれかで「No」と答えた方も、大丈夫です(私も確実に含まれますが、そのような人はたくさんいます)。しかし、偉大なプログラマーの大多数は、こういったことのすべて(またはそのほとんど)を簡単に行う方法を知っているものです。Thomas氏とHunt氏は、必要なスキルを獲得できる方法を示しています。その中でもっとも重要なのは、「マウスに触れない」ということです。こうすることで、調べざるを得なくなり、コマンドも身につきます。 また、両氏はさらにその先の提案も行っています。エディタやIDEのすぐ外側で行っているタスクを見つけ、そのタスクを自動化するか、または容易にするプラグインを探すことです。こうすることで、主なツールに関する専門知識が増え、さらに多くの作業に対応できるようになります。 偉大なプログラマーとペアプログラミングを行ったことがある方なら、そういった人のスピードや器用さを実際に目の当たりにしているはずです。コードやテストを書いてすぐに、ウィンドウを開いてメモをとったりユーティリティを実行したりしてリファクタリングを行います。これを見るのは楽しいことです(そして実際、さまざまなソーシャル・メディアで見ることができます)。そのような人を目指しましょう。重要なのはツールを知ることです。   Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 Javaにテキスト・ブロックが登場 言語の内側:シールド型 TeaVMを使ってブラウザでJavaを動かす クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Andrew Binstock Andrew Binstock(javamag_us@oracle.com、@platypusguy):Java Magazine編集長。Dr. Dobb's Journalの元編集長。オープンソースのiText PDFライブラリを扱う会社(2015年に他社によって買収)の共同創業者。16刷を経て、現在もロング・テールとして扱われている、Cでのアルゴリズム実装についての書籍を執筆。以前はUNIX Reviewで編集長を務め、その前にはC Gazetteを創刊し編集長を務めた。 妻とともにシリコン・バレーに住んでおり、コーディングや編集をしていないときは、ピアノを学んでいる。 ※本記事は、Andrew Binstockによる”Really Know Your Tools“を翻訳したものです。

偉大なプログラマーは皆、主要ツールについての深い知識を持っている。ツールのエキスパートでないなら、必要な時間をかけること。その手はじめはここから 著者:Andrew Binstock 2019年10月16日 私の仕事でよいところの1つは、偉大な開発者や真のドメイン・エキスパート、テクニカル・イノベーター、そして「魔法使い」に出会えることです。そういった人々と話す中で、偉大なプログラマーを偉大たらしめてい...

TeaVMを使ってブラウザでJavaを動かす

code { font-family: courier,"courier new",monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } Javaをフロントエンドとバックエンドの両方に使ってWebアプリを構築する 著者:Andrew Oliver 2019年10月8日 Javaがブラウザの中で実行されていた頃を覚えている方もいるかもしれません。その頃は、Webページから「Pure Java」のUIを簡単に起動できました。ユーザー・インタフェースとバックエンドを強く型付けされた同じ言語で開発することや、データ・クラスや検証ロジックを共有することもできました。また、コード品質ツールをフロントエンドとバックエンドの両方のコードに対して適用することもできました。いい時代でした。 しかし最近、ブラウザ・ベンダーはJavaScriptに重きを置くようになり、Javaのサポートをだんだん減らしてきました。クライアント側のWebアプリに支配された世の中では、Javaはサーバー側のみのテクノロジーに格下げされてしまっているようです。フルスタックJavaエクスペリエンスのメリットは、失われています。開発者は複数の言語やツールセットを行き来しなければならないため、開発の生産性は急降下します。サーバー側のリファクタリングがクライアント側で見逃されることや、その逆のことが起きた場合、エラーが紛れ込むことになります。コードの品質を保つための優れたJavaツールセットも、クライアント側で再発明せざるを得なくなります。これは大きな後退であるように感じられます。   解決策 うれしいことに、解決策があります。オープンソース・プロジェクトTeaVMは、受け取ったJavaコードをビルド時にコンパクトで高速なJavaScriptに変換するものです。多くのWeb APIのラッパーが提供されているため、DOMの操作からユーザーの位置情報の取得まで、コードでブラウザを完全に操作できます。また、Flavourという、Webページ・テンプレート用の軽量フレームワークも含まれています。Flavourには、JSONバインディングを含め、JAX-RS Webサービスを簡単に呼び出す仕組みが組み込まれています。 TeaVMの考え方はGoogle Web Toolkit(GWT)に似ています。いずれのプロダクトでもJavaでコードを書くことができ、ブラウザと親和性があるJavaScriptが生成されます。しかし、柔軟性、パフォーマンス、Webネイティブ性という領域では、TeaVMがGWTを上回っています。TeaVMではKotlinやScalaなどのすべてのJVM言語をサポートしていますが、GWTでサポートしているのはJavaのみです。TeaVMでは、GWTよりコードのビルドが高速であるだけでなく、GWTよりコンパクトでブラウザでのパフォーマンスもよいJavaScriptが生成されます。さらに、おそらくもっとも重要なポイントは、TeaVMのFlavourライブラリにより、アプリのコンテンツやコンポーネントをHTMLとCSSで構築できるため、開発者とデザイナーが連携して作業できることです。 フロントエンドのTeaVMとバックエンドの従来のJavaサービスとを組み合わせれば、フルスタックのJavaを取り戻すことになります。すべてをJavaでコーディングすることができます。UIとサーバーでクラスを共有することができ、サーバーで名前をリファクタリングすればUIもリファクタリングされます。すべてのビジネス・ロジックの単体テストをJUnitで書くこともできます。PITミューテーション・テストでテスト品質を計測することや、PMDやCheckstyleなどのユーティリティでコード品質を確認することも可能です。   使ってみる TeaVM Flavourアプリは、標準Maven Webプロジェクトにいくつかの追加を行ったものです。アプリケーションのメイン・ページは、おなじみのwebapp/index.htmlです(慣例的に、CSSはwebapp/css/app.cssにあります)。ただし、メイン・ページは簡単なものであることが多く、通常はresources/templatesフォルダからHTMLテンプレート(ページ断片)を読み込みます。このHTMLテンプレートは、Javaのビュー・クラスと1対1になるようにリンクされています。ページのビジネス・ロジックを提供するのは、このビュー・クラス(src/main/javaにあります)です。ビュー・クラスには、ビジネス・ロジック、テンプレートで使われるプロパティ、バインディングが含まれています。さらに具体的に言えば、ビュー・クラスでは、イベントへの応答、RESTサービスとの通信、表示されるテンプレートの変更など、何でも行うことができます。 このセクションでは、単純なTeaVMアプリケーションをゼロから立ち上げる方法について説明します。その中で、Javaベースのビジネス・ロジックにリンクしたHTMLテンプレートを作成します。このビジネス・ロジックが、ブラウザの中だけでユーザーのアクションに応答します。 使用を開始するもっとも早い方法は、Mavenアーキタイプを使ってTeaVM Flavourプロジェクトを作成することです。 mvn archetype:generate \     -DarchetypeGroupId=org.teavm.flavour \     -DarchetypeArtifactId=teavm-flavour-application \     -DarchetypeVersion=0.2.0 グループとパッケージにcom.mycompanyを、アーティファクトIDにflavourを使った場合、主なファイルは次のようになります。 src/main/java/com/mycompany/Client.java:このファイルには、アプリのJavaロジック(ビューと呼ばれます)が含まれます。また、テンプレート(次の項目で説明します)で使われるプロパティ(名前)も含まれます。 src/main/resources/templates/client.html:アプリのHTMLテンプレートです。nameフィールドにバインドされる、入力フィールドとHTMLテキストが含まれます。入力を変更すると、HTMLが変わります。後ほどルーティングとコンポーネントのセクションで説明しますが、HTMLテンプレートとビューの2つは、Flavourのあらゆる場面で使用される基本要素です。 src/main/webapp/css/app.css:アプリのCSSです。 src/main/webapp/index.html:アプリケーションのラッパーHTMLページです。ここでは大したことはしておらず、実際のアクションはテンプレートで行われます。 packageゴールを使ってプロジェクトをビルドします。 mvn clean package Webアプリのファイルで、パッケージが指定されていないものは、target/flavour-1.0-SNAPSHOT/に格納されることになります。ブラウザからindex.htmlファイルを開いて、アプリが動作していることをすぐに確認できます。 プラグインやダウンロードは必要なく、Javaアプリがブラウザで直接実行されます。 アプリをTomcatにデプロイする場合は、target/flavour-1.0-SNAPSHOT.warを使います。または、${TOMCAT_HOME}/webapps/flavourをflavour-1.0-SNAPSHOTフォルダへのシンボリック・リンクにすることもできます。シンボリック・リンクの方法を使った場合は、http://localhost:8080/flavourからアプリにアクセスすることができます(Tomcatがデフォルト・ポートの8080で動作するように構成している場合)。   Flavourを使ったリスト表示 UIに項目のリストを表示したいことはよくあります。Flavour要素<std:foreach>を使うことで、短いリストや中規模のリストを表示できます。このFlavour要素には、Javaでの通常のforeachループと同じように、反復処理するコレクションと、ループ本体をスコープとするコレクション要素の変数名を渡します。 コレクションはビュー・クラスから読み取られます。public List<Song> getSongs()というgetterで歌のリストを定義している場合、次のようにして単純なリストを作成することができます(本記事で紹介しているすべてのコードは、ダウンロード・サイトで公開しています)。次に示すのは、listプロジェクトのclient.htmlのコードです。 <ol>   <std:foreach var="song" in="songs">     <li>       <html:text value="song.name"> by       <strong><html:text value="song.artist"></strong>     </li>   </std:foreach> </ol> Flavourで生成される順序付きリスト(ol)には、getSongs()が返すすべてのSongに対応するリスト項目(li)が存在しています。リストの各項目には、歌の名前とアーティストが含まれます。<html:text>要素では、value式が評価され、その結果がページに挿入されます。Flavourの式言語を使うことで、明示的にgetterやsetterを呼び出さずに、JavaBeansスタイルのプロパティ(getX/setX)に名前を使ってアクセスすることができます。そのため、song.getName()と書く代わりに、song.nameと簡略化して書くことができます。 次は、それぞれの機能について詳しく見ていきます。   その他の標準コンポーネント Flavourでは、std:foreachの他にも、ページのコンテンツを制御する多くの標準コンポーネントをサポートしています。 std:ifを使うことで、ブール条件に基づいてページにコンテンツを追加できます。 attr:xyzを使うことで、式を使って属性xyzを設定できます。たとえば、attr:classにより、要素のクラスを動的に設定できます。 標準コンポーネントは、次に紹介するFlavourの式言語と密接に連携しています。   式言語 Flavourコンポーネントの属性は、式言語(EL)を使って指定します。ELはJavaに似ていますが、いくつかのシンタックス・シュガーが追加されており、HTMLページでうまく動作させるための若干の調整も行われています。 以下を含め、すべての標準プリミティブがサポートされています。 文字列(HTML内で簡単に使えるように、一重引用符を使用) 数値(整数と浮動小数点数) ブール値(trueとfalse) ビュー・クラスのメソッドとプロパティは、名前を使って呼び出すことができます。Javaと同様に、メソッド呼出しにはパラメータが必要です。ただし、プロパティは名前で直接参照できます。先ほど紹介したように、titleと指定するだけで、FlavourがgetTitle()を呼び出してくれます。 次に示すのは、ELの使い方を説明したいくつかの標準コンポーネントの例です(standard-components-elのclient.html)。 <!-- ブール値プロパティshowHeadingを使用 --> <std:if condition="showHeading">   <h1>Flavour Messenger</h1> </std:if>   <!-- messageが入力されたときにボタンを有効化 --> <!-- message.emptyはELの省略記法で、message.isEmpty()を表す --> <button html:enabled="!message.empty">Check Spelling</button>   イベントへの応答 UIは、ユーザーの操作に応答できなければ完成とは言えません。Flavourでevent属性を使うことにより、DOMイベントが発生したときにJavaメソッドを呼び出すことができます。一般的に使われるオプションには、以下のものがあります。 event:click:クリック・イベントのハンドリング event:change:コンポーネントの値変更のハンドリング テンプレートで、ボタンをクリックしたときにsendメソッドを呼び出したい場合を考えてみます。次のようにして、単純にevent:click属性をボタンに追加します。 <button event:click="send()">Send</button> バインディング バインディングを行うことで、ビュー・クラスのプロパティを表示コンポーネントにリンクすることができます。バインディングには、いくつかの種類があります。ビュー・クラスのプロパティが変更されたときにUIが更新されるようにするものもあれば、ユーザーがUIコンポーネントを操作したときにビュー・クラスのプロパティが更新されるようにするものもあります。双方向バインディングは、この2つを組み合わせて、ビュー・クラスのプロパティ、またはUIのいずれが変更された場合でも両方を同期させるものです。特によく使われるものを紹介します。 html:textでは、ビュー・クラスのプロパティに基づいてテンプレートにHTMLが出力されます。 html:valueでは、ビュー・クラスのプロパティの変更に基づいて入力コンポーネントが更新されます。 html:changeでは、入力値が変更されたときにビュー・クラスのメソッドが呼び出されます。 html:bidir-valueはもっとも強力です。html:valueとhtml:changeを組み合わせて、UIの入力フィールド、またはビュー・クラスのプロパティのいずれが変更されても両者を同期させます。 先ほどのファイルには、次の内容が含まれています。 <form> <!-- 値が変更されると、messageプロパティからの読取りまたはmessageプロパティへの書込みを行う -->   <input type="text" html:bidir-value="message"> </form>   ルーティング 単一ページ・アプリケーション(SPA)には複数の画面があり、サーバーにリクエストせずにブラウザ内で切り替わるようになっています。Flavourでは、ルーティング機能によってSPAを完全にサポートしています。ルーティングには、いくつかの要素が関連します。 ルート・インタフェース:画面とそのURLを定義する ルート実装:オンデマンドで画面のインスタンスを生成する 画面のHTMLテンプレート:1画面につき1つ存在し、レイアウトとコンポーネントを含む ビュー・クラス:1つのテンプレートにつき1つ存在し、テンプレートのデータとイベント・ハンドラを提供する レストランの一覧を表示する画面と、それぞれのレストランの詳細画面があるものとします。その場合、レストラン一覧とレストラン詳細のテンプレートを作成できます。それぞれのテンプレートにビュー・ページが存在することになります。ルート・インタフェース(サンプル・コードではApplicationRoute.java)は次のようになります。 @PathSet interface ApplicationRoute extends Route {   @Path("/restaurants")   public void restaurantList();     @Path("/restaurant/{id}")   public void restaurantDetails(@PathParameter("id") int id); } レストランの詳細を表示するrestaurantDetailsページに、レストランID用のパラメータがどのように含まれているかに注意してください。 Routeの実装には、ページを切り替えるロジックが含まれています。慣例的に、RouteはClient.javaのメイン・ページで実装しています。 @BindTemplate("templates/client.html") public class Client extends ApplicationTemplate   implements ApplicationRoute {     RestaurantSource source = new RestaurantSource();     public static void main(String[] args) {         Client client = new Client();         new RouteBinder()             .withDefault(ApplicationRoute.class,                          route -> route.restaurantList())             .add(client)             .update();         client.bind("application-content");     }     @Override     public void restaurantList() {         setView(new RestaurantListView(source));     }     @Override     public void restaurantDetails(int id) {         setView(new RestaurantDetailsView(source, id));     } } レストラン一覧ページ(routingのrestaurant-list.html)では、std:foreachを使ってレストランの一覧を表示します。各レストランには、対応するレストラン詳細ページへのリンクが含まれます。 <div>   <h1>Restaurants</h1>   <ol>     <std:foreach var="restaurant" in="restaurants">       <li>         <button type="button"                 event:click="showRestaurant(restaurant.id)">           <html:text value="restaurant.name"/>         </button>       </li>     </std:foreach>   </ol> </div> レストラン詳細ページ(restaurant-detail.html)では、1つのレストランについての情報を表示します。ここでは、<html:text>を使ってレストラン・オブジェクトのフィールドを表示しています。 <div>   <h1><html:text value="restaurant.name"/></h1>   <h3>In business for     <html:text value="restaurant.yearsInBusiness"/> years!</h3>   <p></p>   <p><button type="button" event:click="showList()">   Return to the restaurant list</button></p> </div>   RESTful API ほとんどのWebアプリケーションではサーバーと通信します。よく使われるのは、リモート・サービスの起動、データの保存、アップデートの取得などです。 Flavourでは、簡単にWebサービスにアクセスする方法を提供しています。RESTClientクラスにより、JAX-RSサービスとして宣言したJSONベースのWebサービス用のクライアントを構築できます。JSONとJAX-RSの人気を考えれば、皆さんのWebサービスがこのクラスに対応している可能性も高いはずです。UIモジュールのPOMファイルにJAX-RSインタフェースを含めるだけで、1行のコードを書くことによりFlavourからインスタンスを生成できます。 YourService service =     RESTClient.factory(YourService.class)               .createResource("api"); レストランの例の続きとして、サービスにレストランの一覧を取得するメソッドがあるものとします。 List getRestaurants(); このメソッドは、次のようにして呼び出すことができます。 List restaurants = service.getRestaurants(); 以上です。クライアント側でレストランの一覧を入手できたことから、先ほどのセクションのようにしてビューで使用できます。 近日中に予定されているTeaVMバージョン0.6リリースでは、REST関係の小さな変更が行われることが発表されています。コードを0.6で動作させるために必要なのは、2箇所にマーカー・アノテーションを付加することだけです。 RESTサービス・インタフェースに@Resource(org.teavm.flavour.rest.Resource)アノテーション サービス・メソッドに渡す、またはサービス・メソッドから受け取るカスタム・クラスに@JsonPersistable (org.teavm.flavour.json.JsonPersistable)アノテーション(StringやLongなどの標準クラスには不要)   カスタム・コンポーネント ページやビューのクラスを設計する際には、再利用したいHTMLやコードが数多くあることに気づくでしょう。筆者がよく見るケースは2つあります。 ページの一部を2つのページで繰り返して使う必要がある リストやテーブルなど、ページ内に繰り返される部分がある コンポーネントを定義する最初の手順は、Flavourアプリで通常のページを定義する操作によく似ています。ビュー・クラスにバインドされたHTMLテンプレートを作成します。このテンプレート(慣例的に、src/main/componentsに配置します)には、コンポーネントのHTMLを格納します。ビュー・クラスにはテンプレートで使用するビジネス・ロジックとプロパティを含めます。この点は先ほどと同じですが、バインディングを追加します。バインディングはコンポーネントに対して一意で、属性やその他の値がどのようにテンプレートにバインドされるかを指定します。属性は、コンポーネントをカスタマイズするために使われます。 それでは、リスト内部や複数のページで再利用できるレストラン・コンポーネントの作り方を見てみます。 まず、components/restaurant.htmlでテンプレートを定義します。 <div style="background-color: #99e">   <div>     <h1><html:text value="restaurant.name"/></h1>   </div>   <div>     <h3><html:text value="restaurant.yearsInBusiness"/>      years in business!</h3>   </div> </div> 次に、src/main/java/com/app/component/Restaurant.javaでビュー・クラスを定義します。コンポーネントに表示するレストランをrestaurant属性にバインドしている点に注意してください。 @BindTemplate("components/restaurant.html") @BindElement(name = "restaurant") public class RestaurantComponent extends AbstractWidget {     private Supplier<Restaurant> restaurantSupplier;       public RestaurantComponent(Slot slot) {       super(slot);     }       @BindAttribute(name = "restaurant")     public void setNameSupplier(                     Supplier<Restaurant> supplier) {         this.restaurantSupplier = supplier;     }       public Restaurant getRestaurant() {         return restaurantSupplier.get();     } } さらに、コンポーネントを使う前に、ビュー・クラスの名前を次のファイルに追加して登録を行う必要があります。 META-INF/flavour/component-packages/com.mycompany コンポーネントが別のパッケージにある場合は、com.mycompanyの部分をパッケージと一致するように変更します。 以上の手順が完了すれば、他のテンプレートでレストラン・コンポーネントを使えるようになります。先ほどのレストラン一覧ページを書き換えて、各レストランの一覧が表示されるページを作成してみます。std:foreachループの中にコンポーネントを配置し、各レストランに対応する、コンポーネントのインスタンスを1つずつ作成します(restaurant-list.html)。 <?use comp:com.mycompany?> <div>   <h1>Restaurants</h1>   <ol>     <std:foreach var="restaurant" in="restaurants">       <li>         <comp:restaurant restaurant="restaurant"/>       </li>     </std:foreach>   </ol> </div> テンプレートの最初に、処理命令useがある点に注意してください。この命令では、コンポーネントを使用することをFlavourに対して伝えるとともに、後ほどファイル内で使用する接頭辞を指定しています。ここでは、接頭辞をcompとして宣言しています。後ほどコンポーネントを使う際に、comp:restaurant-detailという形で接頭辞が再登場しています。   位置情報APIの使用 位置情報APIを使ってユーザーの位置を照会することができます。サンプル・アプリのビュー・クラス(ここでは、geolocationのClient.java)に次のコードを追加します。 public void locate() {     if (Navigator.isGeolocationAvailable()) {        Navigator.getGeolocation().getCurrentPosition(            (Position pos) -> {                final Coordinates coords = pos.getCoords();                location = "Lat/Lon: " + coords.getLatitude()                         + "/" + coords.getLongitude();                Templates.update();               },            (PositionError positionError) -> {               switch (positionError.getCode()) {                   case PositionError.PERMISSION_DENIED:                     location = "The user blocked location access.";                     break;                   case PositionError.POSITION_UNAVAILABLE:                     location = "Location could not be determined.";                     break;                  case PositionError.TIMEOUT:                     location = "A timeout occurred while attempting"                             + " to determine your location."; break;               }               Templates.update();            });     } else {           location = "This browser doesn't support geolocation";           Templates.update();     } } public String getLocation() {     return location; } 位置情報の検索を呼び出すボタンと、結果を表示する別のテキスト・フィールドを追加します。 <div>   <div>     <button event:click="locate()">Locate</button>   </div>   <div>     Your location is: <html:text value="location"/>   </div> </div> 位置情報は非同期的に発生することから、Templates.update()を使って表示を更新しています。Templates.update()は軽量であるため、必要なときにはためらわずに呼び出すことができます。   まとめ 以上で、TeaVMで独自のJava Webアプリを構築する準備が整いました。レストラン一覧のWebサイトでも、新しいソーシャル・ネットワークでも、画期的なオンライン・ゲームでも作ることができます。 他の考え方や情報を探したい方、本記事の範囲を超える質問がある方は、TeaVMのWebサイトにアクセスしてみることをお勧めします。フォーラムが設置されているほか、詳しいドキュメントや例、問題リストなどが掲載されています。 Alexey Andreev氏は、TeaVMとFlavourの作者です。本記事の原稿を確認していただいたことに感謝いたします。   Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 Javaにテキスト・ブロックが登場 言語の内側:シールド型 ツールをよく知る クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Andrew Oliver 20年以上にわたり、Javaのコーディング、講演、執筆に携わる。O'Reilly Conferenceでは、エンタープライズJavaについて講演を行った。AWT、Swing、JavaFX、Codename OneなどのさまざまなJavaツールキットでUIを構築した経験を持ち、現在はいくつかのTeaVM/Flavourベースのプロジェクトに従事している。 ※本記事は、Andrew Oliverによる”Java in the Browser with TeaVM“を翻訳したものです。

Javaをフロントエンドとバックエンドの両方に使ってWebアプリを構築する 著者:Andrew Oliver 2019年10月8日 Javaがブラウザの中で実行されていた頃を覚えている方もいるかもしれません。その頃は、Webページから「Pure Java」のUIを簡単に起動できました。ユーザー・インタフェースとバックエンドを強く型付けされた同じ言語で開発することや、データ・クラスや検証ロジックを共有するこ...

言語の内側:シールド型

code { font-family: courier, "courier new", monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } パターン・マッチング、列挙型およびswitch文の改善に向けて進化するJava 著者:Ben Evans 2019年10月16日 本記事では、Javaにとって新しいプログラミング言語概念である、シールド型について説明します。この機能は現在活発に開発が行われており、将来のバージョンのJavaに導入される見込みです。シールド型の実現に必要な、プラットフォームレベルの重要な仕組みが、Java 11のネストメイトと呼ばれる機能で導入されました。Java 12でも、プレビュー機能としてswitch式が導入されました。そこから、将来のバージョンのJavaでシールド型をどのように使えるかが垣間見えます。 本記事の内容を完全に理解するためには、プログラミング言語の設計や実装について、かなりの知識が必要です(少なくとも、興味を持っている必要があります)。まず、シールド型とは何であるかを説明するにあたり、Javaの列挙型とその内部の仕組みについて詳しく見てみます。 列挙型は、とてもよく知られている、Javaの言語機能です。列挙型を使うことにより、ある型が取り得るすべての値を表現する有限集合をモデリングすることができます。そのため、列挙型は実質的に型安全な定数として扱われます。 たとえば、列挙型Petについて考えてみます。 enum Pet { CAT, DOG } プラットフォームでは、特殊な形態のクラス型をJavaコンパイラで自動生成させることによって、この列挙型を実現しています(厳密に言えば、ランタイムは実際にはライブラリ型java.lang.Enumを他のクラスとは少しばかり異なる特殊な方法で扱っていますが、この処理の詳細はここではあまり関係ありません。すべての列挙型クラスはjava.lang.Enumを直接拡張しています)。 この列挙型を逆コンパイルして、コンパイラが何を生成したのかを確認してみます。 eris:src ben$ javap –c Pet.class Compiled from "Pet.java" final class Pet extends java.lang.Enum { public static final Pet CAT; public static final Pet DOG; … // Private constructor } クラス・ファイルの中では、列挙型が取り得るすべての値がpublic static final変数として定義されています。コンストラクタはprivateであるため、インスタンスを追加生成することはできません。 実質的に、列挙型はシングルトン・パターンを一般化したものに近くなっていますが、クラスのインスタンスが1つだけ存在するのではなく、有限個存在する点が異なります。このパターンにより、網羅性という考え方を導入できるため、非常に便利です。つまり、NULLでないPetオブジェクトがある場合、CATインスタンスまたはDOGインスタンスのいずれかであることが確実にわかります。 ここで、さまざまな種類の犬と猫を現在のJavaでモデリングすることを考えてみます。その場合、1つのインスタンスではそれぞれの種類のペットを表すのに十分ではないため、2つの好ましくない方法のいずれかを使わざるを得なくなります。 まず、1つの実装クラスPetと、実際の種類を保持する状態フィールドを併用する方法が可能です。状態フィールドは列挙型のような性質を持ち、特定のオブジェクトが実際にどの種類に属するかを表すビットを提供するため、このパターンはうまく動作します。しかし、自らビットを追跡する必要があり、それはまさに型システムの範疇であることから、これは明らかに次善の方法です。 もう1つの方法として、抽象型のベースタイプPetを宣言し、そのサブクラスとして具象型のCatとDogを作成することができます。ここでの問題は、Javaが、デフォルトで拡張可能であるオープンな言語として常に設計されてきたことです。クラスが一度コンパイルされれば、何年が経過しても(または何十年後であっても)サブクラスをコンパイルすることができます。 Java 11の時点で、Java言語で許可されているクラス継承構造は、オープン継承(デフォルト)と継承なし(final)のみです。抽象型をベースとして具象型のサブタイプを使うパターンの重大な弱点がここに露呈しています。 ここでの問題は、クラスではパッケージ・プライベートなコンストラクタ(これは実質的に「同じパッケージのクラスのみが拡張できる」ことを意味します)を宣言できるものの、ランタイム・システムにはユーザーがそのパッケージ内に新しいクラスを作成することを防ぐ手段はない点です。したがって、この保護は、どう好意的に見ても不完全です。 つまり、Petクラスを定義した場合、Petを継承したSkunkクラスを第三者が作ることを防ぐのは不可能です。さらに悪いことに、この望まれない拡張は、Pet型がコンパイルされてから何年が経過しても(または何十年後であっても)行われる可能性があります。これは非常に好ましくないことです。 結論として、現在のバージョンのJavaでは、抽象型のベースを使ったアプローチは安全ではありません。つまり、開発者は、Petの実際の種類を保持するためにフィールドを使うしかないということになります。 OpenJDKプロジェクト(標準バージョンのJavaが開発されている場所)全体の中の、Project Amberというプロジェクトに関する最近の取り組みでは、継承性を細かく制御する新しい方法を導入することで、この状態を改善することを目指しています。その新しい方法がシールド型です。 この機能は、さまざまな形態で他のいくつかのプログラミング言語に存在しており、ここ最近の流行になっています(ただし実のところ、この考え方はかなり古くからあります)。 Javaでは、この機能をシールド(封印された)という概念によって実現しています。この概念が表しているのは、クラスは拡張可能であるものの、既知のリストにあるサブタイプにのみ拡張でき、他のクラスには拡張できないということです。 他の言語ではこの機能を違う形で見ているかもしれませんが、Javaでは「ほとんどfinal」なクラスを表す機能と考えます。 簡単な例を使って、現時点での新しい構文を見てみます。 public abstract sealed class SealedPet permits Cat, Dog { protected final String name; public abstract void speak(); public SealedPet(String name) { this.name = name; } } public final class Cat extends SealedPet { public Cat(String name) { super(name); } public void speak() { System.out.println(name +" says Meow"); } public void huntMouse() { System.out.println(name +" caught a mouse"); } } public final class Dog extends SealedPet { public Dog(String name) { super(name); } public void speak() { System.out.println(name +" says Woof"); } public void pullSled() { System.out.println(name +" pulled the sled"); } } ここでいくつか気づくことがあります。まず、SealedPetはabstract sealedクラスになっています。sealedは、今までJavaで許可されていたキーワードではありません。次に、2つ目の新しいキーワードであるpermitsが使われています。開発者はpermitsを使って、そのシールド型に許可されているサブクラスを列挙することができます(サブタイプのリストを記述していない場合、許可されているサブタイプは同じコンパイル・ユニットのサブタイプから推論されます)。 さらに、CatとDogは正規のクラスであるため、ネズミを捕まえる、ソリを引くなど、その型に固有な動作を行うことができるというメリットも得られます。オブジェクトの「実際の型」を示すフィールドを使う場合、すべてのサブタイプにおけるすべてのメソッドがベースタイプに存在することが必要になるか、不格好なダウンキャストを行わざるを得なくなるため、ここまで簡単にはいかないでしょう(なお、この例では、サブクラスをfinalにしていますが、staticでfinalなインナー・クラスにするなど、修飾子の組合せは他のものも可能です)。 ここでこれらの型を使ってプログラムを作る場合、登場するすべてのPetインスタンスは、CatまたはDogのいずれかであるとわかっていることになります。さらに、コンパイラもこの情報を使うことができます。つまり、ライブラリのコードでは、列挙されたものしかサブクラスが存在しないことを問題なく前提にできるようになり、クライアントのコードもこの前提を破ることはできません。 オブジェクト指向プログラミングの理論で言えば、これは新しい種類の正式な関係を表します。オブジェクトoには、CatまたはDogとis-a関係があると言うことができます。すなわち、oが取り得る型は、CatとDogの和集合(union)です。 そのため、こういった型は非交和(disjoint union)型と呼ばれます。さまざまな言語では、タグ付き共用型(tagged union)や直和型(sum type)とも呼ばれています。ただし、これらはCの共用体(union)とは少しばかり異なることに注意してください。 たとえば、Scalaプログラマーは、ケース・クラスやScala版のsealedキーワードを使って、非交和型と非常によく似た考え方を実現できます。 JVM以外では、Rust言語にも非交和型の考え方が導入されています。ただし、Rustでは非交和型をenumキーワードで表しているため、Javaプログラマーはかなりややこしく感じるかもしれません。 一見したところ、この型はJavaにとってまったく新しい考え方であるように感じるかもしれません。しかし、列挙型にとてもよく似ているため、Javaプログラマーにとっては、その類似点がよい出発点になるはずです。実は、直和型に似たものがすでに存在する箇所があります。マルチキャッチ句の例外パラメータの型です。 Java 11の言語仕様には、「例外パラメータを宣言する型は、例外パラメータの型を和集合(union)D1 | D2 | ... | Dnで記述すると、lub(D1, D2, ..., Dn)となる」(JLS 11セクション14.20)と書かれています。引用部にあるlubとは「最小上界」で、D1、D2、...、 Dnにもっとも近い共通のスーパータイプという意味です。これはjava.lang.Objectまたはそれよりも具体的な何らかの型になります。マルチキャッチの例外の場合、lubはThrowableまたはそれよりも具体的な何らかの型になります。 シールド型と新しいswitch しかし、シールド型の実用性はモデリング能力の向上にとどまりません。実際、JDK 12で導入された(そしてJDK 13で強化された)興味深い機能に、switch式があります。そこから、今後Java開発者がシールド型をどのように活用できるかが垣間見えます。これについてもう少し詳しく見ていきます。 switch式は、Javaに古くからある(Cによく似た)switchキーワード(これは文です)を大きくアップグレードするものです。この新機能を使うことで、switchを式として動作させることができます。この設計では、switch(または同じような言語構造)を、値を返す式として扱う、より関数指向型の言語(Haskell、Scala、Kotlinなど)との間の言語的なギャップを埋めることを目指しています。 最終形がJava 12に導入されたバージョンと大幅に異なるものになることは考えにくいですが、本記事はJava 13の形式が確定する前に執筆しているため、ここではJava 12の形式を使って説明します。次に例を示します。 import java.time.DayOfWeek; public static boolean isWorkDay(DayOfWeek day){ var today = switch(day) { case SATURDAY, SUNDAY -> false; case MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY -> true; }; // 祝日の考慮など、その他の処理を行う return today; } switch式は、入力値に基づいて出力値を生成する関数のように振る舞うことができるようになりました。switch式を使うことで、switchが非常によく使われるパターンを簡単に記述できるため、この機能単独でとても便利です。実のところ、switch式のルールは、すべての入力値が出力値を生成することが保証されている必要があるというものです。 たとえば、intを受け取るswitch式では、取り得るすべての場合を列挙することはできないため、default句を含める必要があります。ただし、鋭い開発者の方なら気づくと思いますが、列挙型の場合、コンパイラでは定数の網羅性を使用できます。ご想像どおり、取り得るすべての列挙型定数がswitch式に存在する場合は、先ほどの例のようにdefault句を含める必要はありません。 また、switch式は、将来のバージョンのJavaで実現される大きな機能へ向けての足がかりでもあります。 その目的は、パターン・マッチングと呼ばれる、より高度な構造を今後のリリースで導入することです。提案されている、言語レベルのこの機能を、正規表現のパターン・マッチング(すなわちregex)と混同しないでください。ここでのパターン・マッチングは、マッチ式(switchのcaseラベルを一般化したもの)をJavaでおなじみの単純な定数以外のものに適用できるように拡張することを指します。 たとえば、対象となるオブジェクトの値ではなく型と照合することもできます(これは型パターンと呼ばれています)。プログラマーにとって型パターンは、コンパイル時に型がわからないオブジェクトがあり、種類の異なる有効な選択肢が存在する場合に役立ちます。たとえば、JSONを解析している場合なら、出現する値は文字列、数値、ブール値、その他のJSONオブジェクトのいずれかになります。解析後に型パターンを使えば、値を表すオブジェクトの型と照合を行うことで、値がString、Double、Booleanの場合に特化した処理を作成できるでしょう。 Javaフレームワークは、この種の動的な柔軟性をJava言語にたびたびもたらしています。この柔軟性が言語レベルで直接サポートされれば、大きな一歩になるでしょう。 シールド型の導入により、このオブジェクトの型はX、Y、Zのいずれかであり、その他の型ではないと断言できるようになります。このオブジェクト指向的な考え方は非常に強力です。switch式における列挙型で紹介した網羅性が、型レベルでも実現できるようになります。シールド型では、Javaの既存の列挙型言語機能に似た機能を提供しますが、列挙型は「存在し得るインスタンスが有限個」であるのに対し、シールド型は「存在し得る型が有限個」となります。 マッチ式、シールド型、そしてその他の開発中のJVM技術を組み合わせれば、関数型スタイルとオブジェクト指向スタイルの両方のプログラミングに対するJavaのサポートがさらに拡張されることになります。 早期アクセス・バイナリはまだ公開されていないため、早速シールド型を試してみたい開発者の方は、ソースから自分用のOpenJDKバイナリをビルドする必要があります。なお、特定の言語機能を含む確定版のJavaが提供されるまでは、そのバイナリを信頼すべきではない点に注意してください。本記事のように、将来のことや、今後導入される見込みの機能について取り上げている場合、純粋に探求目的のみで将来の見込みを説明していることを常に理解しておいてください。本記事の説明は、ここで取り上げた機能をサポートした確定版のJavaが実際に提供されるということを、誰か(オラクルを含む)に代わって確約するものではありません。 Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 Javaにテキスト・ブロックが登場 TeaVMを使ってブラウザでJavaを動かす ツールをよく知る クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Ben Evans Ben Evans(@kittylyst):Java ChampionおよびjClarityの創業者/技術フェローであり、London Java Community(LJC)主催者。Java SE/EE Executive Committeeのメンバーでもある。先日発刊された『Optimizing Java』(O'Reilly)を含め、プログラミングに関する4冊の書籍を執筆している。 ※本記事は、Ben Evans”Inside the Language: Sealed Types“を翻訳したものです。

パターン・マッチング、列挙型およびswitch文の改善に向けて進化するJava 著者:Ben Evans 2019年10月16日 本記事では、Javaにとって新しいプログラミング言語概念である、シールド型について説明します。この機能は現在活発に開発が行われており、将来のバージョンのJavaに導入される見込みです。シールド型の実現に必要な、プラットフォームレベルの重要な仕組みが、Java 11のネストメイ...

Javaにテキスト・ブロックが登場

code { font-family: courier, "courier new", monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } 長く待ち望まれてきた複数行文字列がJava 13で実現 著者:Mala Gupta 2019年10月16日 Java 13のテキスト・ブロックを使うことで、複数行文字列リテラルを簡単に使えるようになります。文字列リテラル内の特殊文字をエスケープすることや、複数行にまたがる値に連結演算子を使うことは不要になります。さらに、文字列を書式設定する方法も制御できるようになります。テキスト・ブロックとは、複数行文字列を表すJavaの用語です。テキスト・ブロックにより、コードの可読性は大幅に向上します。 本記事では、テキスト・ブロックとは何か、テキスト・ブロックによって対処できる問題、そしてテキスト・ブロックの使い方について説明します。それでは始めます。 テキスト・ブロックとは Stringデータタイプはおそらく、Java開発者がもっともよく使う型の1つです。任意の言語で数文字の文字列から複数行文字列まで、何でも格納できます。しかし、この柔軟性のため、一部のString値を読み取ることや変更することが難しくなる場合があります。例を挙げるなら、引用符が埋め込まれている文字列、エスケープ文字、複数行にわたる文字列などです。 それでは、Java 13の新しいプレビュー機能であるテキスト・ブロックが、どのように役立つかについて見ていきます。 テキスト・ブロックを使用して、複数行Stringリテラルを簡単に定義することができます。通常のStringリテラルを使って実現した場合に見にくさの原因となる、連結演算子やエスケープ・シーケンスの追加が不要です。さらに、String値をどのように書式設定するかも制御できます。例として、次のHTMLスニペットについて考えてみます。 String html = """ <HTML> <BODY> <H1>"Java 13 is here!"</H1> </BODY> </HTML>"""; ブロックの開始と終了を表す3つの二重引用符に注目してください。以前のJavaでは代わりにどのように記述していたかについて考えてみます。 String html1 = "<HTML>\n\t<BODY>\n\t\t<H1>\"Java 13 is here!\"</H1> \n\t</BODY>\n</HTML>\n"; 次の方が一般的かもしれません。 String html = "<HTML>" + "\n\t" + "<BODY>" + "\n\t\t" + "<H1>\"Java 13 is here!\"</H1>" + "\n\t" + "</BODY>" + "\n" + "</HTML>"; いずれも、テキスト・ブロックほどわかりやすくはありません。 構文 前述のように、テキスト・ブロックは、3つの二重引用符(""")を、開始および終了を表すデリミタとして使って定義します。開始デリミタの後には、0個以上の空白と行終端文字(改行)を置くことができます。テキスト・ブロックの値は、この行終端文字の後から始まります。終了デリミタの場合、このようなルールはありません。 したがって、次の例は無効なテキスト・ブロックとなります。開始デリミタの後に行終端文字が存在しないからです。 String multilineValue1 = """ """; String multilineValue2 = """"""; プレビュー言語機能 テキスト・ブロックは、Java 13でプレビュー言語機能としてリリースされました。しかし、プレビュー言語機能は未完成または開発途中の機能ではありません。実際のところ、開発者に使ってもらう準備は整っているものの、細かい部分は今後のJavaリリースで変更される可能性もある機能という意味です。このような扱いになっていることには、理由があります。 開発者は、6か月周期の新しいリリース・サイクルにより、言語の新機能を使えるようになっています。しかし、Javaチームは、Javaに言語機能を恒久的に追加する前に、その機能に対する開発者の意見について評価します。フィードバック次第で、プレビュー機能が微調整されてからJava SEに追加されることも、完全に削除されることもあります。そこで、テキスト・ブロックについてフィードバックがある方は、JDKメーリング・リスト(メンバー登録が必要です)で共有してください。 プレビュー言語機能を使うためには、コンパイル時と実行時に明確に有効化する必要があります。これにより、意図せずにプレビュー機能を使ってしまうことがないようにしています。テキスト・ブロックを含むソース・ファイルをコンパイルするためには、--enable-previewオプションと-release 13オプションを使用します。コマンドラインを使ってソース・ファイルJava13.javaをコンパイルする例を次に示します。 javac --enable-preview --release 13 Java13.java プレビュー機能は変更される可能性もあることを強調するため、先ほどのコマンドを実行した際に、図1のようなコンパイラ警告が表示されます。 図1:>プレビュー機能が使われているコードに対して表示されるコンパイラ警告 クラスJava13を実行するときも、--enable-previewオプションを使う必要があります。 java --enable-preview Java13 次は、テキスト・ブロックの実装について見てみます。 同じStringデータタイプ 従来のString値もテキスト・ブロックも、コンパイルされると同じ型、すなわちStringになります。バイトコードのクラス・ファイルでは、String値が従来のStringによるものか、テキスト・ブロックによるものかは区別されません。このことは、テキスト・ブロックの値が文字列プールに格納されていることを示しています。 次のコードをご覧ください。皆さんは、変数traditonalStringとtextBlockStringが同じStringインスタンスを指すと思うでしょうか。 String traditionalString = "Java"; String textBlockString = """ Java"""; System.out.println(traditionalString == textBlockString); この2つは内容が同じであるため、同じインスタンスを指します。先ほどのコードでは、trueが出力されます。 本記事の冒頭で、従来のStringでは複数行のString値が扱いづらくなることについて説明しました。続くいくつかのセクションでは、テキスト・ブロックがどのように役立つかについて取り上げます。 複数行の値の扱いを改善 開発者は、JSON、HTML、XMLや正規表現(regex)データなどの複数行文字列値を頻繁に扱います。テキスト・ブロックを使うことで、複数行JSON値の扱いが次のようにシンプルになります。 String json = """ { "name": "web", "version": "1.0.0", "dependencies": "AppA" } """; エスケープ・シーケンスや連結演算子によって見にくくなることがないため、JSON値を容易に編集できます。念のため、メリットを感じないと思う方のために、従来のStringで同じJSON値を定義した場合の例も挙げておきます。 String json = "{" + "\"name\": \"web\"," + "\"version\": \"1.0.0\"," + "\"dependencies\": \"AppA\" + "}"; この例は、読者のSven Bloesl氏の提案によって改善されています。 SQL問合せをString値として格納するためには、SQL問合せをコピーして貼り付けるか、または自分で書くかのいずれかを行います。String変数を使って(Java 12またはそれ以前のバージョンで)複数行SQL問合せを次のようにして格納したとします。 String query = "SELECT name, age" + "FROM EMP" + "WHERE name = \'John\'" + "AND age > 20"; このコードは、無効な問合せを表しています。各行の末尾に空白がないため、この問合せは次のように解釈されます。 SELECT name, ageFROM EMPWHERE name = 'John'AND age > 20 Karim Ourrai氏とBrian Goetz氏の報告により、誤った例がこのセクションから削除されました。 テキスト・ブロックを使うことにより、同じような問題を避けることができます。 String query = """ SELECT name, age FROM EMP WHERE name = 'John' AND age > 20 """; テキスト・ブロック内のエスケープ・シーケンス Stringリテラルと同様に、テキスト・ブロックにもさまざまなエスケープ・シーケンスを追加できます。たとえば、テキスト・ブロックに新しい行を含める場合、値を複数行にわたって配置することも、\nのようなエスケープ・シーケンスを使うこともできます。次のコードでは、I'mとhappyは別々の行になります。 String html = """ <HTML> <BODY> <H1>I'm \nhappy</H1> </BODY> </HTML>"""; ご想像のとおり、無効なエスケープ・シーケンスやエスケープしていないバックスラッシュは許可されません。 意味のない空白とインデント 大きな疑問として、不要な空白がどのように扱われるかが挙げられます。実は、この点はコンパイラがエレガントに処理してくれます。テキスト・ブロックでは、すべての行で一番左側にある非空白文字、または一番左側にある終了デリミタによって、意味のある空白が始まる場所が定義されます。 図2の場合、getHTML()で返されるString値の中で、一番左側にある非空白文字は<(<HTML>の最初の部分)です。この位置は、終了デリミタの位置とも一致しています。 図2:>不要な空白(青)と意味のある空白(緑)を表したコード このコードでは、図3に示す文字列が返されます(最初と最後の行では、先頭に空白が含まれません)。 図3:>先ほどのコードから返される文字列(緑色の四角は文字列に含まれる空白を示します) 空白が削除されないように、必須としてマークするためには、終了デリミタ、またはいずれかの非空白文字を左に動かします。図4に示すように、終了デリミタ"""を8文字分左に動かしてみます。 図4:>終了デリミタを左に動かした、図2のコード 変更したコードでは、図5に示すString値が返されます。各行の先頭に8文字分の空白(緑色の四角)が追加されています。その他の空白も緑色の四角で表されています。 図5:>図4のコードから出力される文字列(先頭に空白(緑色の四角)が追加されています) デフォルトでは、それぞれの行の末尾にある空白はテキスト・ブロックから削除されます。その空白を保持する必要がある場合は、8進エスケープ・シーケンス\040(ASCIIでは、空白は文字32となります)を使って強制的に空白を含めることができます。次に例を示します。この例では、テキスト・ブロックの2行目の末尾に空白を追加しています。 String campaign = """ Don't leave home without - money &\040 carry bag. Reduce | Reuse """; なお、必須の空白にタブ(\t)が含まれている場合、タブは展開されず、1つの空白としてカウントされることに注意してください。 テキスト・ブロックの連結 テキスト・ブロックは、従来のString値と連結できます。その逆も可能です。次に例を示します。 String concatenate() { return """ Items to avoid - Single Use Plastics """ + "Let's pledge to find alternatives"; } String値を連結する理由の1つに、変数の値の挿入があります。 String concatenate(Object obj) { return """ Items to avoid - Single Use """ + obj + """ Let's pledge to find alternatives"""; } テキスト・ブロックは、文字列が想定される任意の場所で使うことができます。そのため、たとえばString.replaceメソッドでも、特別な処理をせずに使うことができます。 String concatenateReplace(Object obj) { return """ Items to avoid - Single Use $type Let's pledge to find alternatives""".replace("$type", obj.toString()); } 同じように、format()をはじめとする、Stringの任意のメソッドも使用できます。 まとめ テキスト・ブロックにより、開発者は複数行文字列値をより簡単に扱えるようになります。現時点でテキスト・ブロックはプレビュー機能であり、変更される可能性もあることに留意してください。 ただし、そのような状況ではあっても、コーディング作業を大いに軽減してくれるはずです。 Java Magazine 日本版Vol.47の他の記事 Java 13のswitch式と再実装されたSocket APIの内側 言語の内側:シールド型 TeaVMを使ってブラウザでJavaを動かす ツールをよく知る クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Mala Gupta Mala Gupta(@eMalaGupta):Java Champion。JetBrainsのデベロッパー・アドボケート。eJavaGuru.comの創設者で、認定試験に関する何冊かの人気書籍を執筆。Delhi Java User Groupの共同リーダーであり、Women Who Codeデリー支部のディレクターも務める。 ※本記事は、Mala Guptaによる”Text Blocks Come to Java“を翻訳したものです。

長く待ち望まれてきた複数行文字列がJava 13で実現 著者:Mala Gupta 2019年10月16日 Java 13のテキスト・ブロックを使うことで、複数行文字列リテラルを簡単に使えるようになります。文字列リテラル内の特殊文字をエスケープすることや、複数行にまたがる値に連結演算子を使うことは不要になります。さらに、文字列を書式設定する方法も制御できるようになります。テキスト・ブロックとは、複数行文字...

Java 13のswitch式と再実装されたSocket APIの内側

code { font-family: courier, "courier new", monaco !important; font-size: 17px !important; color: #00488a !important; margin: 0 !important; background-color: #fff !important; padding: 0 5px !important; display: inline !important; } 段階的変更により、将来のメリットが今回のリリースに含まれるように 著者:Raoul-Gabriel Urma、Richard Warburton 2019年10月16日 時がたつのは早いものです。予定どおり、2019年9月にJDK 13がリリースされました。Java 13では、開発者の興味を引くアップデートが主に3つ行われています。 switch式(プレビュー機能)を新しいyield文により改善 言語プレビュー機能として、複数行文字列リテラル(テキスト・ブロック)を導入 Socket APIの実装を最新化 本記事では、switch式とSocket APIに注目します。テキスト・ブロックについては、本号の別の記事で特集しています。 switch式(プレビュー機能) 以前の記事で、JDK 12のプレビュー機能として導入されたswitch式を紹介しました。switch式はJDK 13でもプレビュー機能のままですが、これが意味するのは、プレビュー・モードを卒業するまでは今後のリリースで変更される可能性があるということです。さらに、機能を開放する必要があることも表しています。switch式を有効にするためには、次のコマンドを実行する必要があります(Example.javaというファイルがあるものとします)。 javac --enable-preview --release 13 Example.java java --enable-preview Example switchの新機能に入る前に、簡単にJDK 12をおさらいしておきます。JDK 12では、式形式のswitchが導入されています。この形式のswitchを使うことで、以前の記事で紹介したいくつかのメリットを享受できます。たとえば、次のようなものです。 フォールスルー:switchの新しい構文ではフォールスルーが発生しません。これにより、バグが発生する可能性を減らすことができます。 複合形式:新しいswitch式では、1つの分岐条件で複数のcaseラベルを扱うことができます。これにより、コードの冗長性を減らすことができます。 網羅性:新しいswitch式を使った場合、可能な列挙値すべてに対して、対応するswitchラベルが存在することをコンパイラが確認してくれます。これにより、バグが発生する可能性がまた少なくなります。 式形式:次の例で示すように、switchを式形式で使えることから、コードが短くなるとともに、コードの意図をより明確に表現できるようになります。次の例では、列挙型をswitchで条件分岐して適切に文字列を返しています。 var log = switch (event) { case PLAY -> "User has triggered the play button"; case STOP -> "User needs a break"; default -> "No event to log"; }; この例からわかるように、アロー構文を使ったワンライナーで簡単な式を返すことができます。しかし、分岐のコードが複数行にまたがる複数の文(ブロック式)の場合、どのように値を返すかはわかりやすくはありませんでした。return文は、呼び出されたメソッド自体から戻ることを示すため、使うことはできません。JDK 12では、switch式自体から値を返す場合、break文を使いました。これは、次に示す例のコードの最終行のように、値付きのキーワードをオーバーロードしているため、少々不格好です。  var log = switch (event) { case PLAY -> "User has triggered the play button"; case STOP -> "User needs a break"; default -> { String message = event.toString(); LocalDateTime now = LocalDateTime.now(); break "Unknown event " + message + " logged on " + now; } }; 上記のコードはJDK 12のプレビュー・モードではコンパイルできますが、JDK 13では動作しなくなります。 JDK 13では、この動作を実現するためにyield文が導入されています(コードの最終行をご覧ください)。  var log = switch (event) { case PLAY -> "User has triggered the play button"; case STOP -> "User needs a break"; default -> { String message = event.toString(); LocalDateTime now = LocalDateTime.now(); yield "Unknown event " + message + " logged on " + now; } }; それでは、break、return、yieldはどう違うのでしょうか。return文は呼出し元に制御を戻し、yieldはもっとも内側にあるswitch式に制御を戻すと考えることができます。breakキーワードは、switch文から抜け出すためのものです。なお、yieldの導入により、Javaのキーワード管理と予約済み識別子に関連して、拡大した議論が始まっていることに注目してください。returnとbreakはキーワードですが、yieldは現在、JDK 10で導入されたvarのような限定識別子として提案されています。この2つの違いは小さなものですが、この違いが重要になる場合もあります。breakを変数名として使うことはできません。その理由は、breakがキーワードであるからです。しかし、varは限定識別子であるため、変数名として使うことができます。 switch式へのyield文の導入は小さな変更ですが、言語にyield文が導入されることによって、将来的な可能性が開かれることになります。というのは、yield文を他の機能に使用できる可能性もあるからです。たとえば、他の多くのプログラミング言語では、コルーチンやジェネレータなどの高度な構造を実現する方法として、yieldという単語が採用されています(たとえば、PythonやJavaScript、Scalaでサポートされています)。一方、現在のJavaで文としてのyieldがサポートされているのはswitch式のみであることを覚えておくことは重要です。 yieldという名前が付いた別の機能(Thread.yieldなど)や、他のプログラミング言語の機能とは混同しないでください。 Socket API 多くの場合、OpenJDKなどの実績ある長命のソフトウェア・プロジェクトは、内部に多くの古いコードを抱えています。こういったコードは、メンテナンスと改善が必要であるにもかかわらず、長期間存在しています。最近のJavaリリースでは、古いコードベースを改善して新機能を追加するために、多くの作業が行われています。Java 13もその例外ではありません。Java 13では、古いSocket APIが完全に再実装されています。その対象になった機能と、理由について確認します。 Java標準には、低レベルTCPネットワーク構成を実装する複数のAPIが含まれています。このAPIを大きく分類すると、「New IO」(NIO)サブシステムと、古いI/Oシステムに分かれます。導入されてからすでに15年が経過したNIOは、この2つのうち新しい方の実装で、非同期APIと同期APIの両方が含まれています(現在、一からTCPを記述している方は、古いI/Oシステムではなく、NIOや高レベルライブラリ(Nettyなど)を使うべきです)。 従来のI/Oライブラリは、古いAPIであるにもかかわらず、現在もJavaエコシステム全体で広く使われています。少しGitHubを検索しただけでも、11,046件のコミットがあり、古いSocketクラスは100万回を超えて参照されていることがわかります。そのため、今後のバージョンのJavaでもこのAPIのメンテナンスがやはり必要であることは明らかです。それでは、Java 13でまったく新しく実装し直す必要があったのはなぜでしょうか。この問いに答えるためには、JDK開発の全体像を理解する必要があります。 現在、OpenJDKで行われている大規模なプロジェクトの1つに、Project Loomがあります。このプロジェクトは、JVMによるFiberの実装です。Fiberは、オペレーティング・システムのスレッドとの対応関係が1対1ではない軽量スレッドです。実際には、1つのオペレーティング・システムのスレッドで、数百や、場合によっては数千のFiberが動作している可能性もあります。Fiberでは、スレッドの動作をブロックしないように考慮されています。Fiberでロックの使用やスリープが必要になった場合、ベースとなるスケジューラはそのスレッドに別のFiberをスワップ・インし、動作を継続させます。 Javaのソケット・オブジェクトはスレッドセーフな設計になっているため、内部的にロック(つまり、同期ブロック)を使ってI/O操作の競合状態を回避します。この実装の大部分は古いCコードです。このコードでは、I/Oバッファとしてスレッド・スタックが使われ、ネイティブ・ロックも使われています。 Project Loomでは、ネイティブCのロックではなく、Java 5のロック(つまり、java.util.concurrent.lockパッケージ)を使ってFiberを効率的に切り替える仕組みがサポートされる予定です。そのため、JDKのすべてのブロッキング・コードをJava 5のロックに移行する必要があります。つまり、Project Loomとの両立性を高めるため、古いSocket APIの再実装が必要だったのです。 ただし、書き換えの動機はそれだけではありませんでした。驚くべきことではありませんが、古いSocket APIには、膨大な問題を抱えた、古くてメンテナンス性の低いコードが数多く含まれています。ネイティブ・ロックとネイティブ・バックエンドのコードには、前述のLoomとの連携に関する問題のほか、メンテナンス上の問題もありました。さらに、JDKに古いSocket APIとNIO APIの両方が存在したため、JDK開発者は2つの異なる実装をメンテナンスする必要がありました。1つの実装を使うことができれば、それに伴ってメンテナンスの負荷も低くなるでしょう。 一言で言えば、Java 13では、NIOと同じベースのインフラストラクチャと実装を使って、古いSocket API用の新しいバックエンドを実装しています。Java 11リリースの一環として、NIOはJava 5のロックを使うように移行されました。そのため、すでにFiberとの親和性があります。今回の変更にはその既存作業が活用され、その結果、Java 13の古いSocket APIにもFiberとの親和性が生まれています。また、JDKで2つのI/Oバックエンドをメンテナンスする必要もなくなっています。 移行の負荷を軽減するため、jdk.net.usePlainSocketImplシステム・プロパティをtrueに設定することで、古い実装を有効化できるようになっています。 APIは変更されていないことから、動作の互換性を別にすれば、この変更に関連する主要なリスクはパフォーマンスです。 OpenJDKプロジェクトでは、変更のパフォーマンスを評価するために使われる一連のマイクロベンチマークがメンテナンスされています。このベンチマークをUbuntu Linux 18.04 / AMD Ryzen 7 1700マシンで実行し、Java 8のSocket API実装と、書き換えられたJava 13のSocket API実装のパフォーマンスを比較してみました。  図1と図2は、それぞれタイムアウトがある場合とない場合で、java.net.Socket APIを使ってTCPのパケットを読み書きするSocketReadWrite.echoベンチマークのパフォーマンスを示したものです。このベンチマークを、1バイトから128,000バイトのサイズのメッセージに対して実行しました。このベンチマークでは、Socketオブジェクト自体のtimeoutプロパティを有効および無効にしています。   図1:タイムアウトがある場合のパフォーマンス   図2:タイムアウトがない場合のパフォーマンス さらに、I/O Streams APIを使ってパフォーマンスをテストするSocketStreaming.testSocketInputStreamReadベンチマークも実行しました。このベンチマークでは、Java 8とJava 13の両方の実装で44ミリ秒/opが達成されました。 以上のベンチマークから、パフォーマンス面での差異に気づくJavaプロジェクトが多いとは考えにくいことがわかります。差は極めて小さく、測定ツールの誤差の範囲内です。なお、この分析の注意事項として、このベンチマークはSocket APIが使われるすべてのシナリオを代表したものではないことを付記しておきます。そのため、パフォーマンスの問題を発見した場合は、バグとして報告する方がよいでしょう。 まとめ Java 13では、いくつかの変更や改善がJava開発者に提供されています。そのいずれもが、調べてみるだけの価値があるものです。複数行文字列が導入され、yieldキーワードの追加によってswitch式が改善されています。これらは、Java SEプラットフォームへの継続的な注力や改善を実証するプレビュー機能です。 さらに、古いSocket APIの書き換えは、Fiberといった将来の機能のリリースへの対応に向けて内部的に行われている継続的な作業の一例です。Java言語は、Javaらしいスタイルと大きなライブラリ・エコシステムを維持しつつ、積極的に改善を繰り返そうという気概にあふれています。そのため、Javaは今後も特に人気の高いプログラミング言語であり続けることでしょう。 Java Magazine 日本版Vol.47の他の記事 Javaにテキスト・ブロックが登場 言語の内側:シールド型 TeaVMを使ってブラウザでJavaを動かす ツールをよく知る クイズに挑戦:1次元配列(中級者向け) クイズに挑戦:カスタム例外(上級者向け) クイズに挑戦:ロケールの読取りと設定(上級者向け) クイズに挑戦:関数型インタフェース(上級者向け) Raoul-Gabriel Urma Raoul-Gabriel Urma(@raoulUK):イギリスのデータ・サイエンティストや開発者の学習コミュニティをリードするCambridge SparkのCEO/共同創業者。若いプログラマーや学生のコミュニティであるCambridge Coding Academyの会長/共同創設者でもある。ベストセラーとなったプログラミング関連書籍『Java 8 in Action』(Manning Publications、2015年)の共著者として執筆に携わった。ケンブリッジ大学でコンピュータ・サイエンスの博士号を取得している。   Richard Warburton Richard Warburton(@richardwarburto):Java Championであり、ソフトウェア・エンジニアの傍ら、講師や著述も行う。ベストセラーとなった『Java 8 Lambdas』(O'Reilly Media、2014年)の著者であり、Iteratr LearningとPluralsightで開発者の学習に貢献し、数々の講演やトレーニング・コースを実施している。ウォーリック大学で博士号を取得している。 ※本記事は、Raoul-Gabriel Urma、Richard Warburtonによる”Inside Java 13’s switch Expressions and Reimplemented Socket API“を翻訳したものです。

段階的変更により、将来のメリットが今回のリリースに含まれるように 著者:Raoul-Gabriel Urma、Richard Warburton 2019年10月16日 時がたつのは早いものです。予定どおり、2019年9月にJDK 13がリリースされました。Java 13では、開発者の興味を引くアップデートが主に3つ行われています。 switch式(プレビュー機能)を新しいyield文により改善 言語プレビュ...

津島博士のパフォーマンス講座 第74回 パラレル実行とリソース管理について

津島博士のパフォーマンス講座 Indexページ ▶▶   皆さん、明けましておめでとうございます。今年も素敵な一年になりますようお祈り申し上げます。 今回は、苦労されている方も多い、パラレル実行と同時実行のリソース管理について説明しようと思います。後半に、これが簡単に利用できるようになっているOracle Autonomous Databaseについても説明していますので、参考にしてください。   1. パラレル実行の同時実行管理 パラレル実行は、第20回で説明したように、処理時間を大幅に短縮することができますが、同時実行するとある時点でリソース制限に行きあたるので、SQL文ごとのパラレル度(DOP)と同時実行するSQL数との間でバランスをとることが大事になります。自動DOPフレームワーク(自動DOPとパラレル・ステートメント・キューイング)を使用することで、ユーザーの介在なしにパラレル処理の使用状況を総体的に(バランスよく)制御することが可能です(自動DOPは、Oracle12cからDBMS_RESOURCE_MANAGER.CALIBRATE_IOプロシージャを実行しない場合でも、デフォルト値を使用して動作するようになりました)。ただし、優先順位の高いSQLなどもあるので、第40回で説明したDatabase Resource Managerと一緒に制御する方がより効果的です。これまでは、自動DOPフレームワークとリソース管理の使い方までは説明していなかったので、以下についてのガイドをまとめてみました。 パラレル実行(PX)サーバー・プロセス数の管理 パラレル・ステートメント・キューイング(PSQ)を使用したパラレル処理の管理 Database Resource Manager(DBRM)を使用したパラレル処理の管理   (1)PXサーバー・プロセス数の管理 まずは、パラレル実行に使用されるPXサーバー・プロセス数の決定について説明します。 PXサーバー・プロセスは、プロセスのプール(PARALLEL_MAX_SERVERS初期化パラメータで最大数を設定)からパラレル操作に割り当てます。デフォルトでは、以下のように設定されるので、基本はこれで問題ありません(CPU時間の割合が多いSQL文のときには、CPU使用率の確認を行うようにしてください)。 PARALLEL_MAX_SERVERS = 5 × <concurrent_parallel_users> × <デフォルトDOP> デフォルトDOPは、CPU_COUNT×PARALLEL_THREADS_PER_CPU×起動インスタンス数(RAC環境のみ)になり、自動DOPではデフォルト最大DOPとして使用されます(PARALLEL_THREADS_PER_CPU初期化パラメータのデフォルトは、Oracle18cから1になっていますが、インテルのHyperThreading機能が無効のときは2の方が最適です)。 concurrent_parallel_usersの値は、初期化パラメータMEMORY_TARGET、SGA_TARGET、PGA_AGGREGATE_TARGETによって以下のようになります(参考までに、デフォルトDOPでの同時実行数も載せておきました)。   MEMORY_TARGET/SGA_TARGET PGA_AGGREGATE_TARGET concurrent_parallel_users デフォルトDOPの同時実行数 設定 - 4 10(5*4/2) 未設定 設定 2 5(5*2/2) 未設定 未設定 1 2(5*1/2)   パラレルSQL文は、プール内のプロセスがすべて割り当てられると、シリアル(非パラレル)実行またはDOPがダウングレードされてパフォーマンスが低下します。そのため、自動DOPの場合は、もう1つの制限として、PSQの前に使用可能なPXサーバー・プロセス数(PARALLEL_SERVERS_TARGET初期化パラメータ)が使用されます。デフォルトは、PARALLEL_MAX_SERVERSの40%で、キューを迂回するパラレルSQL文のために、いくらかのバッファが確保されています(存在しない場合は増やしてください)。なお、PSQをアクティブ化しても、シリアルSQL文はすべて即時実行されます。PARALLEL_SERVERS_TARGETが考慮されるのは、PARALLEL_DEGREE_POLICY初期化パラメータをAUTOまたはADAPTIVEに設定している場合のみです(ADAPTIVEでは、第33回で説明したパフォーマンス・フィードバックも動作しますが、Oracle18cからOPTIMIZER_ADAPTIVE_STATISTICS初期化パラメータがFLASEでも動作するようになりました)。   (2)PSQを使用したパラレル処理の管理 次に、同時実行を制御するPSQの調整方法について説明します。 同時実行の制御は、第20回でPARALLEL_ADAPTIVE_MULTI_USER初期化パラメータも可能ですと説明しましたが、Oracle12cR2からデフォルトはFALSEになり非推奨となりましたので、PSQを使用してください。 自動DOPフレームワークでは、PSQを使用してPXリソースが使用可能になってから実行させるので、調整ポイントはSQL文が長時間キューイングされていないかになります(以下の手順で確認するようにしてください)。 SQL文がキューで待機していないかを待機イベント'resmgr: pq queued'(11.2.0.2から)で確認する。 キューイングされているSQL文は、以下のSQL(V$SQL_MONITOR/GV$SQL_MONITORビュー)またはOracle Enterprise ManagerのSQLモニター画面を使用して特定する。 SQL> SELECT sql_id, sql_text, rm_consumer_group FROM V$SQL_MONITOR WHERE status='QUEUED'; SQL文がPSQにより遅くなっている場合は、以下の手順で検討を行ってください。 SQLが最適に実行しているか(できるだけSQLチューニングを行い最適な実行計画にする) パラレルになる最小実行時間(PRALLEL_MIN_TIME_THRESHOLD)を大きくできないか(パラレルSQL文を減らす) 最大DOP(PARALLEL_DEGREE_LIMIT)を下げられないか(またはDBRMで複数レベルの最大DOPにできないか) PARALLEL_SERVERS_TARGETを大きくできないか(リソースに余裕がある場合) ワークロードに対してシステムのサイズが小さすぎないか また、キューイングさせたくないパラレルSQL文は、NO_STATEMENT_QUEUINGヒントを使用するか、第40回で説明したPARALLEL_STATEMENT_CRITICALパラメータがBYPASS_QUEUEに設定しているユーザーで実行すると、PSQをバイパスしてすぐに実行できます。   (3)DBRMを使用したパラレル処理の管理 次に、PSQの優先順位が設定できるDBRMについて説明します。 第40回の「パラレル・ステートメント・キューイングのリソース管理について」で説明したように、DBRMと一緒に使用してリソース・コンシューマ・グループ(コンシューマ・グループ)ごとにPSQのキューを管理することで、以下のことができるようになります。 個々のSQL文やコンシューマ・グループ全体で使用できるPXサーバー数を制御する 優先順位の高いコンシューマ・グループに、より多くのPXリソースを割り当てる ユーザー毎に異なるキューを割り当て、優先順位の高い要求が低い要求の後にキューイングさせない そのため、同時実行環境でパラレル実行する場合は、DBRMで複数のコンシューマ・グループを使用することを強くお勧めします(この後のAutonomous Databaseの設定を参考にすると良いと思います)。 また、これから使用する機会が多い(Autonomous Databaseでも使用されている)PDBのリソース管理についても説明しておきます。   PDB(プラガブル・データベース)について ご存知ない方のために、ここでマルチテナント・アーキティクチャ(MTA)のPDBについて簡単に説明します。 MTAは、データベースのマルチテナント(1つのシステムに複数のサービスが同居している環境)を効果的に実現するために、Oracle12cから一つのインスタンス(メモリー、バックグランド・プロセス)上で、複数の仮想的なデータベースを稼働するようにした機能です。インスタンスが動作するマルチテナント・コンテナ・データベース(CDB)と、それに内包される一つ以上のPDBで構成され、これまでのデータベース(非CDBと呼ぶ)からも変更せずに使用できます。このMTAにより、これまでのデータベース統合の課題(スキーマ分割はリソースを分割できない、複数データベースや仮想マシンは個々に必要なリソースや管理コストなどが増える)を以下のように解決し、ITコストの削減に貢献することが可能になります。 高密度の統合 CDB上のCPUやインスタンスを共有することで、リソースを有効に活用でき(PDB間の動的なリソース管理もでき)、高いパフォーマンスと集約密度(1サーバー当たりのデータベース数)の向上を実現します。 多数のデータベースの一元管理 アップグレードやパッチ適応、バックアップ/リカバリ、インスタンス・チューニングなどを、CDBレベルで行うことで、管理コストを削減します(CDB全体のバックアップからPDB単位でのリカバリ、他のPDBに影響させずにバッファ・キャッシュのフラッシュなども可能です)。 迅速なプロビジョニング 様々なプロビジョニング(CDB内に新しいPDBを作成する、既存のPDBをクローンする、既存の非CDBをPDBとしてCDBに移行、切断したPDBを異なるCDBに接続するなど)を簡単および迅速にできることで、いろいろな場面で効果的に使用することが可能になります。   PDBリソース管理は、以下のように、2つのレベルのリソース・プランをsharesパラメータ(共有値:リソースの割合)で作成して行います(DBRMを使用しないと、初期化パラメータだけで制御することになります)。 CDBリソース・プラン CDBリソース・プランを作成し、優先度に従ってPDBごとにリソースを配分します(作成しないでPDBリソース・プランが作成されると、付属のDEFAULT_CDB_PLANが使用されます)。sharesは、PDBに対するソフト・リミットになるので、CPUリソースの上限値はutilization_limitパラメータ(またはCPU_COUNT初期化パラメータ)、PXサーバー数の上限値はparallel_server_limitパラメータ(またはPARALLEL_SERVERS_TARGET初期化パラメータ)で制御します(Oracle12cR2からメモリー関連やI/O関連も初期化パラメータで指定できます)。 PDBリソース・プラン PDBに接続してPDBリソース・プランを作成し、PDB内のコンシューマ・グループごとにリソースを配分します。これまでの非CDBリソース・プランと同じように行いますが、いくつかの制限(ディレクティブのレベル数、コンシューマ・グループ数、サブプランを設定できない)があります。リソース割り当ては、マルチレベル管理ディレクティブ(mgmt_p2からmgmt_p8)は使用できないので、mgmt_p1またはOracle12cからのsharesを使用します(推奨はsharesです)。 以下に、設定している例を載せておきます(CPUリソースはCPU_COUNTを使用しています)。このCDBリソース・プランは、DEFAULT_CDB_PLANと同じですが、参考のために載せておきました。   -- CDBリソース・プラン作成 DECLARE l_plan VARCHAR2(30) := 'test_cdb_plan'; BEGIN DBMS_RESOURCE_MANAGER.clear_pending_area; DBMS_RESOURCE_MANAGER.create_pending_area; -- CDBのプラン作成 DBMS_RESOURCE_MANAGER.create_cdb_plan(plan=>l_plan, comment=>'test CDB resource plan'); -- PDB(pdb1)にリソース配分 DBMS_RESOURCE_MANAGER.create_cdb_plan_directive(plan=>l_plan, pluggable_database=>'pdb1', shares=>1); …<他のPDBは省略>… DBMS_RESOURCE_MANAGER.validate_pending_area; DBMS_RESOURCE_MANAGER.submit_pending_area; END; / -- PDBリソース・プラン作成 ALTER SESSION SET CONTAINER = pdb1; -- PDB(pdb1)に接続 ALTER SYSTEM SET CPU_COUNT = 10 SCOPE = BOTH; BEGIN DBMS_RESOURCE_MANAGER.clear_pending_area; DBMS_RESOURCE_MANAGER.create_pending_area; -- PDBのプラン作成 DBMS_RESOURCE_MANAGER.create_plan(plan=>'pdb1_plan', comment => 'pdb1 Plan'); -- コンシューマ・グループの作成とサービスのマッピング DBMS_RESOURCE_MANAGER.create_consumer_group(consumer_group=>'high', comment=>'high priority'); DBMS_RESOURCE_MANAGER.set_consumer_group_mapping (attribute=>DBMS_RESOURCE_MANAGER.SERVICE_NAME, value=>'pdb1_high', consumer_group=>'high'); -- プラン・ディレクティブをコンシューマ・グループに割り当てて優先順位やリソース制限を定義する DBMS_RESOURCE_MANAGER.create_plan_directive(plan=>'pdb1_plan', group_or_subplan=>'high', comment=>'High Priority - level 1', shares=>4, parallel_server_limit=>50, parallel_degree_limit_p1=>10); …<他のコンシューマ・グループは省略>… DBMS_RESOURCE_MANAGER.validate_pending_area; DBMS_RESOURCE_MANAGER.submit_pending_area; END; /   2. Oracle Autonomous Database 最後に、パラレル実行と同時実行が簡単に利用できるAutonomous Database(ADW:Autonomous Data WarehouseとATP:Autonomous Transaction Processing)について説明します。 同時実行する環境では、様々なことを考えて設定する必要があり、大変と思っている方も多いのではないでしょうか。そのため、何もしなくても効果的に実行できるように、事前設定されているのがAutonomous Databaseです(パラレルDMLもデフォルトで有効になっています)。また、管理を簡単にするために、それぞれをPDBとして作成されています。ここでは、参考のために、どのように設定されているかを簡単に説明します(非常によく考えられているので、参考になると思います)。 Autonomous Databaseでは、以下のようなコンシューマ・グループ(サービス)で事前定義されているので、どのサービスを使用するかを検討するだけになります(TPとTPURGENTはATPのみです)。そのため、性能を改善するには、OCPU(Oracle Compute Units:CPUコア)の数を増やすだけになります(OCPU数に比例して、メモリーサイズ、I/O帯域幅が拡張されるようになっています)。 サービス (コンシューマ・グループ) SHARES パラレル制御 PX Degree Limit PX Server Limit 同時実行セッション数 HIGH 4 自動DOP CPU_COUNT 50% 3(MEDIUMが存在しない場合) MEDIUM 2 自動DOP 4 84% 1.25×OCPU LOW 1 シリアル 1 - 100×OCPU TP 8 シリアル 1 - 100×OCPU TPURGENT 12 手動 - - 100×OCPU OTHER_GROUP 1 シリアル 1 - 100×OCPU   パラレル実行する場合は、HIGHとMEDIUMの2つのグループで最大DOPを使い分けることが可能です。初期化パラメータPARALLEL_MAX_SERVERSとPARALLEL_SERVERS_LIMITは、どちらもデフォルトではなく(3×4×<デフォルトDOP>)になっているので、HIGHの同時実行数は、MEDIUMの問合せが存在しない場合にpx_server_limitが50%から3となります(MEDIUMの問合せが存在する場合は、px_server_limitが84%になっているので、少なくても1つのSQL文は実行できます)。ATP用のTPURGENTは、最も優先度の高い(緊急度の高い)処理として、手動DOP(ヒントや表レベル)を使用できるようになっています。OTHER_GROUPは、デフォルト・コンシューマ・グループ(HIGH~TPURGENT)を使用しないときのグループになります。 sharesの割合は、2019/04新機能からCS_RESOURCE_MANAGER.update_plan_directiveプロシージャを使用して変更できるようになっています(OCIコンソールの「サービス・コンソール」→「Administration」→「Set Resource Management Rules」からも行えます)。例えば、以下のように変更(HIGHが6、MEDIUMが2、LOWが1)を行います。sharesは、ソフト・リミットになるので、高負荷のときに保証される割合になります。 BEGIN CS_RESOURCE_MANAGER.update_plan_directive(consumer_group => 'HIGH', shares => 6); CS_RESOURCE_MANAGER.update_plan_directive(consumer_group => 'MEDIUM', shares => 2); CS_RESOURCE_MANAGER.update_plan_directive(consumer_group => 'LOW', shares => 1); END; / コンシューマ・グループの設定内容は、以下のSQL(DBA_RSRC_PLAN_DIRECTIVESビュー)で、リソース・プラン・ディレクティブから確認できます('DWCS_PLAN'がADW、'OLTP_PLAN'がATP、そしてsharesがmgmt_p1になります)。 SQL> SELECT plan, group_or_subplan name, mgmt_p1 shares, parallel_server_limit, parallel_degree_limit_p1 2 FROM dba_rsrc_plan_directives 3 WHERE plan IN ('DWCS_PLAN', 'OLTP_PLAN') 4 ORDER BY 1,3 DESC ; PLAN NAME SHARES PARALLEL_SERVER_LIMIT PARALLEL_DEGREE_LIMIT_P1 ---------- ------------ ---------- --------------------- ------------------------ DWCS_PLAN HIGH 6 50 10 DWCS_PLAN MEDIUM 2 84 4 DWCS_PLAN LOW 1 1 DWCS_PLAN OTHER_GROUPS 1 1 このようにクラウド環境でもあるので、非常に簡単に管理ができるようになっています(慣れた管理者には、少し不自由さを感じるかもしれませんが、管理するシステムを削減できると思えば嬉しいことだと思います)。 Autonomous Databaseに興味を持たれた方は、「Autonomous Database ハンズオンラボ(HOL)」にハンズオン情報がありますので、使用してみてください。   3. おわりに 今回は、パラレル実行とリソース管理について説明しましたが、少しは参考になりましたでしょうか。これからも頑張りますので、今年もよろしくお願いします。 それでは、次回まで、ごきげんよう。 ページトップへ戻る▲    津島博士のパフォーマンス講座 Indexページ ▶▶

津島博士のパフォーマンス講座 Indexページ ▶▶   皆さん、明けましておめでとうございます。今年も素敵な一年になりますようお祈り申し上げます。 今回は、苦労されている方も多い、パラレル実行と同時実行のリソース管理について説明しようと思います。後半に、これが簡単に利用できるようになっているOracle Autonomous Databaseについても説明していますので、参考にしてください。   1....

OCIでブロック・ボリュームを複数インスタンスにアタッチする

  すばらしいお知らせがあります。ブロック・ストレージ・ボリュームを共有して、Oracle Cloud Infrastructure上の複数のコンピュート・インスタンスに接続できるようになりました。 これまでは、複数のブロック・ボリュームを1つのコンピュート・インスタンスに接続することはできましたが、ボリュームを接続して読取り/書込みアクセスができるのは、一度に1つのコンピュート・インスタンスからのみに制限されていました。他のパブリック・クラウド・ベンダーでも同じような設計上の制限がありますが、一部のベンダーでは、共有の読取り専用ボリュームへのアクセスが可能な場合もあります。 Oracle Cloud Infrastructureからの本発表に伴って、読取り/書込みアクセスに対応する共有可能なボリュームを、複数のコンピュート・インスタンスに接続できるようになりました。クラウド・ストレージでのこの独自の機能により、Oracle Cloud Infrastructure Block Volumeサービスが提供する共有可能なボリュームを使用して、クラスタ対応ソリューションをデプロイおよび管理できます。   クラスタ対応ソリューションによる同時書込み この機能自体が、複数のコンピュート・インスタンスからの同時書込みの調整を処理するわけではありません。クラスタ対応のシステムまたはソリューションを別途用意して、複数インスタンスが接続された共有ストレージの上位にデプロイする必要があります。複数の同時書込みを調整できるクラスタ対応ソリューションには、Oracle RAC(入手およびサポートはOracle Cloud Infrastructure Databaseサービスを通した場合のみ)、Oracle Cluster File System(OCFS2)、IBM Spectrum Scale(オラクルとIBMのパートナーシップを通して利用可能)、GlusterFSなどがあります。 複数インスタンスの接続とOCFS2を使用するソリューションのセットアップ方法の例について詳しくは、「複数インスタンスへのブロック・ボリュームのアタッチ機能を利用したOracle Cloud Infrastructure上の共有ファイル・システムの作成」というブログ記事をご覧ください。   ユースケース この新しい機能は、2017年5月に登場したOracle Cloud Infrastructure Databaseサービスをサポートすることをおもな目的としていました。しかし当社は、この機能を一般にも公開してほしいという多数の要望を受け取りました。この機能によって、可用性が高く、耐久性があり、費用対効果に優れ、柔軟なパフォーマンスを発揮するブロック・ボリュームの利点を活用し続けることができ、クラスタ対応のデプロイメントと、この機能の処理に対応した任意のソリューションを作成および管理できるようになりました。 たとえば、以下のようなユースケースがあります。 大規模データベースに合わせて高度に最適化された共有ファイル・システム 共有ディスクによるパッチ適用と構成の管理 書き込むユーザーが1人、読み取るユーザーが複数いる共有カタログ・コンテンツ 分散システムから共有リポジトリへのログ・ファイルのアップロード この複数インスタンスの接続機能は、オラクルがIO500ベンチマークのトップ15にランクインするに当たっても重要な要素となりました(「Oracle Cloud Joins the IO500 Fastest File Systems in the World」をご覧ください)。   使ってみよう デフォルトでは、ボリュームは、同一機能を持ち常に使用可能な1つのインスタンスからの共有不可能な読取り/書込みアクセスのみが有効な状態で接続されます(ボリュームへの最初の接続で共有可能な読取り/書込みアクセスのオプションが選択されている場合を除く)。ボリュームへの共有可能な接続が確立されると、その後に設定される、同一ボリュームへの他のインスタンスからの接続も共有可能になります。 さらにオラクルは、読取り専用接続も共有できるようにしました。読取り専用アクセスでボリュームを接続すると、複数のコンピュート・インスタンスへの共有可能な読取り専用接続が有効になります。同時アクセス制御やクラスタ対応ソリューションがなくても、読取りを行う複数のユーザー間で共有ブロック・ボリュームのコンテンツを共有できます。 読取り/書込みアクセス用のブロック・ボリュームの共有は簡単でシームレスです。コンソールのAttach Block Volumeのページで1回クリックするだけで済みます。 複数インスタンスが接続された共有可能ボリュームにも、ボリューム・グループ、ディスクからディスクへのディープ・クローン、自動化されたバックアップなど、すべてのブロック・ボリューム機能を適用できます。デタッチされた既存のボリュームでも、未接続の新規ボリュームでも、複数インスタンスの接続機能を利用できます。以前に共有可能な読取り/書込みアクセスで接続されなかったボリュームを共有可能にしたい場合は、ボリュームをデタッチして、共有可能なボリュームとして再接続します。これまでと同様のOracle Cloud Infrastructure Block Volume SLAを引き続き適用できます。 複数インスタンスが接続された共有可能なブロック・ボリュームは、Oracle Cloud Infrastructure Console、CLI、SDK、Terraformを通して、Oracle Cloud Infrastructureのすべてのリージョンで使用できます。この機能に関して詳しくは、ブロック・ボリュームのドキュメントをご覧ください。 ブロック・ボリューム・ストレージに関する情報は、ブロック・ボリューム・サービスの概要およびFAQをご覧ください。OCFS2について詳しくは、OCFS2のユーザー・ガイドをご覧ください。 特徴と機能についての詳しい情報は、本ブログでの発表をご確認ください。エンタープライズの皆様に当社のクラウド・サービスを引き続き役立てていただくために、当社では皆様からのフィードバックを歓迎しています。当社がより良いサービスをご提供し続けるためのアイディアをお持ちの場合や、トピックに関わらず詳しい情報をお知りになりたい場合は、私までお問い合わせください。 ※本記事は、Max Verun (Principal Product Manager)による”Announcing Multiple-Instance Attachment of Shareable Read/Write Block Volumes“を翻訳したものです。

  すばらしいお知らせがあります。ブロック・ストレージ・ボリュームを共有して、Oracle Cloud Infrastructure上の複数のコンピュート・インスタンスに接続できるようになりました。 これまでは、複数のブロック・ボリュームを1つのコンピュート・インスタンスに接続することはできましたが、ボリュームを接続して読取り/書込みアクセスができるのは、一度に1つのコンピュート・インスタンスからのみに...

全国のOTNおすすめ技術者向けセミナー&イベント(2020年2月)

Oracle Cloud Infrastructure ハンズオン 「Oracle Cloud Infrastructure」は、オンプレミスからの大規模ワークロード移行に完全対応する次世代インフラ基盤です。本セミナーでは、Oracle Cloud Infrastructureのサービス概要のご紹介とともに、実際のクラウド環境を利用したハンズオンを半日で体感いただけます。 2/7【2月第1回】Oracle Cloud Infrastructure ハンズオン 2/18【2月第2回】Oracle Cloud Infrastructure ハンズオン 一歩進んだ分析でビジネスにチカラを!! ~あなたもデータ アナリスト~ Autonomous Database CloudおよびOracle Analytics Cloudの特徴や活用法についてご紹介し、実際にサービスを利用し、起動からデータロード、分析まで一連の流れを体感いただけます。 2/12 【2月第1回】一歩進んだ分析でビジネスにチカラを!! ~あなたもデータ アナリスト~ 2/19 【2月第2回】一歩進んだ分析でビジネスにチカラを!! ~あなたもデータ アナリスト~ 2/27 実践Kubernetesハンズオン ~OKEでKubernetesを体験しよう~ Oracle Cloudは大規模なコンテナの管理、デプロイおよび運用に適したクラウドサービスを複数提供しています。本ハンズオンセミナーではOracle Cloudが提供するコンテナ・サービスを実際に利用しKubernetes環境の構築からコンテナ・アプリケーションのデプロイ、CI/CDまでの一連の流れを体感いただけます。 AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。

Oracle Cloud Infrastructure ハンズオン 「Oracle Cloud Infrastructure」は、オンプレミスからの大規模ワークロード移行に完全対応する次世代インフラ基盤です。本セミナーでは、Oracle Cloud Infrastructureのサービス概要のご紹介とともに、実際のクラウド環境を利用したハンズオンを半日で体感いただけます。 2/7【2月第1回】Oracl...

Data SafeでAutonomous Data Warehouseの安全性を維持する - パート2

この連載のパート1では、既存のADWおよびOCI環境でData Safeを使用するための準備作業について確認しました。まだパート1を読んでいない場合や、ざっと復習したい場合は、こちらをご覧ください。 https://blogs.oracle.com/otnjp/keeping-your-autonomous-data-warehouse-secure-with-data-safe-part-1-ja パート2では、新しくデプロイしたData Safe環境をAutonomous Data Warehouseインスタンスに接続するプロセスについて確認していきます。オラクルのクラウド・サービスはどれもそうですが、Data Safeコントロール・センターは特定のOCI地域データセンター内にデプロイされています。このため、別のデータセンターに切り替える場合は、新しくData Safe環境をデプロイする必要が生じるのでご注意ください。 Data Safeサービス・コンソールの起動 パート1の最後でFrankfurtデータセンター内のData Safeを有効化しました。このため、新しく作成したOCI資格証明を使用してOracle Cloudにログインすると、ハンバーガー・メニューにData Safeが表示されます。 「Data Safe」を選択すると、Data Safeランディング・パッド・ページが表示されます。次のステップでサービス・コンソールを起動します(ランディング・パッド・ページには「Service Console」ボタンしか表示されないのに、なぜ自動的にサービス・コンソールを表示しないのかと不思議に感じるかもしれません。とても良い疑問です。この連載の最後にはランディング・パッド・ページにもっと多くの情報が表示されるので、そのときもう一度この点について考えましょう)。  「Service Console」ボタンをクリックすると、次のような新しいウィンドウが表示されます。   この時点では、グラフにもその他のページにも情報は表示されていません。これはまだデータウェアハウス・インスタンスを登録していないからです。登録は次のステップで行います。  Data SafeへのADWの登録 Data Safeライブラリに含まれるレポートを生成するには、Data SafeにADWを登録する必要があります。 はじめに、ページ上部のメニューから「Targets」タブを選択します。 「Register」ボタンをクリックするとフォームが表示されるので、ADWの接続情報を入力します。 Data Safeと連携できるのはAutonomous Databaseだけではありません。以下のクラウド・データベースも登録できます。 ただし、Data Safeでサポートされているのはサーバーレス・デプロイメントのAutonomous Databaseのみであり、"専用サーバー"は現在サポートされていません。詳しい情報はこちらを参照してください。 https://docs.oracle.com/en/cloud/paas/data-safe/udscs/supported-target-databases.html ADW(およびATP)の場合、最初に接続タイプをTLSに変更します。変更すると、フォームに追加フィールドが表示されます(通常DI/ETLまたはBIツールからADWの接続を設定している場合、この方法が一番わかりやすいでしょう)。  ADWインスタンスの登録には多くの情報を入力する必要があると思えるかもしれませんが、ご安心ください。ほとんどの必要情報を含んだzipファイルをOCI ADBコンソールからダウンロードできます。実質的に必要なのはインスタンスのウォレット・ファイルですが、その前にフォーム上部のフィールドを入力しましょう。   残るはADWインスタンスに関する情報です。入手方法を次のステップで説明します。 ADW接続情報の収集 ADWインスタンスのOCIコンソール・ページに切り替えて、"OCID"というラベルの行を見つけます。これが最初に入手する情報です。"Show"と"Copy"という2つのリンクがあります。 「Copy」をクリックしてからData Safeページに戻り、「OCID」フィールドに貼り付けます。このほかに、ホスト名、ポート、サービス名、ターゲット識別名、セキュア・ウォレット・ファイルなどの情報が必要です。これらを入手するため、ウォレット・ファイルをダウンロードします。ウォレット・ファイルにアクセスするには、「DB Connection」ボタンをクリックします。ポップアップ表示されたフォームで、「Download Wallet」ボタンをクリックしてパスワードを入力します。あとで必要になるので、このパスワードをメモしておいてください。 ファイルをダウンロードしたら、ファイルシステム上にあるファイルを解凍します。解凍したフォルダには以下のファイルが含まれます。  Data Safeのターゲット登録フォームに戻りましょう。次に入力する4つのフィールドのデータはtnsnames.oraファイルから確認できます。Data Safeレポートの実行は緊急性の高いワークロードではないので、今回の接続には"low service"を使用します。 "low service"についてご存知ない場合は、ADWドキュメントのセクション12の「Managing Concurrency and Priorities on Autonomous Data Warehouse」にざっと目を通すことをおすすめします。簡単に言うと、ADWインスタンスに接続するとき、low、medium、highのいずれかのサービスを選ぶ必要があります。このサービスは以下の特性を持つコンシューマ・グループ(LOW、MEDIUM、またはHIGH)にマッピングされます。      HIGH:リソース: もっとも多い、同時実行性: もっとも低い。問合せは並列で実行。 MEDIUM:リソース: HIGHより少ない、同時実行性: HIGHより高い。問合せは並列で実行。 LOW:リソース: もっとも少ない、同時実行性: もっとも高い。問合せは順番に実行。 いずれにせよ、ジョブが実行されれば問題ありません。tnsnames.oraファイルからlow-service接続用の情報を探します。以下のような行が見つかります。  adwdemo_low = (description=(address=(protocol=tcps)(port=1522)(host=xxxxxx.oraclecloud.com))(connect_data=(service_name=xxxxx_adwdemo_low.xxxxxxx))(security=(ssl_server_cert_dn="CN=xxxxxx.oraclecloud.com,OU=Oracle,O=Oracle Corporation,L=Redwood City,ST=California,C=US"))) host、port、service_name、ssl_server_cert_dnの値をコピーして、"TLS"プルダウン・メニュー項目の下にある4つのフィールドに貼り付けます。 フォームは以下のようになります。 あと少しです。Wallet Typeに"JKS Wallet"を設定します。Certificate/Walletには、ダウンロード後に解凍した接続ファイル"truststore.jks"を指定します。同じディレクトリ/フォルダにある"keystone.jks"ファイルをKeystore Walletに指定します。その下のフィールドには、zipされた接続ファイルをダウンロードするときにOCI ADWコンソール・ページで使用したパスワードを入力します。 最後に、ADWインスタンスのユーザー名/パスワードを入力します。このユーザーは、この連載のパート1で作成したDATASAFEです。      「Test Connection」ボタンをクリックする前に、PL/SQLスクリプトを実行する必要があります。このスクリプトは、新しいデータベース・ユーザーであるDATASAFEに権限を付与して、Data Safeのさまざまなチェックを問題なく実行できるようにするものです。 ダウンロード・ボタンをクリックして、dscs_privileges.sqlというPL/SQLスクリプトを見つけます。SQL Developer(または任意のツール)を使用し、標準のADMINユーザーとしてログインしてからスクリプトを実行します(コピー&貼付けを使用)。スクリプトのログをチェックすると、以下のようなメッセージが確認できます。 Enter value for USERNAME (case sensitive matching the username from dba_users) Setting USERNAME to DATASAFE Enter value for TYPE (grant/revoke) Setting TYPE to GRANT Enter value for MODE (audit_collection/audit_setting/data_discovery/masking/assessment/all) Setting MODE to ALL Granting AUDIT_COLLECTION privileges to "DATASAFE" ...  Granting AUDIT_SETTING privileges to "DATASAFE" ...  Granting DATA_DISCOVERY role to "DATASAFE" ...  Granting MASKING role to "DATASAFE" ...  Granting ASSESSMENT role to "DATASAFE" ...  Done. Disconnected from Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production Version 18.4.0.0.0 以上で接続をテストする準備が整いました。「Test Connection」ボタンをクリックすると、接続に成功し、緑のチェック・マークが表示されます。   最後に「Register Target」をクリックします。新しく登録したデータベースの情報がTargetページに表示されます。     ここではADWを新規ターゲットとして登録しただけなので、ホームページを含むその他のページはまだ空白です。     パート2のまとめ パート1では、Data Safeを使用できるように環境を準備し、地域データセンター(今回はFrankfurtデータセンター)内でData Safeを有効化しました。パート2では、既存のADWインスタンスを新しいターゲット・データベースとしてData Safeに登録しました。   パート3を近日公開予定 次の記事では、Data Safeに含まれるデータ検出機能とデータ・マスキング機能について確認する予定です。   詳細情報 オラクルのセキュリティ・チームは、Data Safeの学習に役立つコンテンツを多数作成しています。ここでは、個人的に使用しているブックマークを紹介します。 ドキュメント - まずはここから: https://docs.oracle.com/en/cloud/paas/data-safe/udscs/oracle-data-safe-overview.html Oracle.comのData Safeページ - https://www.oracle.com/database/technologies/security/data-safe.html データベース・セキュリティ・ブログ: https://blogs.oracle.com/cloudsecurity/db-sec https://blogs.oracle.com/cloudsecurity/keep-your-data-safe-with-oracle-autonomous-database-today https://blogs.oracle.com/cloudsecurity/keeping-your-data-safe-part-4-auditing-your-cloud-databases   ※本記事は、Keith Laker (Senior Principal Product Manager)による”Keeping Your Autonomous Data Warehouse Secure with Data Safe Part 2“を翻訳したものです。

この連載のパート1では、既存のADWおよびOCI環境でData Safeを使用するための準備作業について確認しました。まだパート1を読んでいない場合や、ざっと復習したい場合は、こちらをご覧ください。 https://blogs.oracle.com/otnjp/keeping-your-autonomous-data-warehouse-secure-with-data-safe-part-1-ja...

Data SafeでAutonomous Data Warehouseの安全性を維持する - パート1

サンフランシスコで開催されたOpenWorld 2019では、重要な発表の1つにOracle Data Safeがありました。Data Safeは、Oracle Autonomous Data Warehouse(ADW)に対応したまったく新しいクラウドベースのセキュリティ・コントロール・センターで、完全に無償でご使用いただけます。    具体的にはどんな機能があるのでしょうか。簡単に言うと、Oracle Data Safeは、不可欠なデータ・セキュリティ機能をOracle Cloud Infrastructureのサービスとして提供します。これらのサービスは、データの機密性の把握、データ・リスクの評価、機密データのマスキング、セキュリティ管理の実装と監視、ユーザー・セキュリティの評価、ユーザー活動の監視、データ・セキュリティ・コンプライアンス要件への対応に役立ちます。   こちらの短い動画が参考になります。     Data Safeコンソール Data Safeのメイン・コンソールであるダッシュボード・ページは次のように表示されます。  Autonomous Data Warehouse内に保存された各種のデータセットを直接確認できるので、次の処理が可能になります。     データベースがセキュアに構成されているかどうかを評価する GDPRの条項/備考、Oracle DatabaseのSTIGルール、CISベンチマークの推奨事項に基づいてリスクを調査し、軽減する 重要なユーザー、ロール、権限を明確にすることで、ユーザー・リスクを評価する 監査ポリシーを設定し、ユーザー・アクティビティを収集して、異常な行動を特定する 機密データを見つけて、その保存場所を把握する 機密データをマスキングして、本番以外のデータセットからリスクを除外する 既存のAutonomous Data WarehouseをData Safeに接続するのはごく簡単です。ここからは、その方法とデータセットに対して実行できるセキュリティ・レビューの種類を紹介しましょう。 Data Safeと連携するためのADWの設定 ここでは設定を簡単にするため、既存のADWインスタンスにLOCAL_SHという新規ユーザーを作成します。続いて、デモグラフィック、国、顧客の各表を、読取り専用の販売履歴デモ・スキーマから新しいlocal_shスキーマに追加でコピーします。  これにより、ADWをData Safeに接続したときにData Safeが検出する"機密"のデータ・ポイントがスキーマに含まれます。 CREATE USER local_sh IDENTIFIED BY "Welcome1!Welcome1"; GRANT DWROLE TO local_sh; CREATE TABLE local_sh.supplementary_demographics AS SELECT * FROM sh.supplementary_demographics; CREATE TABLE local_sh.customers AS SELECT * FROM sh.customers; CREATE TABLE local_sh.countries AS SELECT * FROM sh.countries; 顧客表にはどのようなデータが含まれるのでしょうか。 間違いなく個人の特定につながりそうな列がいくつかありますね。このような列は、開発者チームやビジネス・ユーザーに表示されないようにするか、マスキングしなくてはなりません。   ここまでで、非常に機密性の高いデータが含まれることが確認できました。 今回の例とは異なり、まっさらなADWにデータをロードする必要がある場合は、オラクルのドキュメント・ガイドに記載された手順を参照してください。このガイドでは、ユーザー・データをADWにロードする方法について説明しています。 https://docs.oracle.com/en/cloud/paas/autonomous-data-warehouse-cloud/tasks_load_data.html   次に、Data Safe接続プロセスで使用するユーザーをADWインスタンスに作成します。新しく作成することで、セキュリティ・レビュー・プロセスがいずれかのアプリケーション・ユーザーに関連付けられることを回避します。 CREATE USER datasafe IDENTIFIED BY "Welcome1!DataSafe1"; GRANT DWROLE TO datasafe; このあとで、インストール・スクリプトを実行する必要がありますが、スクリプトはデータベースの登録時にData Safeコンソールから入手できます。既存のアプリケーション・ユーザーに関連付けないようにしたのは、Data Safeの実行に必要なロールと権限をこのユーザーに付与するからです。   Oracle Cloudアカウントの種類の確認 Oracle Cloudを初めて使用する場合や、アカウントを作成したのが過去12か月以内である場合は、このセクションをスキップして問題ないでしょう。Oracle Cloudのクラウド・アカウントを2年以上前に作成している場合は、Data Safeにアクセスしようとすると、連携アカウントに関する警告メッセージが表示される可能性があります。 Data Safeへのアクセス クラウド・アカウントにログインし、左上にあるハンバーガー(3本の横線)メニューをクリックします。ポップアップ・メニューで、Autonomous Transaction Processingの下にData Safeが表示されます。   「Data Safe」をクリックすると、次のような画面が表示される場合があります。このメッセージが表示されない場合は、"Data Safeの有効化"セクションに進んでください。   メッセージが表示されても心配ありません。必要な作業は新しいOCIユーザーを作成することだけです。ハンバーガー・メニュー・リスト内を下方向にスクロールし、"Governance and Administration"が表示されたら、「Identity」→「Users」の順に選択します。 画面上部にある青色の大きな「Create User」ボタンをクリックし、各フィールドに値を入力して新規OCIユーザーを作成します。このユーザーはあとでData Safe環境の所有者として使用します。 新規ユーザーを作成した後に届く「ようこそ」メールには、以下のようにパスワードをリセットするためのリンクが記載されています。 新規ユーザーを作成したら、Data Safeがテナント内でリソースおよび自律型データベース・インスタンスにアクセスできるようにするため、正しい権限をすべて有効化する必要があります。 ここでは、DataSafeというユーザーのために、Data Safeで必要になる権限をすべて含んだ“administrators”グループをテナント内に作成してあります。  実際には、より慎重な方法として、Data Safe管理者専用の新規グループをセットアップし、このグループだけにOCI権限を割り当てると良いでしょう。このプロセスについての詳細情報はこちらを参照してください。 https://docs.oracle.com/en/cloud/paas/data-safe/udscs/required-permission-enabling-oracle-data-safe.html 簡単なおさらい ここでは、あらかじめセットアップしてあったAutonomous Data Warehouseインスタンスを使用しました。SQL Developerを使用して新規ユーザーを作成し、潜在的な機密情報を含む小さなデータセットの所有者にしました。機密データ・ポイントを含むことがわかっている既存のスキーマから、いくつかの表をコピーして、作業用データセットを作成しました。また、新しいOCIユーザーに対して、Data Safe導入環境の所有者として使用できるように設定しました。   Data Safeの有効化 ここまでで、Data Safeを使用する準備が整いました。ハンバーガー・メニューから「Data Safe」を選択します。このテナント・リージョンでのログインが初めての場合は、次のような画面が表示されます。画面から、Frankfurtデータセンターを使用中で、データセンターへのログインは今回が初めてであることがわかります。 次の段階へ進むには、大きな青色のボタンをクリックしてData Safeを有効化します。いつもの"作業中..."画面が表示されます。   その後、"準備完了"画面になります。   パート1のまとめ パート1はここまでです。次回は、Autonomous Data Warehouseインスタンスの登録方法を確認してから、顧客に関する機密データを含むオブジェクトを突き止めるときに役立つセキュリティ・レポートを実行します。 詳細情報 オラクルのセキュリティ・チームは、Data Safeの学習に役立つコンテンツを多数作成しています。ここでは、個人的に使用しているブックマークを紹介します。 ドキュメント - ますはここから: https://docs.oracle.com/en/cloud/paas/data-safe/udscs/oracle-data-safe-overview.html Oracle.comのData Safeページ - https://www.oracle.com/database/technologies/security/data-safe.html データベース・セキュリティ・ブログ: https://blogs.oracle.com/cloudsecurity/db-sec https://blogs.oracle.com/cloudsecurity/keep-your-data-safe-with-oracle-autonomous-database-today https://blogs.oracle.com/cloudsecurity/keeping-your-data-safe-part-4-auditing-your-cloud-databases ※本記事は、Keith Laker (Senior Principal Product Manager)による”Keeping Your Autonomous Data Warehouse Secure with Data Safe Part 1“を翻訳したものです。

サンフランシスコで開催されたOpenWorld 2019では、重要な発表の1つにOracle Data Safeがありました。Data Safeは、Oracle Autonomous Data Warehouse(ADW)に対応したまったく新しいクラウドベースのセキュリティ・コントロール・センターで、完全に無償でご使用いただけます。    具体的にはどんな機能があるのでしょうか。簡単に言うと、Oracl...

全国のOTNおすすめ技術者向けセミナー&イベント(2020年1月)

1/28 Oracle Cloud Infrastructure ハンズオン 「Oracle Cloud Infrastructure」は、オンプレミスからの大規模ワークロード移行に完全対応する次世代インフラ基盤です。本セミナーでは、Oracle Cloud Infrastructureのサービス概要のご紹介とともに、実際のクラウド環境を利用したハンズオンを半日で体感いただけます。 1/31 実践Kubernetesハンズオン ~OKEでKubernetesを体験しよう~ Oracle Cloudは大規模なコンテナの管理、デプロイおよび運用に適したクラウドサービスを複数提供しています。本ハンズオンセミナーではOracle Cloudが提供するコンテナ・サービスを実際に利用しKubernetes環境の構築からコンテナ・アプリケーションのデプロイ、CI/CDまでの一連の流れを体感いただけます。 AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。

1/28 Oracle Cloud Infrastructure ハンズオン 「Oracle Cloud Infrastructure」は、オンプレミスからの大規模ワークロード移行に完全対応する次世代インフラ基盤です。本セミナーでは、Oracle Cloud Infrastructureのサービス概要のご紹介とともに、実際のクラウド環境を利用したハンズオンを半日で体感いただけます。 1/31...

クイズに挑戦:ループ構造の比較(中級者向け)

ユーザーの手動入力をループ処理する場合に使用するループ構造、そこには多くの微妙な違いが... 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しめのものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 ループ構造を比較したいと思います。 以下のことを行うインタラクティブなコンソール・アプリケーションを書いているものとします。 プロンプトを表示する。 入力としてコマンドを読み取る。 入力がQだった場合、終了する。そうでない場合は、指定されたコマンドを実行し、手順1に戻る。   次のコード構造のうち、このシナリオを実装するために最適な選択肢はどれですか。1つ選んでください。 break文があるforループ 拡張forループ continue文があるwhileループ do/whileループ   解答:この設問では価値判断を求めています。多くの場合、こういった選択問題は悩ましいものです。しかし、この設問で求められているのはかなり一般的な判断です。すべての説明が終わるころには、皆さんにもそう思っていただけるはずです。 設問から2つの重要なポイントが読み取れます。この2つが、適切なループを選ぶ際の手がかりになります。1つ目は、手順1と2を少なくとも1回実行する必要があることです。つまり、少なくとも1回コマンドを読み取るまで、コードは終了しないはずであるということです。そのこととも密接に関連していますが、もう1つわかることは、コマンドを読み取ってからでなければ、プログラムを終了する判断はできないということです。 whileループを使おうとする場合、以上の要件が実装にどう影響するかを考えてみます。まずわかるのが、whileループの条件判定はループに入るときに行われるということです。つまり、条件判定はループ本体より先に実行されます。そのため、このループを使ってプログラムの実行と終了を制御する場合の1つの可能性としては、次の疑似コードに示すように、ループの開始前にプロンプトを表示してコマンドを読み取ることが考えられます。  プロンプトを表示する コマンドを読み取る While (コマンドが"Q"でない) コマンドを実行する ... 現時点では、このアプローチに問題はないように思えるかもしれません。しかし、さらに、次のプロンプトを表示して次のコマンドを読み取る必要があります。この処理はループごとに行う必要があるため、関連するコードをループの中に入れる必要があります。すなわち、同じコードを2か所に書かなければなりません。この条件は、コードに重複する部分が必要だと間接的に述べているのと同じことです。このコードは次のようになります。 プロンプトを表示する コマンドを読み取る While (コマンドが"Q"でない) コマンドを実行する プロンプトを表示する // 重複 コマンドを読み取る // 重複 End-while コードの重複は美しくなく、メンテナンスの際にエラーが起きやすくなります。別のアプローチとして、ループの前にダミーの値をコマンドに設定し、そのコマンドを実行しても何も行わないようにする方法も考えられます。こうすれば重複は回避されますが、実質的に動作を「ハッキング」する特殊な値を使っているため、やはりコードが複雑になり、理解しにくくなる可能性があります。 この問題は、whileループの使用にとって確かに打撃と考えられますが、価値判断を行う前に、他の可能性について考えてみます。 次は、標準forループについて見てみます。実は、forループは、whileループに飾り付けをしただけのものにすぎません。その飾りによって、ループ構造でよくある2つの状況に対処します。1つはループ内で使われる変数の初期化(同時に宣言が行われることもあります)、もう1つは反復に伴う、変数の更新です。しかし、forループの実体は、飾りが付いたwhileループにすぎません。その飾りのいずれかが今回のシナリオに役立つ可能性もありますが、プロンプトと入力読取りのコードが重複するという根本的な問題があることは変わりません。 次に、拡張forループについて見てみます。拡張forループは、Iterableオブジェクトのすべての要素を処理する際に、よりクリーンな手段を提供します(対象となるIterableは、Listなどのコレクションによって提供されるのが一般的ですが、常にそうであるとは限りません)。この問題では、コンソールから入力として項目を読み取る必要があり、入力値がQであればループは終了します。それに対して、拡張forループでは、Iterableから項目を取得し、利用できる項目がなくなったときに終了します。 ユーザーにプロンプトを表示して1行のテキストを読み取り、ユーザーの入力がQでなかった場合にStringを返し、ユーザーの入力がQだった場合には反復を終了するIterableオブジェクトを作ることはできますが、今回のシナリオで使うにはあまりに遠回りで複雑すぎます。この状況で拡張forループが推奨される理由が多いとは考えられないため、最後の選択肢について考えてみます。 残る選択肢は、do/whileループです。このループを繰り返すかどうかを決める条件判定は、do/while構造の最後に置かれます。これによって、いくつかの結果が生まれます。do/whileループは、常に少なくとも1回は実行されます。ループの条件判定に到達するためには、その本体を実行しなければならないからです。別の言い方をすれば、条件判定が行われる前にループの本体が実行されるということです。今回のシナリオには、こちらの方がはるかに適しています。ループ本体でプロンプトを表示し、コマンド入力を読み取ることができるからです。その結果、コードを重複させることなく、条件判定の前にプロンプトの表示と入力の読取りが行われることが保証され、クリーンでシンプルな構造が実現します。 この時点で、今回のシナリオに最適なのは選択肢Dであり、他の選択肢よりもはるかに優れていることは明らかでしょう。そのため、選択肢Dが正解で、A、B、Cは誤りであることがわかります。 いくつか補足しておきます。選択肢Aにはbreak文を使うとあり、選択肢Cにはcontinueを使うとあります。forとbreakの構造を代わりに使用することもできますが、いずれにしても、エレガントな解決策にはなりません。選択肢Aは、次のようにコーディングすることもできるでしょう。 for (;;) { // 事実上の無限ループ // プロンプトを表示する String input = // ユーザーの入力を読み取る if (input.equals("Q")) break; // ループの外に出る executeCommand(input); } しかし、do/whileループを使用したものに比べれば、やはり美しくありません。同じように、whileループでcontinueを使っても、クリーンな解決策に直結することはありません。 正解は選択肢Dです。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する Arquillian:簡単なJakarta EEテスト ArchUnitでアーキテクチャの単体テストを行う 新しいJava Magazine 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。

ユーザーの手動入力をループ処理する場合に使用するループ構造、そこには多くの微妙な違いが... 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しめのものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく...

クイズに挑戦:スレッドとExecutor(上級者向け)

ExecutorServiceを使って行う具体的な処理の詳細 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 設問(上級者向け):RunnableおよびCallableを使ってワーカー・スレッドを作成し、ExecutorServiceを使って複数のタスクを同時に実行したいと思います。次のクラスについて: class Logger implements Runnable { String msg; public Logger(String msg) { this.msg = msg; } public void run() { System.out.print(msg); } } さらに、次のコード部分について: Stream<Logger> s = Stream.of( new Logger("Error "), new Logger("Warning "), new Logger("Debug ")); ExecutorService es = Executors.newCachedThreadPool(); s.sequential().forEach(l -> es.execute(l)); es.shutdown(); es.awaitTermination(10, TimeUnit.SECONDS); すべてのimport文(表示されていません)が適切に構成されており、コードがコンパイルできると仮定した場合、出力される可能性があるものはどれですか。2つ選んでください。 Error Debug Warning Error Warning Debug Error Error Debug Error Debug   解答:試験対象には、ExecutorsクラスおよびExecutorServiceインタフェースに関連するトピックが含まれています。Executorsクラスが提供するExecutorServiceインタフェースを実装したスレッド・プールも同様です。 Javaの初期のバージョンでは、スレッドの作成や管理はプログラマーの責任でした。また、スレッドは作成が高価であり、限られた、カーネルレベルのリソースでもあるため、「スレッド・プール」を作って、少数のスレッドで独立した小さなジョブを数多く処理できるようにするのが一般的でした。スレッド・プールという考え方は、小さなバックグラウンド・ジョブごとにスレッドを作り、各ジョブの完了後にそのスレッドを破棄するという方法に代わるものです。スレッド・プールでは、少数のスレッドを作って構成し、まとまった仕事(たとえば、Runnableオブジェクト)をスレッドに渡せるようにします。仕事がないスレッドのうち最初のものがジョブを引き受けて実行し、そのジョブが完了すると、そのスレッドは別のジョブを探します。 スレッド・プールは、Java 5でJavaのAPIの一部になりました。ExecutorインタフェースおよびExecutorServiceインタフェースは、スレッド・プールと、スレッド・プールがサポートする操作を汎用化したものです。また、静的ファクトリ・メソッドを含むクラスから、多くのExecutorService実装のインスタンスを生成できます。そのクラスがExecutorsです。java.util.concurrentパッケージには、これら3つの型のほか、多数の高水準なクラスやインタフェースが含まれています。こういったクラスやインタフェースは、並行プログラミングでよく生じる問題に対処しようとする開発者に活用してもらうことを意図したものです。 ベース・インタフェースのExecutorは、Runnableを実装したタスクを実行できます。通常は、ExecutorServiceを使うことが多いでしょう。これはExecutorのサブインタフェースです。ExecutorServiceには、Callableインタフェースを実装したタスクを処理する機能と、スレッド・プールの停止を制御する機能が追加されています。Callableインタフェースを使うことで、マネージャ・タスクから非同期的にタスクの結果を取得できるようになります。多くの場合、このマネージャ・タスクのコードが最初にジョブを送信しますが、必ずそうであるとは限りません。 ExecutorやExecutorServiceの実装は、送信された仕事を実行するために特定の戦略を使う必要はありません。実装の中には、固定サイズのプールを使って同時実行するものもあります。その場合、新しい仕事は、スレッドが利用できるようになるまで待機します。ワークロードが増加した際により多くのスレッドを開始し、需要が少なくなった際にスレッドをクリーンアップする実装もあります。また、1つのスレッドを使って単純にジョブを逐次処理する実装もあります。すべては個々の実装次第です。そのため、プログラマーはアプリケーションのアーキテクチャのニーズに適した実装を注意深く選択する必要があります。Executorsクラスの3つのファクトリ・メソッドでは、前述の動作が生成されます。 newFixedThreadPool newCachedThreadPool newSingleThreadExecutor 最初の2つは複数のワーカー・スレッドを使うプールを作成しますが、newSingleThreadExecutorはすべてのタスクを1つのバックグラウンド・スレッドで次々に実行するサービスを作成します。 本設問のコードでは、キャッシュド・スレッド・プールを使っています。このタイプのExecutorServiceは、必要に応じて新しいワーカー・スレッドを生成し、一定期間使用されなかったスレッドをクリーンアップします。しかし、キャッシュド・スレッド・プールには、作成できるスレッドの最大数に制限がないという重大な欠点があります。この動作により、高負荷時にリソース消費量が高くなり、パフォーマンスが低下する可能性があります。 設問のコードで作成しているプールには複数のスレッドがあることを踏まえれば、プールに送信されたジョブはおそらく同時実行されると考えることができます。そのため、開始される順番がどうであれ、相対的な処理の進み具合を予測することはできません。つまり、出力されるメッセージはどんな順番にもなり得るということです。ここから、選択肢AとBがいずれも正解であることがわかります。 ExecutorServiceが、送信された各ジョブを実行するのは、多くても1回です。状況によっては、ジョブが実行されないことや、完了前に停止されることもあるかもしれません。しかし、ジョブが複数回実行されることはありません。つまり、メッセージが重複することは絶対にありません。よって、選択肢Cは誤りです。 ExecutorServiceに対してshutdownメソッドを呼ぶと、新しいジョブのリクエストは拒否されるようになりますが、実行は最後のジョブが完了するまで続きます。そのため、設問のコードでは、3つのメッセージのうちいくつかが表示されないということはありません。以上より、選択肢Dも誤りであることがわかります。 1点補足しておきます。10秒以内にシャットダウンが完了しない場合、コードは末尾に到達することから、選択肢Dは正解かもしれないと考える方もいるかもしれません。3つのメッセージが確実に表示されると断言することはできるのでしょうか。 ここで、いくつかの見解が関連してきます。まず、このジョブが完了するまでに10秒かかる可能性は非常に低いということです。また、2つの選択肢(AとB)が明らかに正解であることを考えれば、このような起こりそうもないことは除外できます。 もちろん、ホストで極端な状況が発生すれば、ジョブが10秒以内に完了しない可能性もあります。そこから、選択肢Dはやはり正解かもしれないと思うかもしれません。たとえば、設問のコードが起動した瞬間に、OSのアップデートのインストールが始まった場合を考えてみてください。設問のコードには、仮想マシンが強制シャットダウン中であることを示す内容は含まれていないことに注意してください。このスレッド・プールのスレッドは非デーモン・スレッドであるため、ジョブが完了するまで仮想マシンはシャットダウンされません。そのため、プログラムの実行が許可されれば、3つのメッセージが表示されます。 正解は選択肢AとBです。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する Arquillian:簡単なJakarta EEテスト ArchUnitでアーキテクチャの単体テストを行う 新しいJava Magazine 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。

ExecutorServiceを使って行う具体的な処理の詳細 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しか...

クイズに挑戦:ラッパー・クラス(中級者向け)

Integerラッパー・クラスを使って2つの整数のインスタンスを作成したときに、値を比較する正しい方法 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 設問(中級者向け):Boolean、Double、Integer、などのラッパー・クラスを使ったコードを作成したいと思います。 次のコード部分について: String one = "1"; Boolean b1 = Boolean.valueOf(one); // line n1 Integer i1 = new Integer(one); Integer i2 = 1; if (b1) { System.out.print(i1 == i2); } どのような結果になりますか。1つ選んでください。 line n1で実行時例外が発生する true false コードは実行されるが、何も出力されない   解答:この設問は、プリミティブのラッパー・クラス、とりわけBooleanクラスとそのファクトリに関する奇妙な側面について問うものです。この設問で取り上げた内容がそっくりそのまま実際の試験に出題される可能性は低いでしょう。というのも、解けるかどうかは仕様を丸暗記しているか次第であり、試験ではそのような設問は回避されることが多いからです。ただし、この設問では、1つの問題で複数の側面にわたる理解と知識を確認しています。運が良ければ、その点がさらにおもしろいものになります。 ラッパーでは、インスタンスを取得する方法が主に3つあります。各ラッパーでは、valueOfという名前のメソッドで静的ファクトリが提供されています。また、ラッパー型の変数に、型が一致するプリミティブから代入する場合のように、コンテキストが十分明示的であれば、オートボクシングが行われます。オートボクシングは、構文の単なる省略表記で、コンパイラにvalueOfメソッドを呼び出すコードを書かせることができ、ソース・コードが簡潔になります。3つ目のアプローチは、newキーワードを使ってコンストラクタを呼び出すというものです。実は、この3つ目のアプローチはJava 9で非推奨になっています。この設問のねらいの1つは、なぜ非推奨になったのかを問うことにあります。 Javaで、newキーワードを使ってコンストラクタを呼び出すたびに起きる可能性があるのは、2つのことだけです。すなわち、指定されたとおりの名前の型の新しいインスタンスが生成されて返されるか、例外が発生するかのいずれかです。実のところ、これは制約です。現在では、一般的にファクトリ・メソッドが好まれています。これら2つの効果を持たせることができるうえに、追加の結果を提供することもできるからです。 コンストラクタでは不可能で、ファクトリでは可能な機能の1つに、リクエストに沿った既存のオブジェクトを返こすとがあります。Integerラッパーが不変であることを考えれば、同じ数値を表す、この型の2つのオブジェクトは完全に交換可能です。そのため、同じ値を表す2つのオブジェクトを作るのは、メモリの無駄です。さらに、このアプローチでは、このようなオブジェクトをequals(Object o)メソッドではなく==を使って比較できます。Integerクラスでは、通常、-128から+127までの値がこのようにして再利用されます。 (補足ですが、この動作は、new String("1")のようにしてStringオブジェクトを作成する代わりに、Stringリテラルを使用することと実質的に同じです。) ファクトリ・メソッドには有利な点があと2つあります。複数のファクトリを作成する場合、各メソッドを異なる名前にすることができます。つまり、適切であれば、同じ引数型リストを受け取れるということです。コンストラクタでは、互いが有効なオーバーロードである必要があるため、これを行うのは不可能です。 3つ目の有利な点は、コンストラクタでは指定されたとおりの名前の型のオブジェクトを必ず返すということです。ファクトリでは、代入において宣言された型に対応するものであれば、何でも返すことができます(インタフェースの実装も含みます。こうすることにより、実装の詳細をうまく隠すことができます)。 この設問にもっとも関連するのは、Boolean.valueOf(...)を使う場合です。この場合、厳密に2通りの定数オブジェクトを得ることになります。1つはBoolean.TRUE、もう1つはBoolean.FALSEです。この2つは、追加のメモリを占有することなく、必要に応じて何度でも再利用されます。この動作は、newの呼出しでは不可能です。 ところで、ほとんどのラッパーのファクトリは、NULL引数や、作成する型を適切に表していない文字列が渡された場合、例外をスローします。たとえば、Integer.valueOfファクトリを"5"ではなく"five"という引数で呼び出した場合です。ただし、java.lang.Booleanクラスのファクトリは、引数の文字列が存在し、"true"という値(大文字、小文字は区別しません)が含まれているかどうかを確認します。その条件を満たす場合は、値Boolean.TRUEを返します。そうでない場合は、引数についてそれ以上何も知らせることなく、Boolean.FALSEを返します。つまり、NULL引数やテキスト"nonsense"でファクトリを呼び出しても、Boolean.FALSEが返され、例外はスローされません。 そのため、line n1のコードでは、例外はスローされず、変数b1にBoolean.FALSEが代入されると判断できます。そのため、選択肢Aは誤りです。 次は、if文の動作と、そこで行われている比較について吟味する必要があります。 一般的なルールに、if文の条件式はboolean型でなければならないというものがあります。Booleanオブジェクトがアンボクシングされて、そのままboolean型になることは明らかでしょう。ここで疑問を感じたとしたら、コードがコンパイルできないのではということかもしれません。そう考えるのは、おかしなことではありません。Java 5でオートボクシングが導入されるまで、このコードはコンパイルできなかったからです。しかし、そう心配したとしても、その点について触れている選択肢はないため、見た目どおりの動作が起こると考えて問題ありません。 この場合、b1が参照するオブジェクトはfalse値を表していることを確認しました。そのため、ifの条件は満たされず、コードの本体は実行されません。そこから、選択肢Dは正解であると判断できます。 実行されないことはわかりましたが、この議論に関連して、if文の中にあるprint呼出しの引数が評価されるとしたら何が起こるかについて考えることには価値があると思われます。 Javaでは、2つの形態の等価比較を提供しています。1つは、コア言語の一部である==演算子です。もう1つは、実質的にAPI機能と言えるequals(Object o)メソッドです。このメソッドはjava.lang.Objectクラスで定義されているため、すべてのオブジェクトで利用できます。しかし、対象のクラスでこのメソッドが実装されていない場合、有用な動作とならない可能性があります。この2つは、どの場面にいずれを使うかを把握し、正しく使い分けることが重要です。しかし、この設問には登場するのは==演算子だけであるため、こちらを詳しく見てみます。 ==演算子では、2つの式の値を比較します。これは一見簡単なように思えますが、それぞれの値で式の基本型が異なる場合、簡単とは言い切れません。==の外見上の効果は2つの型でまったく異なるため、この事実は重要です。ところで、ここでは意図的に「式」という用語を使っています。変数はシンプルな式の1つです。変数の値と型という面から考えてみても、この議論は成り立ちます。ただしその場合、真実の一部だけを捉えていることになります。 式を大きく2つに分ければ、プリミティブ(boolean、byte、short、char、int、long、float、doubleという8つの型のいずれか)と、いわゆる参照となります。参照は、メモリ内の別の場所にあるオブジェクトを見つけるために使う値という意味で、ポインタとよく似ています。 式がプリミティブタイプである場合、実のところ、関心の対象はその式の値です。そのため、あるint式の値が32であれば、事実、その式の値は32をバイナリで表現したものになります。そんなことは当たり前だと言われるかもしれません。問題は、変数がたとえばInteger型への参照タイプであり、その変数が、32という値を含むオブジェクトを参照するために使用されているような場合です。この場合、変数の値は32にはなりません。そうではなく、32を含むオブジェクトをJVMが見つけられるようにするための魔法の数値(参照)になります。つまり、参照タイプ(前述の8つのプリミティブを除いたすべてのものを指すことを思い出してください。したがって、Integer式も含まれます)の場合、==という条件で判定されるのは、2つの式が同じ意味を持つかどうかではなく、厳密に同じオブジェクトを参照しているかどうかです。重要なことに、32という値を含む2つのIntegerオブジェクトがあり、その2つが異なるオブジェクトである場合、それぞれの参照値は異なることになります。そのため、==を使って、それぞれを参照する式を比較すると、結果はfalseになります。 ここまで来れば、次のコードがあった場合、 Integer v1 = new Integer("1"); Integer v2 = new Integer("1"); System.out.print(v1 == v2); 確実にfalseが出力されることは明白でしょう。先ほども触れましたが、newを呼び出すと、指定されたとおりの名前の型の新しいオブジェクトか、または例外が必ず生成されます。つまり、v1とv2は必ず違うオブジェクトを参照します。すなわち、==操作は必ずfalseを返します。 代わりに次のコードがあったとします。 Integer v1 = new Integer("1"); Integer v2 = 1; System.out.print(v1 == v2); 設問のコードととてもよく似ており、片方ではコンストラクタを呼び出し、もう片方ではアンボクシングを使っています。このコードでも、確実にfalseが出力されます。 コンストラクタで生成されるオブジェクトは一意な新しいオブジェクトであるため、オートボクシングされた値を生成するファクトリから返されるものとは異なります。 多くの場合、不変オブジェクトのファクトリは、同じ引数で呼ばれた場合には毎回同じオブジェクトを返すようにコードが書かれています。IntegerクラスのvalueOf(int)メソッドのAPIドキュメントには、次のように書かれています。 「このメソッドは、-128から127の範囲の値を常にキャッシュしますが、この範囲に含まれないその他の値をキャッシュすることもあります」 言い換えれば、次のコード Integer v1 = Integer.valueOf(1); Integer v2 = Integer.valueOf(1); System.out.print(v1 == v2); では、確実にtrueが出力されます。 先ほど引用した仕様は、valueOf(int)メソッドのドキュメントにのみ書かれており、valueOf(String)では触れられていません。しかし実際は、両方のメソッドで同じプーリング動作が見られます。 もちろん、この設問で扱っているのは2つのIntegerオブジェクトです。片方はコンストラクタで生成され、もう片方は(Integer.valueOf(int)メソッドを使って)オートボクシングで生成されています。つまり、if文の本体に入力されたとすれば、出力はfalseになりました。しかし、選択肢Dが正解であることはすでに確定しているため、選択肢BとCは誤りとなります。ここまで説明してきたことは、おもしろい補足にすぎません。もちろん、実際におもしろいと思っていただけると幸いです。正解は選択肢Dです。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する Arquillian:簡単なJakarta EEテスト ArchUnitでアーキテクチャの単体テストを行う 新しいJava Magazine 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。

Integerラッパー・クラスを使って2つの整数のインスタンスを作成したときに、値を比較する正しい方法 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度...

クイズに挑戦:Collectorsの使用(上級者向け)

クイズに挑戦:Collectorsの使用(上級者向け) Collectorsクラスから想定どおりの結果を得るために注意すべきこと 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」というレベルは、設問の難易度ではなく、対応する試験による分類です。しかし、ほとんどすべての場合において、「上級者向け」の方が難しくなります。設問は認定試験対策として作成しており、認定試験と同じルールの適用を意図しています。文章は文字どおりに解釈してください。回答者を引っかけようとする設問ではなく、率直に言語の詳細な知識を試すものだと考えてください。 collectメソッドと、Collectorsクラスのグループまたはパーティションのデータを使ってコレクションに結果を保存したいと思います。次のStudentクラスがあり、初期化済みで未使用のStream<Student> sがスコープ内にあるとします。このsには、さまざまな年齢の学生が含まれています。 class Student { private String name; private Integer age; Student(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public Integer getAge() { return age; } } 次のコード部分のうち、18歳未満の学生の数と18歳以上の学生の数が最適な方法で表示されるものはどれですか。1つ選んでください。 s.collect(Collectors.groupingBy( Student::getAge() >= 18, Collectors.counting())) .forEach((c, d) -> System.out.println(d)); s.collect(Collectors.groupingBy( a -> a.getAge() >= 18, Collectors.mapping( Student::getName, Collectors.counting()))) .forEach((c, d) -> System.out.println(d)); s.collect(Collectors.partitioningBy( a -> a.getAge() >= 18, Collectors.counting())) .forEach((c, d) -> System.out.println(d)); List<Integer> l = Arrays.asList(0, 0); s.forEach(w -> { if (w.getAge() >= 18) { l.set(1, l.get(1) + 1); } else { l.set(0, l.get(0) + 1); }}); l.forEach(System.out::println); 解答:この設問は、データを収集し、ある基準に従ってグループ化するいくつかの方法を示しています。選択肢A、B、Cでは、CollectorsクラスのユーティリティとStream.collectメソッドを使ってこれを実現しようとしています。選択肢Dでは、その処理を手作業で行おうとしています。 まずは、簡単な選択肢から見ていきます。選択肢Aのコードには、重大な構文エラーが存在します。ここでは、メソッド参照を使用し、次の式でメソッドを呼び出そうとしています。 Student::getAge() この構文は正しくありません。メソッド参照の構文をこのような形で使うことはできません。そのため、選択肢Aは誤りです。 通常、この試験では「人間コンパイラ」的な問題は避けられる傾向にあります。IDE全盛のこの時代では、コードを打ち込めばすぐに構文チェックが行われるため、そのようなスキルは役立つものではないからです。この選択肢が誤りであると判断できる理由がそれだけなら、実際の試験でこの選択肢が採用されることはないでしょう。しかし、この選択肢には、誤りであると判断できる理由が他に2つあります。1つは、別の選択肢にあるアプローチの方が設計的に優れていることです。少しばかりではありますが、実際の改善であることはもうすぐわかっていただけるはずです。2つ目の理由は、他に正解があるものの、この設問が単一選択問題であることです。そのため、別の答えを見つけた時点で、注意深くコードを見るようになり、エラーに気づくことになるはずです。ここでヒントとなるのは、この試験の際に、正しいと思われる最初の答えをそのまま解答に選ぶのは賢明でないということです。時間が足りない場合以外、他のすべての答えが確かに誤りであると納得するまで時間をかけるべきです。 注目すべきは、構文エラーを含む式 Student::getAge() >= 18 を正しい式 a -> a.getAge() >= 18 に置き換えれば、選択肢Aから正しい出力が得られ、その場合に問題となるのは設計の質だけであるという点です。 ただし、この時点で、選択肢Aをすぐに除外すべきであることは明らかであり、選択肢Aよりも優れた設計のアプローチが見つかって、その設計が優れている理由がわかることははっきりしています。 選択肢Bのコードは問題なくコンパイルでき、正しい結果が出力されます。これを理解するために、Collectionsクラスが持ついくつかの重要な動作について詳しく見てみます。groupingByメソッドは、関数(Function)を引数として受け取るCollector動作を生成します。この関数を、分類関数(classifier)と呼びます。たとえば、次のコードについて考えてみます。名前のストリームに対してgroupingByコレクション操作を実行するものです。 Stream.of("Fred", "Jim", "Sheila", "Chris", "Steve", "Hermann", "Andy", "Sophie") .collect(Collectors.groupingBy(n -> n.length())) ここでの分類関数は、名前(String)を受け取ってその長さを返す次の式です。 n -> n.length() 結果として、表1に示すようなMap<Integer, List<String>>が生成されます。 表1:キーと、各キーに関連付けられた値 分類関数からキーとして返されるそれぞれの値がこのMapにどのように格納されているかと、各キーに関連付けられた値が、そのキーを生成したストリームのアイテムすべてを含むListであることに注目してください。 groupingBy動作の亜種として、「ダウンストリーム・コレクタ」を持つものがあります。ダウンストリーム・コレクタを使うことにより、特定のキーを生成するアイテムを、同種のアイテムすべてからなるリストにそのまま追加するのではなく、後続のコレクション操作を使って各アイテムを処理することができます。これは、Listに送信されるアイテムを処理するセカンダリ・ストリーム・プロセスのようなものです。ダウンストリームでよく使われるコレクタの1つが、countingコレクタです。このコレクタを処理で使うことにより、値を名前のリストからリストの要素数に変えることができます。 次のコード Stream.of("Fred", "Jim", "Sheila", "Chris", "Steve", "Hermann", "Andy", "Sophie") .collect(Collectors.groupingBy( n -> n.length(), Collectors.counting())) は、表2に示すMap<Integer, Long>を返します。 表2:ダウンストリーム・コレクタを使用した場合のキーと、各キーに関連付けられた値 選択肢Bの動作はこの考え方に似ていますが、異なる点もいくつかあります。まず、分類関数(すなわち、結果のMapのキー)が数値ではなくブール値であることです。これは問題ありません。18歳以上の学生と18歳未満の学生を分類するという目的に沿っているからです。しかし、選択肢Bのコードでのダウンストリーム操作は1つではなく、2つの操作を連鎖させています。もちろんこのような連鎖は許可されており、大変役立つこともあります。しかし、この設問の場合、最初のダウンストリーム・コレクタで実際に行っているのは、各StudentオブジェクトからStudentの名前を抽出するマッピング操作です。2つ目のダウンストリーム・コレクタでは、その結果として得られる名前の数を数えています。 マッピング操作が結果を誤ることはありません。このコードでは実質的に、18歳以上の学生と18歳未満の学生の名前が数えられ、同じ数値が生成されます。ただし、これは無駄な努力です。そのため、このコードは効率の面でも、可読性の面でも、最適なものではありません。無関係で紛らわしいコードが含まれており、混乱が生じるリスクがあるからです。このような無駄な努力をしていない別の選択肢が後ほど登場するため、そこから選択肢Bは誤りであることがわかります。選択肢Bでは正しいレスポンスが生成されますが、もっとも効率のよい選択肢ではありません。 Collectorsクラスには、groupingBy動作のファクトリに加えて、似たような結果を生成する別のファクトリも存在します。このファクトリは、partitioningByと呼ばれています。動作の違いは、任意の型のキーを持つMapを作成するのではなく、Boolean型のキーを持つMapを作成するという点だけです。そのため、分類関数として関数(Function)ではなく条件(Predicate)を指定します。選択肢Cでは、partitioningBy動作を使って正しい出力が行われています。これは、2つの理由で選択肢Bよりも優れています。1つ目は、学生の名前を抽出するという無駄な手順が含まれていないことです。2つ目は、partitioningByが、単純なtrue/falseの結果を使ってグループ化するという目的のみに特化したものであることです。そのため、設計的に(少しばかり)優れた選択です。同じ論理で、(構文が有効だったとしても)選択肢Aより優れています。 手作業で分類するコードを使っている選択肢Dでも、正しい結果が生成される可能性があります。重大な問題は、このコードが副作用によって動作していることです。具体的に言えば、ラムダ式の外側にある変数を変更している部分です。この種の動作は、安全に同時実行(パラレル実行)することができません。ストリームは簡単にパラレル・モードで実行できるからこそ、特にストリームベースのシステムではこの種のコードは避けるべきです。 なお、この考え方が、ラムダ式(およびその登場より前のメソッド・ローカル・クラス)が設計されたときに漠然と示されていたことに注目すべきです。具体的に言うなら、ラムダ式やネスト・クラスの中からは、実質的にfinalである場合を除き、他のメソッド・ローカル変数へのアクセスが禁止されているという点です。選択肢Dのコードでは、実質的にfinalな参照を使って、参照先のListに格納されている可変データにアクセスすることで副作用が発生しています。 このコードは問題なくコンパイルでき、ストリームが逐次実行されれば、正しい結果が出力されます。ただし、設計はよくなく、ストリームがパラレルであれば失敗します。設計に問題があり、ストリームがパラレルの場合は失敗するため、選択肢Dは誤りです。 正解は選択肢Cです。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する Arquillian:簡単なJakarta EEテスト ArchUnitでアーキテクチャの単体テストを行う 新しいJava Magazine 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Simon Roberts Simon Roberts:Sun Microsystemsがイギリスで初めてJavaの研修を行う少し前にSunに入社し、Sun認定Javaプログラマー試験とSun認定Java開発者試験の作成に携わる。複数のJava認定ガイドを執筆し、現在はフリーランスでPearson InformITにおいて録画やライブによるビデオ・トレーニングを行っている(直接またはO'Reilly Safari Books Onlineサービス経由で視聴可能)。OracleのJava認定プロジェクトにも継続的に関わっている。   Mikalai Zaikin Mikalai Zaikin:ベラルーシのミンスクを拠点とするIBA IT ParkのリードJava開発者。OracleによるJava認定試験の作成に携わるとともに、複数のJava認定教科書のテクニカル・レビューを行っている。Kathy Sierra氏とBert Bates氏による有名な学習ガイド『Sun Certified Programmer for Java』では、3版にわたってテクニカル・レビューを務めた。

クイズに挑戦:Collectorsの使用(上級者向け) Collectorsクラスから想定どおりの結果を得るために注意すべきこと 著者:Simon Roberts、Mikalai Zaikin 2019年8月26日 過去にこのクイズの設問に挑戦したことがある方なら、どれ1つとして簡単な問題はないことをご存じでしょう。クイズの設問は、認定試験の中でも難しいものに合わせています。「中級者向け」「上級者向け」とい...

作ってみよう:自分だけのテキスト・エディタ(パート1)

新連載:階層化設計と反復型開発を使ってライン・エディタをテキスト・エディタに進化させる 著者:Ian Darwin 2019年8月20日 本記事のタイトルを読んだ方は、「なぜJavaでテキスト・エディタを作りたいのだろうか。JavaはエンタープライズWebアプリのためのものではないのか」と思うかもしれません。私の最初の答えは、「とんでもない」です。Javaは現在もデスクトップで使われており、活躍しています。私の次の答えは、一部のJava開発者にとって主な「安全地帯」であるWeb環境から離れることで、設計や、興味深い実装の問題に焦点を移すというものです。 本記事では、反復型実装により、簡単なラインモード・テキスト・エディタを作ることに的を絞ります。つまり、シンプルな実装から始め、新機能を追加しながら設計を更新し、その再実装を行います。 次回の記事では、このエディタをグラフィカルなデスクトップ・エディタに進化させます。形はさまざまに変わっても、実体が純粋なテキスト・エディタである点、つまり、プレーン・テキストのファイルを変更するプログラムであることは変わりません。プレーン・テキストとは、フォントや色が変わらないテキストです。バッチ・ファイルやスクリプト・ファイル、プログラムのソース・ファイル、構成ファイル、ログ・ファイルなど、今でも世界中でコンピュータ向けの情報の大部分に使われています。プレーン・テキスト・エディタと完全なワード・プロセッサの間には、大きな隔たりがあります。ワード・プロセッサは、文字の書体やサイズや色の選択、画像やスプレッドシートの埋め込み、テキストの左揃え、右揃え、中央揃えなどの多くの機能を備えています。短い連載記事でこれらすべてを紹介するのは難しいと思われることから、まずはプレーン・テキストに焦点を当てることにします。 エディタを設計する場合、主に2つのことを考える必要があります。1つはユーザー・インタフェース(UI)またはコマンド・レイヤー、もう1つはバッファ管理です。UIまたはコマンド・レイヤーでは、ユーザーがメモリ内のバッファに対して何をすることができるかを定義します。こういったタスクは、たとえば、ライン・エディタであれば簡単なコマンド、スクリーン・エディタならマウス操作、インタラクティブ・システムなら音声コマンドになるでしょう。バッファ管理とは、ユーザーがバッファ内のテキストをどのように扱うかということです。通常、テキスト・エディタ(およびその強力な親戚であるワード・プロセッサ)は、変更しているファイルのコピーをメモリ内に保持しています。このコピーは、メモリ内のバッファに保管されます。エディタでは、ユーザーがエディタを終了したとき、または何らかの「保存」コマンドが発行されたときに、この変更されたテキストが元のファイルの代わりにディスクに書き込まれます。バッファ管理はモデル・コードとしても知られ、メモリ内にある編集中のファイルの内容を管理することに関係しています。最終的なプロダクトを便利でメンテナンスしやすいものにするためには、UIとバッファ管理、そしてその間にあるすべての重要なインタフェースをうまく設計する必要があります。   コードのレイヤー間の境界 Javaインタフェースの定義は、コードの論理レイヤーを分離するための強力(で一般的)な方法です。アプリケーションのレイヤー間や、(現在または将来的に)複数の実装を持つ可能性が高いクラスでは、インタフェースを使うべきです。その結果、クラスが特定の実装ではなく、インタフェースに依存するようにすることができます。 この場合、BufferPrimsインタフェースが両方のニーズに合致します。このインタフェースはレイヤー境界であり、複数の実装を持ちます。これは、バックエンドにデータベースがあるアプリケーションに似ています。このようなアプリケーションではおそらく、中間(ビジネス・ロジック)レイヤーとデータベースのコードの間にインタフェースが存在するでしょう。これにより、JDBC、Java Persistence API(JPA)/Hibernate、場合によってはNoSQLデータベースを切り換えて使用できるようになります。JPAのEntityManagerやHibernateのSessionは、この目的では十分に汎用的だと言う方もいるでしょう。また、アプリケーション固有のインタフェースを使うことを提案する方もいるかもしれません。すべてのアプリケーションに当てはまる正しい1つの答えはなく、これは設計上の考慮事項になります。 エディタには、コマンド・レイヤーとバッファ管理レイヤーとの間のインタフェースが必要です。このレイヤー間のインタフェースはとても簡単なもので、たとえば次のようになります。 public interface BufferPrims { addLineAfter(int afterLine, String newLine); deleteLine(int lineNumber); replaceText(oldText, newText); } このインタフェースでは、バッファ管理がどのように動作するかについてコマンド・コードにほとんど伝えていません。同時に、UIがどのように動作するかについてバッファ管理に何も伝えていません。この点は重要です。相手方に影響を与えずに片方を交換できることが望ましいからです。これは、レイヤー化されたソフトウェア全般に当てはまります。レイヤーは、その上にあるレイヤーについて何も知るべきではありません(たとえば、さまざまなUIから呼び出せるようにするためです)。また、知っているべきなのは、直下のレイヤーを呼び出す方法だけで、他には何も必要ありません。 実際のエディタを作るためには、もう少し包括的なインタフェースが必要です。ここでは、次のようにまとめました。 public interface BufferPrims { final int NO_NUM = 0, INF = Integer.MAX_VALUE; void addLines(List<String> newLines); void addLines(int start, List<String> newLines); void deleteLines(int start, int end); void clearBuffer(); void readBuffer(String fileName); void writeBuffer(String fileName); int getCurrentLineNumber(); String getCurrentLine(); int goToLine(int n); int size(); // 古いコレクションの時点での行数 /** 1つまたは複数の行を取得 */ String getLine(int ln); List<String> getLines(int i, int j); /** 現在の行のみを対象に、最初またはすべての * 「古い」正規表現を「新しい」テキストに置き換える */ void replace(String oldRE, String newStr, boolean all) /** 各行の最初またはすべての検索対象を置き換える */ void replace(String oldRE, String newStr, boolean all, int startLine, int endLine); boolean isUndoSupported(); /** 直近の操作を元に戻す * オプション・メソッド */ default void undo() { throw new UnsupportedOperationException(); } } ほとんどの操作は単純と思われます。本記事のソース・コードでは、BufferPrimsインタフェースの3つの実装を提示しています。オプションのundoメソッドは、1つの実装には含まれていますが、他の2つには含まれていません。この実装については、以前にCommandデザイン・パターンについての記事で説明しました。 ここにはread()やwrite()を入れるべきではないと思う人や、メイン・プログラムで1行ずつファイルを読み取り、いずれかのadd()メソッドを使って行を取り込むべきだと考える人もいるかもしれません。このインタフェースにread()メソッドやwrite()メソッドがあるのは、効率のためです。1回の読取り操作でファイル全体を読み取るバージョンがあっても構わないでしょう。   バッファ管理 大きく異なる複数の実装が存在するのは、インタフェースが合理的な設計に基づいている証拠です。しかし、このことは効率について何も触れていません。効率を気にしないのであれば、1つのStringオブジェクトにすべてを保管することもできます。しかし、文字列は不変であるため、このアプローチでは多くの再割当てが必要になります。そのため、純粋な実装の基盤という面では、StringBuilderやStringBufferの方が優れています。実際には、バッファ・プリミティブ(BufferPrims)の最初の実装では、BufferPrimsStringBufferを使っています。 StringBufferには、バッファの内容を変更する組込みメソッドなどのいくつかのメリットがあります。しかし、本質的に単語のリストのリスト(さらに正確に言えば、行のリスト)であるものを表す自然な構造ではありません。StringBufferの実装(この実装が可能であることを示すために書くことにしました)では、行が始まる場所と終わる場所を見つけるためだけに、いくらかの作業が必要になります。 整合性を保つため、各行は改行文字1文字('\n')で終わり、キャリッジ・リターン('\r')は完全に禁止することを前提としました。このアプローチにより、改行文字を探すだけで行が終わる場所と次の行が始まる場所を見つけることができます。このクラスのほとんどの操作は、StringBufferのメソッドを呼び出して、そのStringBufferの特定の位置にある文字の取得や設定を行うことで終わります。 たとえば、次に示すのは現在の行の内容を取得するコードです。 @Override public String getCurrentLine() { int startOffset = findLineOffset(current); int len = findLineLengthAt(startOffset); return buffer.substring(startOffset, startOffset + len); } findLineOffsetメソッドでは、正規表現を使って行を検索します。これは改行文字を探すforループほど簡単ではありませんが、実行可能で純粋な実装だと言えます。 同様に、StringBufferベースの行検出にも、同じ2つのメソッドを使っています。 @Override public void deleteLines(int startLine, int endLine) { if (startLine > endLine) { throw new IllegalArgumentException(); } int startOffset = findLineOffset(startLine), endOffset = findLineOffset(endLine); buffer.delete(startOffset, endOffset + findLineLengthAt(endOffset) + 1); } おそらく、もっとも複雑なコマンドは置換コマンド(s)でしょう。「UIとコマンド構造」のセクションでは、いくつかの種類の置換コマンドについて説明します。UIレイヤーでは、すべてのコマンド・オプションを解析した後、次に示す2つのメソッドのいずれかを呼び出す必要があります。 void replace(String oldRE, String newStr, boolean all); void replace(String oldRE, String newStr, boolean all, int startLine, int endLine); all変数では、置換対象となるのが一致したすべての結果なのか、1つ目だけなのかを制御します。次に示すのが、replaceを1行で実装したものです。 @Override public void replace(String oldRE, String newStr, boolean all) { int startOffset = findLineOffset(current); int length = findLineLengthAt(startOffset); String tmp = buffer.substring(startOffset, length); tmp = all ? tmp.replaceAll(oldRE, newStr) : tmp.replace(oldRE newStr); buffer.replace(startOffset, length, tmp); } 第2の実装:バッファ・コードの第2の実装となるのが、BufferPrimsNoUndoです。この実装では、バッファのデータをList<String>に格納しています。行単位での処理は、こちらのデータ構造を使った方が簡単です。たとえば、現在の行を取得する処理は、次のコードだけで実現できます。 @Override public String getCurrentLine() { return buffer.get( lineNumToIndex(current)); } (行番号は1から始まりますが、Listのインデックスは0から始まります。そのため、lineNumToIndex()メソッドで行番号からリストのインデックスに変換しています。こうする方が、毎回1を引くよりもきれいに見えます。) 「行の削除」操作も簡単になります。 @Override public void deleteLines(int startLnum, int end) { int startIx = lineNumToIndex(startLnum); for (int i = startIx; i < end; i++) { if (buffer.isEmpty()) { System.out.println( "?Deleted all lines!"); break; } buffer.remove(startIx); // iではない } current = startLnum; } なお、このクラスのメソッドの一部が、AbstractBufferPrimsクラスに格納されていることに注意してください。このクラスは、両方のListベースの実装で使用しています。 第3の実装:最後のBufferPrimsWithUndoは、一歩先に進んだ実装で、その名のとおり「元に戻す」操作を実装しています。簡潔に言えば、バッファを変更する操作を行うたびに、その逆の操作を行うコードを含むラムダ式も作成されます。たとえば、ここでの「行の削除」操作は次のようになります。 @Override public void deleteLines(int startLnum, int end) { List<String> undoLines = new ArrayList<>(); for (int i = startLnum; i < end; i++) { if (buffer.isEmpty()) { System.out.println("?Deleted all lines!"); break; } undoLines.add(buffer.remove(i - 1)); } current = startLnum; if (!undoLines.isEmpty()) { pushUndo("delete lines " + startLnum + " to " + end, () -> addLines(startLnum, undoLines)); } } 一部の操作はBufferPrimsNoUndoととてもよく似ているため、実際には、super()を使ってAbstractBufferPrimsクラスの処理を再利用しています。 @Override public void addLine(String newLine) { super.addLine(newLine); pushUndo("add 1 line", () -> deleteLines(current, current)); } pushUndo()メソッドでは、説明文字列(GUIのあるエディタで使うためのもの)と、現在のコマンドを「元に戻す」操作を行うラムダ式をまとめるラッパー・オブジェクトを作成しています。deleteLines()の「元に戻す」操作では、削除された行すべてを追加できることが必要です。そのため、すべての行をListに格納し、削除の逆の操作であるaddLines()に渡しています。「元に戻す」のメカニズムと、そのメカニズムを実装するCommandデザイン・パターンの詳しい説明は、先ほど触れた記事をご覧ください。   UIとコマンド構造 すべてをゼロから再発明(通常、これはよくない考え方です)しなくてもよいように、このライン・エディタのUIには、UNIXのedコマンドのUIを堂々と拝借することにします。このUIは、何十年もの間にわたって標準であり続けており、exおよびviの両者のベースとなり、さらにはストリーム・エディタsedの大部分のベースとなりました。 次に示すのは、すべてのコマンドの基本フォーマットです。 [n,m]C[operands] この意味は次のとおりです。 角括弧は、その中のテキストが省略可能であることを示します。 nとmは行番号です(1から始まり、デフォルトは現在の行です。現在の行とは、最後に操作を行った行のことです)。 Cは1文字コマンドです(たとえば、dは削除、aは追加、sは置換)。適時最新のコマンド・リストは、ソース・プロジェクトのREADMEファイルに記載されています。 operands(オペランド)は、使用するコマンドによって異なります。 なお、小文字1文字でコマンドを表すという、このインタフェースの設計は、最初にこの設計が生み出されたころの、ユーザーとコンピュータとの間の非常に低速なキーボード・インタフェースの影響を受けたものであることには注目する価値があります。しかしこれは、設計を無制限に拡大させないことを意図した選択でもありました。つまり、可能なコマンドは26個ほどしか想定しなかったということです。よいことか悪いことか、後の開発者はいくつかの大文字コマンドを追加しました。今回のエディタで大文字コマンドは実装しませんが、最近のUNIXやLinuxのedではおそらく実装されているでしょう。 すべてのJavaアプリケーションには、起動のためのpublic static void main(String[] args)メソッドが必要です。通常、このメソッドではコマンドライン・オプション(存在する場合)を処理し、ファイルのチェックやオープンを行い、処理用のメソッドに制御を委譲します。一般的に、処理用のメソッドは静的でないインスタンス・メソッドです。今回の例でのメイン・プログラムは、LineEditor.javaに含まれています。 ここでのmainメソッド内にはループがあります。そこでは、コンソールから1行を読み取り、解析してエディタのコマンドである可能性が高いかを確認し、コマンドであれば、その文字を文字コマンド固有のルーチンに渡しています。メイン・コードのループは次のようになっています。 // エディタのメイン・ループ: while ((line = in.readLine()) != null) { ParsedCommand pl = LineParser.parse(line, buffPrims); if (pl == null) { System.out.println("?"); continue; } EditCommand c = commands[pl.cmdLetter]; if (c == null) { System.out.println( "?Unknown command in " + line); } else { c.execute(pl); } } 1文字コマンドを処理するコードは、Commands.javaで設定しています。具体的には、EditCommandオブジェクトの配列を使い、1文字と、コマンドを実装したラムダ式とのマッピングを行っています。任意のASCII文字を使えるよう、この配列の長さは255にしていますが、実際に実装されているのは20ほどしかありません。コマンド処理の簡単な例として、次にpコマンド(印刷を表す"print"の略です)の実装を示します。 // p - 行の印刷 commands['p'] = pl -> { buffPrims.getLines(pl.startNum, pl.endNum) .forEach(System.out::println); }; このコードの変数plは、ParsedCommand(以前はParsedLineでした)を表します。ParsedCommandは、コマンド、行番号の範囲、そしてオペランドを表すクラスです。ユーザーがコマンドを入力するたびに、LineParserクラスのparse()メソッドによって、そのコマンドを表すParsedCommandが作成されます。 コマンド・ハンドラの中には、先ほどのpのように、短くて扱いやすいものもあります。しかし、中にはかなり長いものもあります。興味がある方は、sコマンド(置換を表す"substitute"の略です)の実装をご覧ください。このコマンドでは、ある範囲の行に対して反復処理を行わなければならないだけでなく、デリミタに任意の文字を使用できなければなりません。さらに、デリミタが2回または3回存在することを確認し、最後のデリミタの後にgとpが任意の順番で存在しているかどうかも確認する必要があります。gは"global"(グローバル)または"go across the line"(行をまたぐ)を表します。このコマンドがない場合、edjでは最初に見つかった古いテキストのみが置き換えられます。最後にpを指定した場合、対象の行が印刷されます。以下に、有効なコマンドの例をいくつか示します。 s/him/them/ # 現在の行を対象に、最初の"him"を"them"に変更 s=him=them= # 上記と同じだが、違うデリミタを使用 2,3/him/them/ # 2行目から3行目を対象に、最初の"him"を"them"に変更 5,s/him/them/ # 5行目から末尾までを対象に、最初の"him"を"them"に変更 ,s/him/them/ # すべての行を対象に、最初の"him"を"them"に変更 s/him/them/g # すべての行を対象に、すべての"him"を"them"に変更 s/him/them/p # 現在の行を対象に、最初の"him"を"them"に変更し、 # 行を印刷 s/him/them/gp # 上記の2つの例を組み合わせたもの この構文を学ぶためには時間が必要です。また、すべての種類を正確に解釈するためには、数行のコードが必要になります(parseSubstitute()をご覧ください)。ただし、このコマンドの簡潔さと強力さを見れば、ed(およびそこから派生したviなどのエディタ)が今もオープンソースの世界でシステム管理者や開発者に愛用されている理由がわかります。   パラメータ化テスト 「早い段階から頻繁にテストする」というのは、信頼性の高いコードを書くための格言です。多数の単体テストを作成し、少しでも変更が発生したときに実行するということです。バッファ・プリミティブのテストは簡単で、ほとんどのコードに対してテストが存在します。3種類の実装に対してテストをコピー・アンド・ペーストすることを避けるため、ここではパラメータ化テストという、JUnit 4の機能を使います。@Parametersアノテーションを付加したメソッドからは、コンストラクタの引数(任意の型)リストが返されるようにします。このリストは、テスト・クラスの個々のインスタンスを作成するために使われます。テスト・クラスのフィールドは、コンストラクタによって設定されます。引数は任意の型でよいため、クラス・ディスクリプタ(たとえば、Reflection APIクラス)を使用しています。次に、BufferPrimsTestの関連部分を示します。 @RunWith(Parameterized.class) public class BufferPrimsTest { protected BufferPrims target; public BufferPrimsTest(Class<BufferPrims> clazz) throws Exception { target = clazz.newInstance(); } @Parameters(name = "{0}") public static Class<BufferPrims>[] params() { return (Class<BufferPrims>[]) new Class<?>[] { BufferPrimsStringBuffer.class, BufferPrimsNoUndo.class, BufferPrimsWithUndo.class }; } // @Testアノテーションを付加したメソッド... } コマンドおよび置換オペランドを解析するコードのテストも存在します。   さらなる作業 この状態のedjは、たとえ完全版が手元にあっても、使いたいと思うようなものではないでしょう。あるいは、viやそのさまざまな派生物のようなスクリーンベースのエディタであっても同じでしょう。edのコマンドの一部は実装されておらず、実装されているものもほとんどが不完全です。たとえば、行の範囲を解析する部分には、「検索」の機能がありません。実際のUNIXやLinuxにおけるedの実装では、開始行または終了行の行番号のいずれか(または両方)の代わりに、検索文字列を指定できます。検索文字列を、/pattern/と指定した場合は現在の行から前方(下方向)に検索でき、?pattern?と指定した場合は上方向に検索できます。コードは全体的に、このような機能を追加する必要がある場合、誰でも拡張して完全な実装にできるような設計になっています。   コードの再利用 設計全体を検証するために、UNIXのストリーム・エディタsedのとても簡単な概念実証実装を作成しました。UNIXのsedコマンドは、名前のついたファイル(ファイルが指定されていない場合は標準入力)を1行ずつ読み取り、コマンドラインで指定されていたすべての編集コマンドを各行に適用します。次に例を示します。 sed -e 's/old/new/g' -e 's=more=less=' file1 想像どおりかもしれませんが、file1内のすべての"old"を"new"に置換し、各行の最初の"more"を"less"に置換するものです。これは、バッチ・エディタというよりはストリーム・エディタです。file1は変更せず、変更結果を標準出力に書き込みます。 バッチ・エディタの作成、すなわち、コマンドにエラーがあったときやディスクがいっぱいになったときにファイルを安全に保つことは、今回の概念実証の範囲外です。 このStreamEditorでは、LineEditorとは異なり、1つのコマンドしか実装していません。ただし、実装しているのはもっとも複雑なs(置換)コマンドです。StreamEditorでは、行を解析するコードと置換コマンドの解析コードを再利用しています。このStreamEditorのプロトタイプでは、実装されている1つのコマンドは問題なく動作します。この概念実証のデモとして、stests(stream tests)という名前のシェル・スクリプトを作成しています。次回の記事では、バッファ処理コードを再利用する予定です。   コードの入手 このバージョンのエディタを、edj(editor in Java、「エッジ」のように発音します)と呼んでいます。繰り返しになりますが、全体を1か所で見てみたい方は、GitHubからコードをダウンロードできます。   まとめ 本記事では、かなり単純なテキスト・エディタをJavaだけで実装するために必要な構造の設計を行う際の問題や、その場合のコードの一部について見てきました。ここで、重要な点をいくつか挙げておきます。 行指向のパラダイムで正規表現の力を活用するUIの設計 UIと、土台になるバッファ管理コードとの間のインタフェースの設計 効率的である一方でわかりやすいバッファ管理の実装 UIの設計は、UNIXのedのUIをベースにしています。また、BufferPrimsのインタフェースは、筆者がかなり前に作成したこのエディタのC言語による再実装にかすかに似たものとなっています。その再実装自体は、『Software Tools』という書籍向けにRatForという教育用言語で書いた、さらにその前のバージョンがベースになっています。今回紹介したバージョンのインタフェースは、最初から完全な形で考えついたわけではなく、エディタの進化とともに何度か改訂を重ねた結果です。次回の記事では、このインタフェースを再利用して、実際に使用できるGUIテキスト・エディタを作成する方法を紹介したいと思います。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する Arquillian:簡単なJakarta EEテスト ArchUnitでアーキテクチャの単体テストを行う 新しいJava Magazine クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Ian Darwin Ian Darwin(@Ian_Darwin):Java Champion。メインフレーム・アプリケーションから、UNIXおよびWindows向けのデスクトップ・パブリッシング・アプリケーション、Javaによるデスクトップ・データベース・アプリケーションやAndroid向けのヘルスケア・アプリまで、あらゆる開発を手がける。『Java Cookbook』、『Android Cookbook』(いずれもO'Reilly)の著者。また、Learning Tree Internationalでいくつかのコースを作成し、多くのコースで教えている。

新連載:階層化設計と反復型開発を使ってライン・エディタをテキスト・エディタに進化させる 著者:Ian Darwin 2019年8月20日 本記事のタイトルを読んだ方は、「なぜJavaでテキスト・エディタを作りたいのだろうか。JavaはエンタープライズWebアプリのためのものではないのか」と思うかもしれません。私の最初の答えは、「とんでもない」です。Javaは現在もデスクトップで使われており、活躍しています...

Arquillian:簡単なJakarta EEテスト

Arquillianフレームワークを使ってJakarta EEアプリケーションをテストする方法 著者:Josh Juneau 2019年8月20日 Webアプリケーションやエンタープライズ・アプリケーションのテストは、Java SEプロジェクトのテストよりもはるかに面倒になる場合があります。スコープが異なり、ほとんどの場合にテストするフェーズも異なる、さまざまな種類のファイルが存在するからです。Arquillianは、長い年月をかけて進化してきた強力で堅牢な、Java EEおよびJakarta EE向けのテスト・フレームワークです。JBossプロジェクト(現在はRed Hatの一部)によって開発されたもので、テストやその出力を拡張できる複数のアドオン拡張機能もあります。 Arquillianフレームワークはとても強力ですが、その背景にはある程度の複雑さがあります。テスト・クラスの設定は、行う必要があるテストのレベルに応じて、とても簡単な場合もあれば、かなり複雑な場合もあります。 本記事では、Arquillianフレームワークの構成と、このフレームワークを使用したテストについて紹介します。基本的なJakarta EE 8(Java EE 8と同等)アプリケーションの構成とビルドに加え、JUnit 4とArquillianを使ういくつかのテストについても触れます。いくつかの基本的な例を示した後は、特に重要な機能や拡張機能について説明します。いずれも、Java EEおよびJakarta EEのプロジェクトの検証機能を拡張できるものです。本記事の内容を理解するためには、Java EEまたはJakarta EEプロジェクトの基本的知識が必要です。 サンプル・アプリケーションはMavenを使ってビルドしています。Mavenプロジェクトに対応した任意のIDEを使えるはずですが、本記事の例ではApache NetBeans IDEを使っています。GitHubから、ArquillianExampleという名前の、Maven Webアプリケーション・プロジェクトのサンプルを取得しておくことをお勧めします。   環境を設定する Arquillianフレームワークを使う際に特に難しいことの1つが環境設定です。基本的なテストに必要となるのはわずかなMaven依存性だけですが、正しいバージョンの依存性を使わなければなりません。バージョンが正しくなかった場合、エラーにつながる不整合が起きる可能性があります。ゼロから始める場合は、コマンドラインまたはIDE(Apache NetBeansなど)からMavenアーキタイプを使ってMaven Webアプリケーション・プロジェクトを作成します。Apache NetBeansを使っている場合は、プラットフォームとしてJava EE 8を選んでください。 プロジェクトを作成したら、プロジェクトを右クリックしてPOMファイルを開き、リスト1に示す依存性を追加します。この依存性には、Arquillianの要件が含まれています(注:本記事のサンプル・ソース・コードを使用する場合、Jakarta EEプラットフォームとApache Derbyデータベースに関連する追加の依存性もあります)。 この依存性を眺めてみます。arquillian-bomアーティファクトがArquillianフレームワークの「部品表」になっており、すべての推移的依存性で使われます。POMファイルの標準の<dependencies>セクションには、JUnitフレームワークを追加しています。本記事の執筆時点では、まだJUnit 5はサポートされていないため、ここではJUnit 4を使っています。ただし、ArquillianでJUnit 5を使えるようにする作業も行われています。このAPIでJUnitを動作させるためには、Arquillian JUnitコンテナが必要です。お気に入りのテスト・フレームワークはTestNGだという方のために、このフレームワークを使えるコンテナも存在します。JBoss ShrinkWrap Resolverを使用して、ShrinkWrapをサポートしています。ShrinkWrapにより、コードから宣言的にデプロイメント・アーカイブを作成できます。その他の依存性は、arquillian-weld-ee-embeddedという名前の埋込みCDIコンテナにテスト・アーカイブをデプロイするために必要となります。実現しようとしている、テストのレベルに応じて、いくつかのデプロイメント・オプションが存在します。Weld埋込みコンテナは、データベース接続や、アプリケーション・サーバー・コンテナのその他の機能を使用せずにCDIをテストする場合に便利です。埋込みコンテナを活用することで、起動とテストがスムーズになります。データベース接続テストを実行する必要がある場合や、その他のアプリケーション・サーバー機能を使う必要がある場合は、リモート・コンテナにデプロイすることも可能です。後ほど、GlassFishサーバーに接続する方法も説明します。   小さなアプリケーションを書く この例で使うアプリケーションは、いくつかの小さなデータベース表を操作して、水泳プール会社とその顧客に関するレコードの作成、読取り、更新、削除(CRUD)を行うことができるというものです。Apache NetBeansやその他ほとんどのIDEでは、ウィザードを使用して、非常に短時間でアプリケーションを生成することができます。そのため、アプリケーションの初期生成は省略し、アプリケーション・ロジックのテスト部分を中心に説明します。 Poolはデータベースに格納でき、Customerオブジェクトに関連付けられています。本記事では、Java Persistence API(JPA)とEJB Beanを使って、Poolデータベース操作の単体テストを作成します。また、CDI Beanのテストについても説明します。このBeanでは、データベースを操作するEJB Beanにフロントエンドをバインドするビジネス・ロジックを実行します。なお、EJB BeanをRESTfulサービス呼出しに置き換えることもできる点に注意してください。その場合も、テストは同じように行われます。   基本的なCDI単体テストを書いて実行する それでは、とても簡単なCDIテストから始めます。この基本的なテスト用のCDI Beanでは、単純にCDI注入を使用して、Poolオブジェクトが適切に作成されていることを確認するテストを行います。テストを書く前に、テスト・クラスを適切に設定する必要があります。 一般的に、アプリケーションのビジネス・ロジックを含む各クラスに対応するテスト・クラスが存在する必要があります。この例でのテスト・クラスは、PoolControllerTestという名前です。このテスト・クラスからArquillianを利用する場合、クラス宣言の前に@RunWith(Arquillian.class)アノテーションを付加する必要があります。このアノテーションを使うと、Arquillianエンジンを使ってテストを実行するようテスト・フレームワークに伝えることができます。 各クラスには、指定したすべてのクラスやライブラリ、構成ファイルをテスト・パッケージ(WAR、EAR、JAR)に格納するデプロイメント・メソッドも必要です。このテスト・パッケージは、ビルド後、Arquillianエンジンによって選択済みテスト・コンテナに自動的にデプロイされ、実行されます。その際の出力は、コマンドラインまたはIDEに表示されます。 デプロイメント・パッケージを作るためには、@Deploymentアノテーションを付加したパブリックな静的メソッドからShrinkWrapアーカイブを返します(リスト2にこれを示します)。このデプロイメント・メソッドの中では、Builderパターンを使ってデプロイ可能アーカイブを構築します。その際に、作りたいアーカイブの種類を指定してShrinkWrapのcreate()メソッドを呼び出します。今回の例では、WebArchive.classを作成しています。別の種類のアーカイブには、標準JARを作るJavaArchive、EARファイルを作るEnterpriseArchiveなどがあります。テストで使う各クラスは、CLASSPATHに追加する必要があります。この追加は、addClass()、addClasses()、addPackage()、addPackages()の各メソッドを状況に応じて使用し、行います。また、addAsManifest()メソッドも呼び出し、beans.xmlファイルを追加してCDIを起動できるようにしている点に注意してください。デプロイ用のcreate()ビルダーの一部であるさまざまなメソッドの詳細については、ShrinkWrapのチュートリアルをご覧ください。 リスト3には、PoolControllerのソース・コードが含まれています。コンストラクタでは、2つのPoolオブジェクトを作成してArrayListに追加しています。このArrayListに対して、空でないことを確認するテストを行っています。CDIコントローラは、標準の@Injectアノテーションを使ってテスト・クラスに注入できます。この注入処理は、テスト・メソッドの直前に行う必要があります。このテストではJUnitを使うことから、テスト・メソッドに@Testアノテーションを付加します。また、テスト・メソッドでは、org.junit.Assertで定義されているアサーション・メソッドのいずれかを使って、テストが成功したかどうかを判定します。テスト・クラスの完全なソース・コードは、リスト4をご覧ください。他のJUnitテストと同じように、ブール値を返す式のテストに使用できるAssertionメソッドも複数存在します。選択できるAssertionメソッドのリストについては、JUnitのドキュメントをご覧ください。 IDEまたはコマンドラインからMavenビルドを実行するだけで、テストを実行できます。プロジェクトをビルドするたびにテストが実行されます。テストのみを実行するためには、コマンドラインからmvn testコマンドを使います。Mavenを使ってプロジェクトをビルドする場合や、コマンドラインからテストを実行する場合は、埋込みWeldコンテナ(このプロジェクト用に選択したデプロイメント・コンテナ)でテストが実行されます。テストを実行すると、次のような内容が出力されます。 Tests run:1, Failures:0, Errors:0, Skipped:0 org.javamagazine.arquillianexample.cdi.PoolControllerTest Results : Tests run:1, Failures:0, Errors:0, Skipped:0   JPAとGlassFishを構成する 実際のデータベースに対してテストを行うためには、いくつかのことを決める必要があります。PersistenceContextは、テスト・クラスに直接注入できます。ただし、トランザクションを管理するためにUserTransactionも注入する必要があります。この場合、テスト・クラス自体がCDIコントローラとして扱われます。このタイプのテストは、次のようになります。 @Test public void insertData(){ utx.begin(); em.joinTransaction(); Pool pool = new Pool(); // 値の設定 em.persist(pool); utx.commit(); em.clear(); } 本記事では、PersistenceContextは使わずに、リモートGlassFishサーバーにデプロイしてテストを行います。同じ依存性で動作するため、GlassFishの代わりにPayaraを使うこともできます。また、他のいくつかのサーバーを使うこともできます。リモート・サーバーに対してテストを行うことで、多くのメリットが生じます。たとえば、テスト環境ではなく実環境でテストができることや、言うまでもありませんが、本番環境でのユースケースに一致するように、データベース接続プールやサーバー環境設定を構成できることです。 リモート・サーバーに対してテストを行う場合、テストを実行する前にサーバーが稼働していなければなりません。そうでない場合、テストは失敗します。サーバーはArquillianエンジンの外にあるため、テストを実行するマシンと同じマシンにインストールされていても、「リモート」サーバーとして構成する必要があります。別の方法として、実際にリモートのサーバーを構成してテストを実行することもできます。 リモート・サーバー環境を設定するためには、src/test/java/resources領域に追加の設定が必要です。また、リスト5に示すような、arquillian-glassfish-remote-3.1への依存性をPOMファイルに追加する必要があります。GlassFishサーバーにログインするための資格証明を、リスト6に示すようにarquillian.xmlファイルに記述する必要があります。 コンテナ設定の属性の1つに、adminHostがある点に注意してください。この属性は、必要に応じて実際のリモート・サーバーに向けることができます。テスト・データベースを使用してテストを行えるように、test-persistence.xmlファイルをこのリソース領域に設定しておくとよいでしょう。test-persistence.xmlという名前の永続コンテキストを作成し、プロジェクトのsrc/test/java/resourcesフォルダに配置します。このファイルには、リモート・アプリケーション・サーバー・コンテナ内で構成されるデータソース用のJava Transaction API(JTA)接続構成を含める必要があります。 これでリモートGlassFishサーバー用の構成が整いました。次は、EJB Bean CustomerFacadeのテストを作成します。EJBテストは、src/test/javaフォルダに配置し、org.javamagazine.arquillianexample.session.CustomerFacadeTestという名前にする必要があります。CustomerFacadeTestのソース・コードをリスト7に示します。このテスト・クラスの宣言の前には、標準の@RunWith(Arquillian.class)アノテーションを含める必要があります。また、このクラスには、ShrinkWrapアーカイブを返すために、@Deploymentアノテーションを付加した静的メソッドが含まれている必要があります。 デプロイメント・メソッドは、createDeployment()という名前とし、そこには、EJBテストを実行するためにCLASSPATHに追加する必要がある各クラスへの参照を含めています。このデプロイメントでは、テスト・デプロイメント・アーティファクト内のCDIを構成するために、ビルダー・パターンを使って addAsManifestResource(EmptyAsset.INSTANCE,"beans.xml") を呼び出しています。このデプロイメントには、永続性コンテキストを構成するために、 addAsResource("test-persistence.xml", "META-INF/persistence.xml") の呼出しも含めています。 この場合、test-persistence.xmlファイルが、テスト・デプロイメントの標準のpersistence.xmlファイルとして読み込まれます。CustomerFacadeTest内のテスト・メソッドは非常にシンプルです。findAllCustomers()メソッドがCustomersエンティティの問合せを行ってその結果を返したかどうかを判定するために、Assert.assertTrueを呼び出しています。 実際のアプリケーションでは、EJB Beanを直接呼び出すのではなく、フロントエンドからCDIコントローラCustomerControllerを呼び出します。そこで、CustomerController CDI Beanが適切にアプリケーション・ロジックを呼び出して画面に結果を返すことを確認するテストを行う必要があります。リスト8に示すように、CDIコントローラのテストは、org.javamagazine.arquillianexample.cdi.CustomerControllerTestを使用して行います。EJBのテストとよく似ていますが、このテストではCustomerController getCustomerList()メソッドを呼び出し、メソッドに移入が行われていることを確認しています。インスタンスが生成される際に、CustomerControllerクラスによってcustomerListが移入されるため、このテストからはtrueという結果が返されるはずです。   テスト実行のオプション テストは、コマンドラインまたはIDEから実行できます。テストするファイルごとに別々にテストを実行することも、プロジェクトのすべてのテストをビルド・プロセスに利用することもできます。コマンドラインから1つのファイルのテストを実行するためには、コマンドラインを開いてプロジェクトのディレクトリに移動し、次のコマンドを発行します。 mvn test テストの結果は即座に表示されます。X個のテストが設定されている場合、X回成功する必要があります。Mavenビルドの一部としてテストを実行している場合、いずれかのテストが失敗したときは、ビルドも失敗するため、アプリケーションのパッケージ化は行われません。 視覚的なフィードバックを受け取りたい場合は、IDEでテストを行うとよいでしょう。NetBeans IDEでは、テスト・ファイルを右クリックするか、図1のようにプロジェクト自体を右クリックして「Test File」を選択することで、テストを実行できます。 図1:NetBeans IDE内で1つのテストを実行する NetBeans内でテストを実行した場合、テストの結果がTest Resultsパネルに表示されます。複数のテストがある場合、図2のように、失敗した各テストがパネルに表示されるため、そこから結果を解析して修正を行うことができます。パネルの左側には、簡単にテスト結果を移動するボタンや、テストを再実行するボタンもあります。 図2:Apache NetBeansのTest Resultsパネル   複数のコンテナによるテスト 別のコンテナでテストを行えるようにプロジェクトを構成するためには、POMファイルでMavenプロファイルを宣言することを検討します。Mavenプロファイルを使うことで、各コンテナに対する依存性をそれぞれ分離し、プロジェクトのビルド時に希望のプロファイルを選択することができます。また、リスト9に示すように、POMファイルでactiveByDefault要素をtrueに設定し、デフォルトのプロファイルを指定することも可能です。 各プロファイルには、コンテナに対する依存性が含まれています。activeByDefault要素を変更して、アクティブなコンテナを切り替えることができます。なお、IDEの中には、ユーザー・インタフェースで複数のMavenプロファイルから選択できるものもあることに注意してください。   高度な内容 Arquillianフレームワークには、テスト・クラスで使用して、テストの調整や実行の制御をさらに行うことができるテスト補助機能が多数含まれています。たとえば、先ほどの例でお見せしたように、注入ポイントは、@Injectアノテーションを使ってフィールドに作成することも、テスト・メソッドで引数として宣言して直接作成することもできます。 こちらも例で示しましたが、テスト・クラスにセッションBeanを注入するために、@EJB補助機能を使用します。その他の補助機能には、@PersistenceContext、@PersistenceUnit、@Resourceなどがあります。最初の2つは、永続コンテキストと永続ユニットを示します。@Resourceアノテーションは、Java Naming and Directory Interface(JNDI)で利用できるオブジェクトの注入に使用します。他の利用可能なJNDIリソースに対するリモート・コンテナ・テストを行う場合、このオプションが非常に役立ちます。 テストは、コンテナ・モードとクライアント・モードという2つのモードで実行できます。デフォルトはコンテナ・モードです。このモードでは、Arquillianのサポート・クラスを追加して@Deploymentを再パッケージ化することが可能なため、コンテナ内でリモート・テストを行うことができます。 クライアント・モードを選択した場合、@Deploymentの再パッケージ化やリモート・サーバーへのデプロイは行われません。JVM内でテスト・ケースが実行されるため、クライアントが外側からコンテナをテストすることができます。クライアント・モードで実行するためには、静的デプロイメント・メソッドに次のアノテーションを付加します。 @Deployment(testable=false) コンテナのテストとクライアントのテストの両方を実行するためには、デプロイメントでtestable=trueを宣言し、クライアント・モードで実行するテスト・メソッドに@RunAsClientアノテーションを付加します。クライアントとして実行する理由の1つに、Warp拡張機能を使ってフロントエンドのテストを行えるようにする点が挙げられます。Warp拡張機能を使うことで、クライアントサイドのテストを書いて、サーバーサイドのロジックを検証することができます。これにより、クライアントとサーバーの両方を使って行う結合テストが可能になります。   拡張機能 複数のArquillian拡張機能をArquillianと組み合わせることにより、さまざまなタイプのテストを実現できます。前述のとおり、Warp拡張機能を使用して、サーバーサイドのロジックを検証する、クライアントサイドのテストを書くことができます。よく使われる別の拡張機能に、Grapheneがあります。Grapheneは、JavaServer Faces(JSF)やSpring MVCで構築したフロントエンドをテストする場合に特に便利でしょう。Grapheneでは、Selenium WebDriverを使ってプログラム的な方法でブラウザを操作することができます。そのため、Javaコードを使用してフォームに入力することや、ビジネス・ロジックによってWebページを移動すること、そしてアサーションで動作のテストを行うことができます。その過程でコンテンツを検証し、UI内で適切な機能が実現されていることを確認することができます。Selenium WebDriverを使用する別の拡張機能であるDroneでは、ブラウザのライフサイクルを管理し、ブラウザをテスト・クラスに注入することができます。Graphene拡張機能はDroneとSeleniumに依存しているため、プロジェクトにいくつかの依存性を追加して、これらの拡張機能を利用できるようにする必要があります。Grapheneテストの@Deploymentは、「クライアント」モードで実行する必要があります。つまり、testable=false属性を含める必要があります。ユーザー・インタフェースのテスト用のデプロイメント・パッケージには、テストされるそれぞれのビューを含める必要があります。そのため、アプリケーションにcustomer.xhtmlという名前のビューが含まれている場合、次のようにして、@Deploymentメソッドでこのリソースを追加する必要があります。 .addAsWebResource("/customer.xhtml"); Grapheneにより、マークアップではなくJavaを使って、別々のページおよびそれらのページに含まれる個々の機能をテストすることが可能になる「ページ・オブジェクト」および「ページ断片」を作成できます。本記事ではこういった考え方について詳しくは説明しませんが、テストのニーズを満たせるように、このような機能を確認しておくことを強くお勧めします。   まとめ Arquillianフレームワークにより、エンタープライズ・アプリケーションでおもに利用されるコンポーネントのテストが実現します。そのため、Java EE/Jakarta EE開発者にとって欠かせないツールです。このフレームワークでは、的を絞った細かいテストをサポートしているため、選択したクラスや機能のみをテスト・デプロイメントに含めることができます。また、JSF、REST、サーブレット、Spring MVCなど、エンタープライズ開発で使用されるテクノロジーのテストを実現する多くの拡張機能が作成されている、成熟したテスト・フレームワークでもあります。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する ArchUnitでアーキテクチャの単体テストを行う 新しいJava Magazine 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Josh Juneau Josh Juneau(@javajuneau):アプリケーション開発者、システム・アナリスト、データベース管理者。おもに、Javaやその他のJVM言語を使った開発に従事。Oracle Technology NetworkやJava Magazineで多くの記事を執筆し、JavaやJava EEに関する複数の書籍をApressから出版している。JSR 372およびJSR 378のJCP専門家グループのメンバーを経験。NetBeans Dream Teamメンバー、Java Champion、CJUG OSS Initiativeのリーダーであり、JavaPubHouse Off Heapポッドキャストにレギュラー出演中。

Arquillianフレームワークを使ってJakarta EEアプリケーションをテストする方法 著者:Josh Juneau 2019年8月20日 Webアプリケーションやエンタープライズ・アプリケーションのテストは、Java SEプロジェクトのテストよりもはるかに面倒になる場合があります。スコープが異なり、ほとんどの場合にテストするフェーズも異なる、さまざまな種類のファイルが存在するからです。Arqui...

ArchUnitでアーキテクチャの単体テストを行う

アーキテクチャの欠陥をビルド時に発見 著者:Jonas Havers 2019年8月20日 開発組織がよく直面する問題に、コードの実装がもともとの設計やアーキテクチャからたびたびずれてしまうことがあるというものがあります。この問題は、大規模なプロジェクトでは特にですが、よく起きるものであるため、コードの実装と最初に定義されたアーキテクチャとの整合性をテストする新しいツールが登場しています。ArchUnitは、小さくシンプルで拡張可能な、オープンソースのJavaテスト・ライブラリです。このライブラリは、事前に定義したアプリケーション・アーキテクチャの特徴やアーキテクチャの制約を検証するためのものです。ArchUnitのテストは、単体テストとして記述して実行します。そのため、開発者やアプリケーション・アーキテクトが、作業に対するフィードバックを迅速に得ることができます。アーキテクチャの違反が含まれていた場合、このテストにより、ソフトウェアのビルドが確実に中断されます。 本記事では、アーキテクチャのテストを行うべき理由と、ArchUnitを使って実際にそのテストを開始する方法について説明します。本記事で紹介しているコード・スニペットや、さらなるサンプルは、筆者のGitHubリポジトリで公開しています。   アーキテクチャのテストを行うべき理由 ソフトウェアのアーキテクチャは、わかりやすく変更しやすいコードベースを実現するためや、ソフトウェアの品質目標に準拠するために重要な前提条件です。コードベースについて言えば、ソフトウェアのアーキテクチャの主な目標は、保守性、置換性、拡張性の3つです。それらの目標を達成する能力を最大化することにより、チームの反復作業の速度を高めることができます。すなわち、アプリケーションが成長したときに、機能追加やバグの修正を短時間で行うことができます。ソフトウェア・システムの保守性、置換性、拡張性を維持するためには、そのシステムがモジュール式になっており、相互依存ができる限り少なくかつ正確であることを保証する必要があります。そうすれば、凝集度が高くかつ疎結合であるシステムが実現します。 こういった目標は、一定のパターンやコード表記規則の導入により達成できます。その場合、該当するパターンや規則を完全に文書化したうえで、それに賛同している開発チーム全体に伝達する必要があります。 既存のソフトウェア・システムの保守が難しくなった場合、自動アーキテクチャ検証を事後導入することも適切な選択肢です。テストによって、技術的負債を段階的に減らしていくことができます。こうすることで、目標としたプロジェクト・アーキテクチャの実現に向けた進捗の監視や検証を行うことができます。   アーキテクチャのテストを記述する準備 通常、アプリケーション・アーキテクチャのコンセプトや構造をテストするためには、アーキテクチャ・モデルをコードにマッピングする作業か、既存のアプリケーションからアーキテクチャ・モデルを導出する作業が最初に必要になります。これを行う場合、あらかじめコード構造について考えておくだけでなく、アプリケーションのコードでどのようにすればドメイン・コンセプトや技術的コンセプトを特定できるか(または、特定できるようになるか)を考えておくことが必要です。これには、「コントローラ」や「サービス」などの具体的なアプリケーション・コンポーネントの技術用語や、「プロダクト」や「顧客」などのドメイン固有用語、そしてそれらの間の関係を特定することが含まれます。 用語、関係、表記規則に賛同したら、静的アーキテクチャのルール体系を作成できます。この体系により、開発者はそのルールに準拠したコードを書くことや変更することができます。つまり、レイヤーやパッケージ、クラスのネーミング方式、アノテーションなどを使用してコンセプトを実装することにより、メンタル・モデルをマッピングすることができます。   ArchUnitを選ぶ理由 最初のArchUnitライブラリは、Peter Gafert氏が2017年に作成しました。ArchUnitにより、アプリケーションのクラスを特別なJavaコード構造にインポートし、Javaの任意の単体テスト・フレームワークを使ってコードとその構造をテストすることができます。ArchUnitでは、実行可能テスト形式でアプリケーション・アーキテクチャの静的プロパティのルールを実装できます。たとえば、次のようなものです。 パッケージ依存性チェック クラス依存性チェック クラスとパッケージの包含性チェック 継承チェック アノテーション・チェック レイヤー・チェック サイクル・チェック さらに、コンストラクタ、メソッド、フィールド、メンバー、および「コード・ユニット」(すなわち、他のコードにアクセスできるメソッド、コンストラクタ、静的クラス初期化機能)のカスタム・テストを作成できます。これらのチェックを使用して、固有のアーキテクチャ制約に加え、ネーミング規則などのコーディング・ルールも検証することができます。 レイヤー間やパッケージ間の依存性をテストするツールにはさまざまなものがあります。これはアーキテクチャの検証において、とりわけレイヤー型アーキテクチャの場合、重要な懸念事項です。コードのlintツールにより、多くのコーディング・ガイドライン(クラスやメンバーのネーミングなど)に対処できますが、こういったツールはスコープが限られており、ルールがさらに複雑になった場合、部分的にしか使えなくなる可能性があります。その結果、複数のツールの組合せによってしか強制できないルールが出てくる可能性もあります(ときには、ツールを組み合わせても強制できないこともあります)。カスタム・テスト・スイートでさまざまなツールやAPI(Java Reflection APIやAspectJなど)、および追加言語(Groovyなど)を使用すると、初心者の場合は特に、結局のところ習得がいたずらに難しくなります。 対照的に、ArchUnitでは、特別なインフラストラクチャや新しい言語は一切必要ありません。ルールを検証するテストは、プレーンJavaで記述できます。ArchUnitでは、Javaバイトコードに変換された他の言語(Kotlinなど)のテスト・コードやアプリケーション・コードを扱うこともできます。ルールは任意の単体テスト・ツールで評価できますが、JUnit 4およびJUnit 5でテストを記述する場合の拡張サポートが存在します。 アーキテクチャが進化している場合、実装ルールも時間とともに進化します。組込みの自動実行テストを使用すると、組織は事前定義ルールからの逸脱があることを意識的に認めざるを得なくなります。後ほどレビューで偶然発見することや、決して発見できないことはなくなります。ArchUnitでは、逸脱の警告が可能です。 筆者の経験では、いったんArchUnitでルールを書き始めれば、次々とユースケースに気づきます。たとえば、サードパーティ製ライブラリの正しくない使用を避けることができ、「コードの臭い」のパターンと比較してテストすることにより、そういった兆候をプロジェクトから排除することもできます。ArchUnitのAPIによって創造性が刺激され、コード全体の品質を向上させるために行う、新しいチェックの発案や既存ルールの改善が容易になります。 さらに、ArchUnitライブラリには、一般的な事前定義ルールも用意されています。ライブラリにおいてすべての使用方法を予測するのは難しいため、拡張可能であることがなおさら重要です。拡張性を実現するため、ArchUnitではカスタム・チェックを記述する便利な方法を提供しています。具体的には、いくつかの事前定義された組合せ可能なビルディング・ブロックやインタフェースを使います。   内部動作 ArchUnitでは、リフレクションとJavaバイトコード分析を使用しています。Java Reflection APIから取得できない情報は、バイトコード・レベルで取得します。たとえば、Reflection APIでは、クラスへのアクセスまたはクラスからのアクセスについての情報を取得する方法は提供されていません。しかし、この情報はバイトコードに含まれています。つまり、2つのクラス間の依存性は、Javaバイトコード分析によってのみ取得できます。バイトコードを分析するために、ArchUnitライブラリではASMを使用します。ASMは、Javaバイトコードの読取り、書込み、操作を行う万能フレームワークです(詳しくは、本誌で以前特集したASMの記事をご覧ください)。 ASMを使用して、単体テストによく似ているものの、アーキテクチャ制約を対象にしたテストを記述することができます。たとえば、ArchUnitでアーキテクチャ・ルールを記述すると、次のようになります。 ArchRule rule = ArchRuleDefinition.classes() .that().resideInAPackage("..domain..") .should().onlyBeAccessed() .byAnyPackage("..domain..", "..application.."); 別の例を示します。 ArchRule rule = ArchRuleDefinition.methods() .that().arePublic() .and().areDeclaredInClassesThat().resideInAPackage("..adapters.primary.web..") .and().areDeclaredInClassesThat().haveSimpleNameEndingWith("Controller") .and().areDeclaredInClassesThat().areAnnotatedWith(Controller.class) .should().beAnnotatedWith(RequestMapping.class); ArchUnitは、3つの主要なAPIレイヤーに分かれています。Core、Lang、Libraryという3つのレイヤーですが、次のセクションではこの点について詳しく説明します。   使用の開始 ArchUnitライブラリは、Maven Centralから入手できます。まず、MavenまたはGradleで宣言を行い、依存性を取得する必要があります。その後は、Javaの任意の単体テスト・フレームワークを使用し、テストを記述して実行することができます。次に示すのは、Mavenユーザー向けのPOMエントリです。 <dependency> <groupId>com.tngtech.archunit</groupId> <artifactId>archunit</artifactId> <version>0.11.0</version> <scope>test</scope> </dependency> Gradleユーザー向けのPOMは次のようになります。 dependencies { testCompile 'com.tngtech.archunit:archunit:0.11.0' } ArchUnitでは、JUnit向けにArchUnitRunnerを提供しています。このランナーにより、コードの定型挿入文が減少します。また、複数のテストに使うクラスを毎回インポートしなくてもよいように、インポートしたクラスがURL別にキャッシュされます。JUnit 4でこのランナーを使う場合は、上記の依存性のarchunitアーティファクトをarchunit-junit4に置き換えます。JUnit 5では、archunit-junit5-apiおよびarchunit-junit5-engineアーティファクトを使用します。その他の情報は、インストール・ガイドに記載されています。 ArchUnitRunnerとJUnitを使う場合、ArchRulesは静的フィールド、または1つのJavaClasses引数を持つ静的メソッドのいずれかで定義できます。いずれの場合も、@ArchTestアノテーションを付加する必要があります。これにより、すでにインポートされてキャッシュされたクラスがランナーによって再利用され、ルールはキャッシュされたクラスを対象として評価されます。次に例を示します。 @RunWith(ArchUnitRunner.class) @AnalyzeClasses( packages = "com.company.app", importOptions = ImportOption.DoNotIncludeTests.class ) public class ArchitectureRulesTest { @ArchTest public static final ArchRule ruleAsStaticField = ArchRuleDefinition.classes() .should()... @ArchTest public static void ruleAsStaticMethod(JavaClasses classes) { ArchRuleDefinition.classes() .should()... } } JUnit 5では、ランナーを宣言する必要はありません。そのため、最初の行@RunWith(ArchUnitRunner.class)を削除できます。 前述のように、ArchUnitではチェックを単体テストとして記述します。その性質上、継続的インテグレーション(CI)パイプラインに特別な手順を導入する必要はありません。このテスト・スイートは、任意のCI環境やデプロイ・パイプラインに組み込むことができます。 既知のアーキテクチャ違反でテストが中断しないように、そういった違反を除外することができます。これを行うには、archunit_ignore_patterns.txtという名前のファイルをクラスパスのルート・ディレクトリに配置します。このファイルのそれぞれの行は正規表現と解釈され、報告された違反と照合されます。違反のメッセージがファイル内のパターンと一致した場合は、無視されます。1つのテストを無視するためには、テスト・クラスで@ArchIgnoreアノテーションを使います。バージョン0.11.0以降では、FreezingArchRuleという機能を使うこともできます。この機能は、ルールの違反が多すぎてすぐに修正できない場合に、現在の違反状態を保存するものです。とは言え一般論としては、テストを無視すべきではありません。ただし、これらのオプションを使うことで、アーキテクチャに関する既知の欠陥や侵害を含む、既存のソフトウェア・プロジェクトにArchUnitを組み込めるようになります。そうすれば、ルールを満たすことを目的として、修正やクリーンなアーキテクチャへの移行を繰り返すことができます。 また、異なるプロジェクト間で、共通のアーキテクチャ・ルールをコピーすることなく、簡単に共有して強制できるサードパーティ製Mavenプラグインもあります。   ArchUnitの中身 前述のように、ArchUnitは3つの主要APIであるCore、Lang、Libraryの各レイヤーに分かれています。 Core API:このレイヤーは、Reflection APIに似ています。さらに、バイトコードのインポート方法などの基本インフラストラクチャも扱います。コンパイル済みのJavaクラス・ファイルをインポートするためには、ClassFileImporterを使います。このインポーターでは、コンパイル済みのJavaクラスをインポートするさまざまな方法を提供しますが、もっとも便利な方法は、次に例を示すように、1つまたは複数のベース・パッケージを宣言することです。テスト・クラスやアーカイブ(JARなど)といった特定の場所を除外できます。 JavaClasses classes = new ClassFileImporter() .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS) .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_ARCHIVES) .importPackages("com.company.app"); インポーターから返されるのは、JavaClassesのインスタンスです。このインスタンスは、JavaClass型の要素のコレクションを表します。JavaClassは、1つのインポート済みクラス・ファイルを示します。 Coreのオブジェクトは、Reflection APIの同等のオブジェクトから命名されていますが、Javaというプリフィックスが追加されています。さらに、Core APIには代表的なクラスとして、JavaPackage、JavaMethod、JavaFieldなどもあります。以前にReflection APIを使ったことがある開発者なら、getName()、getMethods()、getRawType()、getRawParameterTypes()といったメソッドはおなじみでしょう。ArchUnitのCore APIにも、これらと同等のメソッドがあります。 追加のアクセス情報は、JavaMethodCall、JavaConstructorCall、JavaFieldAccessを使ってバイトコードから取得できます。たとえば、JavaClassインスタンスに対してgetAccessesFromSelf()を呼び出すことにより、インポート済みJavaクラスと、他の複数のインポート済みJavaクラスとの間でアクセスを反復させ、そのアクセスを分析することができます。同じようなアクセス・チェックは、getAccessesToSelf()、getFieldAccessesFromSelf()、getFieldAccessesToSelf()の各オブジェクト・メソッドで行うことができます。 Lang API:Coreのクラスだけを使ってアーキテクチャのテストを行うことは可能ですが、表現力に欠けることになります。これに対処するため、ArchUnitではLang APIで高レベルの抽象化を提供しています。このAPIでは、次の3つの中核コンポーネントで構成された、流れるようなインタフェースを提供します。 DescribedPredicate:関連クラスを選択する基準 ArchCondition:選択されたクラスが満たさなければならない条件 ArchRule:アーキテクチャのコンセプトを定義するルール Lang APIの大部分も同様に、流れるようなAPIとして構成されているため、IDEでは、使うAPIについての有益な提案を行うことができます。 クラスArchRuleDefinitionは、ArchRuleを定義するエントリ・ポイントとして使われます。先ほど触れた3つのAPIコンポーネントを使用して、提供されている選択基準および条件にとどまらず、ニーズを満たす独自のものを作成できます。 次の例では、ドメイン・クラスが他のドメイン・クラスまたはアプリケーション・クラスからのみアクセスされることを検証しています。 ArchRule rule = ArchRuleDefinition.classes() .that().resideInAPackage("..domain..") .should().onlyBeAccessed() .byAnyPackage("..domain..", "..application.."); ❝この構文は、AspectJのポイントカットの影響を受けています。❞ パッケージ表記法の「..」は、任意の数のパッケージを表します。この構文は、AspectJのポイントカットの影響を受けています。つまり、この例のArchRuleは、com.company.app.domain.modelなどのパッケージ内にある任意のクラスに適用されます(DescribedPredicate)。また、そのクラスがdomainパッケージまたはapplicationパッケージ内のクラス、あるいはそれらのパッケージのサブパッケージ内にあるクラスによってのみアクセスされることが検証されます(ArchCondition)。 ArchUnitルールのチェックに失敗した場合、ルールのテキストとすべての違反を内包するjava.lang.AssertionErrorが報告されます。この報告には、クラスと行番号も含まれています。 また、ArchRuleDefinition.noClasses()で始めることにより、クラス・ルールを否定することもできます。クラスだけでなく、コンストラクタ、メソッド、フィールド、メンバー、コード・ユニットを直接テストすることもでき、それぞれを否定する方法も存在します。 次に示すのは、Lang APIを使って長い記述をした例です。複雑なチェックがどのようなものになるかをご覧ください。この例はSpringフレームワークを対象としたもので、Springのモデル・ビュー・コントローラ(MVC)クラスのメソッドをチェックするために使用できます。 ArchRule rule = ArchRuleDefinition.methods() .that().arePublic() .and().areDeclaredInClassesThat() .resideInAPackage("..adapters.primary.web..") .and().areDeclaredInClassesThat() .haveSimpleNameEndingWith("Controller") .and().areDeclaredInClassesThat() .areAnnotatedWith(Controller.class) .or().areDeclaredInClassesThat() .areAnnotatedWith(RestController.class) .should().beAnnotatedWith(RequestMapping.class) .orShould().beAnnotatedWith(GetMapping.class) .orShould().beAnnotatedWith(PostMapping.class) .orShould().beAnnotatedWith(PatchMapping.class) .orShould().beAnnotatedWith(DeleteMapping.class); このルールでは、コントローラ内のパブリック・メソッドにSpring MVCのリクエスト・マッピング・アノテーションのいずれかが付加されていることを確認し、リクエストの処理に使われないパブリック・メソッドがコントローラに存在しないようにしています。選択されたクラスは、Controllerで終わる単純名を持ち、Spring MVCの@Controllerまたは@RestControllerアノテーションが付加され、..adapters.primary.web..パッケージまたはそのサブパッケージ内に存在しなければなりません。このようなルールにより、メソッド・レベルで強いコーディング規約を強制できます。 上記のようなルールを作成したら、そのルールをテスト結果に反映させるために、インポートしたJavaクラスに対してチェックを行う必要があります。 JavaClasses classes = new ClassFileImporter() ... ArchRule rule = ... rule.check(classes); Library API:このレイヤーには、さらに抽象化された複雑な事前定義ルールが含まれています。たとえば、ArchUnitでは、Architectures.LayeredArchitectureのインスタンスを使ってレイヤー型アーキテクチャの定義を作成し、個々のレイヤーに対してチェックを行うことができます。レイヤー型アーキテクチャは、レイヤー、名前、パッケージを規定することで簡単に定義できます。レイヤー型アーキテクチャとして表現できるポート・アダプタ・アーキテクチャの定義は、次のようなものになります。 Architectures.LayeredArchitecture portsAndAdaptersArchitecture = Architectures .layeredArchitecture() .layer("domain layer") .definedBy("com.company.app.domain..") .layer("application layer") .definedBy("com.company.app.application..") .layer("adapters layer") .definedBy("com.company.app.adapters.."); ここで、このアーキテクチャ定義を使用し、レイヤーに対してルールを定義することができます。ルールは、1つのテストに直接追加することも、次の例に示すように、個々のテストに保存されているインスタンス変数に追加することもできます。いずれの場合でも、whereLayerメソッドでレイヤー条件を追加します。 ArchRule applicationLayerRule = portsAndAdaptersArchitecture .whereLayer("application layer") .mayOnlyBeAccessedByLayers("adapters layer"); ArchUnitバージョン0.11.0では、Jeffrey Palermo氏が言うところのオニオン・アーキテクチャのセマンティックを検証するための新しい事前定義APIであるArchitectures.onionArchitecture()が追加されています。オニオン・アーキテクチャは、ポート・アダプタ・アーキテクチャに関連しています。このAPIも他と同じように使うことができますが、それぞれのアダプタを定義する必要があります。 Architectures.OnionArchitecture onionArchitecture = Architectures.onionArchitecture() .domainModels("com.company.app.domain.model..") .domainServices("com.company.app.domain.service..") .applicationServices("com.company.app.application..") .adapter("cli", "com.company.app.adapters.cli..") .adapter("web", "com.company.app.adapters.web.."); ArchUnitのLibrary APIには、スライスを扱うものがあります。スライスは、基本的にJavaクラスのサブセットのルール定義です。各サブセットは、パッケージの挿入辞のパターンに一致します。スライスの作成と、スライスに対するアサーションの実行には、SlicesRuleDefinitionを使用します。その結果、Slices APIのSliceRuleオブジェクトが生成されます。SlicesRuleDefinitionビルダーを使用してSliceRuleを作成し、循環依存を検出することができます。すなわち、スライス間に循環が発生していないことや、個々のスライスが相互に依存していないことを確認できます。たとえば、次のSliceRuleは推移的依存性の検出に役立ちます。 SliceRule layersShouldBeFreeOfCycles = SlicesRuleDefinition.slices() .matching("com.company.app.(*)..") .should().beFreeOfCycles(); SliceRule adaptersShouldNotDependOnEachOther = SlicesRuleDefinition.slices() .matching("com.company.app.adapters.(**)..") .should().notDependOnEachOther(); ここでも、照合の表記法はAspectJの構文の影響を受けたものになっています。最初のルールでは、appの1階層下位にあるパッケージのクラスを対象として、スライス間に循環が発生していないことを確認します。2つ目のルールでは、adaptersのすべてのサブパッケージ(たとえば、..adapters.primary.web..や..adapters.secondary.mongodb..)内にあるJavaクラスをグループ化し、それらすべてのスライス間の相互依存性をチェックします。   たとえば、Webコントローラ(プライマリ・アダプタ)からMongoDBリポジトリ(セカンダリ・アダプタ)に直接アクセスしている場合、ArchUnitでは次のエラーが生成されます。このエラーは、上記の2つ目のルールに対するものです。 java.lang.AssertionError:Architecture Violation [Priority:MEDIUM] - Rule 'slices matching 'com.company.app.adapters.(**)..' should not depend on each other' was violated (1 times): <strong>Slice primary.web calls Slice secondary.mongodb</strong> 先ほどの例でアスタリスクを1つだけ使ったとすれば、クラスはプライマリとセカンダリの2つのスライスにのみグループ化されたでしょう。エラー・メッセージにもそれが反映されることになります。 Library APIには、GeneralCodingRulesクラスも含まれています。このクラスには、多くのJavaプロジェクトで一般的に使われている静的コーディング・ルールが含まれ、いずれも自己記述的な名前で事前に定義されています。たとえば次のようなものです。 NO_CLASSES_SHOULD_ACCESS_STANDARD_STREAMS(クラスから標準ストリームへのアクセスを禁止します。標準ストリームとは、System.outやSystem.err、そしてprintStackTraceメソッドを指します。代わりにロギング・ライブラリを使います) NO_CLASSES_SHOULD_THROW_GENERIC_EXCEPTIONS(クラスから汎用例外をスローすることを禁止します。たとえば、RuntimeExceptionをスローする代わりに、IllegalArgumentExceptionのようなカスタム例外を使います) NO_CLASSES_SHOULD_USE_JAVA_UTIL_LOGGING(クラスでJavaユーティリティのロギングの使用を禁止します。SLF4JのバックエンドにLog4jやLogbackを使う場合に指定します)  NO_CLASSES_SHOULD_USE_JODATIME(クラスでJoda-Timeの使用を禁止します。最新のjava.time APIを使う場合に指定します)   テストを記述する際の留意事項 コードベースが大きい場合は、テストの際にクラス・ファイルのインポートをキャッシュすべきです。この手順により、テストの実行時間を大幅に削減できます。インポートしたクラスのキャッシュは、たとえばArchUnitRunnerで実現できます(JUnitサポートを使っている場合)。コードベースが小さい場合、クラスの再インポートによるオーバーヘッドは無視できます。 テスト対象のコンセプトは、可能な限り正確に記述された、ルールの要点を明確に伝えるものであることが重要です。複雑なルールの場合は、生成されるルール・テキストに依存するのではなく、明確でわかりやすいルール・テキストを使う方が理にかなっているでしょう。場合によっては、長いルール定義を、短くわかりやすい複数のルールに分割できることもあります。 また、実装されたルールに、何も考えずに従うべきではありません。同様に、あらかじめ考えることなく、簡単にテストを通過させるためにルールを変えるべきでもありません。ときには、新しいコンポーネントが既存のコンセプトに適合しないため、既存のルールの変更や拡張が必要になります。アーキテクチャが進化している場合、このようなことはよく起こります。しかし、前述のように、ArchUnitで提供されるテストを無視するオプションは、過剰に使用すべきではありません。未成熟なプロジェクトでは、特にそう言えます。   ArchUnitの代替プロダクトとその使用タイミング 言語レベルでは、Java 9で導入されたProject Jigsawのモジュール・システムが、意図せずにレイヤー間の依存性が発生することを防ぐために非常に役立ちます。モジュール依存性を明示的に指定するからです。残念ながら、この機能は既存のアプリケーションにはあまり役立ちません。Java 8以前を必要とする場合は、特にそうです。さらに、Jigsawで保証されるのはモジュール性とモジュール間の依存性だけです。これは品質の1つの側面でしかなく、ArchUnitで実行できるチェックです。 ArchUnitの代わりに使えるものに、jQAssistantがあります。このツールは、プロジェクトを分析し、生成された情報をNeo4jグラフ・データベースに格納するものです。jQAssistantではAsciiDocとの統合が提供されているため、テストをドキュメントに埋め込むことができます。ターゲット・アーキテクチャに移行しようとしている場合、これは実用的なツールです。商用プロダクトも存在します。その一例であるStructure101 Studioは、システムやアーキテクチャの監査に使われることが多い製品です。さらに、いくつかの静的コード解析ツールでは、ArchUnitで行うことの一部を実行できます。たとえば、DegraphやDeptectiveなどがあります。こういったツールの中には、ビルド環境や、場合によってはIDEに組み込めるものもあります。   まとめ ArchUnitは小さなライブラリですが、アプリケーションの規模を問わず、アーキテクチャや内部コードの品質の単体テストに使用できます。ArchUnitにより、短時間で容易かつ実践的に、コードの品質目標テストを始めることができます。ArchUnitによってビルド・プロセスの間に行われるテストで、Javaアプリケーションのアーキテクチャが、定義されたルールに準拠していることを確認できます。流れるようなAPIと細かく記述されたJavadocドキュメントに加え、公式ガイドでは、コードベースのチェックのためにArchUnitで提供されているさまざまなオプションについて説明されています。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する Arquillian:簡単なJakarta EEテスト 新しいJava Magazine 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Jonas Havers Jonas Havers(@JonasHavers):ドイツでフリーランスのフルスタック・ソフトウェア・エンジニアとソフトウェア・エンジニアリングの講師として活躍。主にeコマース関係のプロジェクトで、Java、Kotlin、Groovy、TypeScript、JavaScriptを組み合わせたWebアプリケーションを開発。リモート・ワークの支持者であるとともに、ブログで頻繁に発信している。

アーキテクチャの欠陥をビルド時に発見 著者:Jonas Havers 2019年8月20日 開発組織がよく直面する問題に、コードの実装がもともとの設計やアーキテクチャからたびたびずれてしまうことがあるというものがあります。この問題は、大規模なプロジェクトでは特にですが、よく起きるものであるため、コードの実装と最初に定義されたアーキテクチャとの整合性をテストする新しいツールが登場しています。ArchUni...

プロパティベース・テストを習得する

無数の値を使ってコードをテストする方法 著者:Johannes Link 2019年8月20日 JUnitなどのツールを使って単体テストを記述することは、コードの品質を確保するうえで欠かせない技術です。しかし、発生する可能性がある問題すべてを確認するために多くのテスト・ケースが必要となる関数の場合、テストは面倒でエラーが起こりやすくなります。その救世主となり得るのがプロパティベース・テスト(PBT)です。PBTにより、テスト・ケースを多数書く作業から解放されます。本記事では、PBTとは何か、JUnit 5プラットフォームでPBTを使用する方法、そしてどうすればサンプルベース・テストの拡張、場合によっては置き換えが可能かについて説明します。   サンプルベース・テスト 個々の測定値を受信(receive)し、それぞれの出現頻度を数えて集計するAggregatorクラスを扱っているとします。オブジェクトが意図どおりに動作するかどうかを確認するために、次の簡単なJUnit 5テストを使用できます。 import java.util.*; import org.junit.jupiter.api.*; class AggregatorTests { @Test void tallyOfSeveralValues() { Aggregator aggregator = new Aggregator(); aggregator.receive(1); aggregator.receive(2); aggregator.receive(3); aggregator.receive(2); Map<Integer, Integer> tally = aggregator.tally(); Assertions.assertEquals(1, (int) tally.get(1)); Assertions.assertEquals(2, (int) tally.get(2)); Assertions.assertEquals(3, (int) tally.get(1)); } } 多くの場合、この種のテストはサンプルベースと呼ばれます。具体的な入力例を使い、特定の状況において、生成された出力が意図した結果と一致しているかどうかを確認するからです。ほとんどの開発者は、何年あるいは何十年も似たようなテストを書いています。通常、一般的なプログラミング・エラーはそのようなテストでうまく検出できます。しかし、筆者の心の奥には、いつも1つの悩みの種がありました。Aggregatorが5つの測定値でも動作することは、どうすれば確認できるでしょうか。5,000個の要素がある場合や要素が何もない場合、負の値などもテストすべきなのでしょうか。虫の居どころが悪い日なら、自分のコードや同僚の開発者のコードに対する疑念が限りなく生じてきます。   プロパティ しかし、正確さに関するこの疑問には、別の角度から迫ることができます。どんな事前条件や制約(たとえば、入力パラメータの範囲)であれば、テスト対象の機能に対して特定の事後条件(計算結果)が得られるでしょうか。また、その過程で違反してはいけない不変量はどれでしょうか。 事前条件と、期待される特性の組合せを、プロパティと呼びます。 それでは、Aggregatorのいくつかのプロパティを簡単な日本語で表現してみます。 すべての測定値は、集計(tally)にキーとして出現する 測定されなかった値は、集計に出現しない 集計に出現した回数の合計は、受信した測定値の数と等しくなる 測定の順序によって集計結果が変わることはない 最初の文から3番目の文までは、いずれもかなり一般的な宣言です。最後の文が成立するためには、少なくとも2つの測定値が必要です。それぞれのプロパティは、要素リストが空でも、かなり長くても、その長さにかかわらず、任意の要素リストに適用できます。測定値は、Integer型の範囲全体に広がる可能性があり、重複することもあります。   プロパティ・テストの自動化 それでは、どうすれば自動テストにプロパティを使えるのでしょうか。宣言そのものは、コードに変換できそうです。最初のプロパティをJavaメソッドで表すのは簡単で、次のようになります。 boolean allMeasuredValuesShowUpAsKeys(List<Integer> measurements) { Aggregator aggregator = new Aggregator(); measurements.forEach(aggregator::receive); return measurements.stream() .allMatch(m -> aggregator.tally().containsKey(m)); } 実際に自動テストを行うために足りないのは、一連の入力リストを生成する方法と、メソッドにそのリストを提供する方法、そして条件がfalseを返したらすぐにテストを失敗させる方法です。これをすべて標準のJUnitにより行うこともできますが、専用の生成ロジックが多数必要になります。また、単純なケースは実現できますが、生成する値が複雑になり、ドメイン固有性が高まった場合、すぐに厄介になります。そこで、別のテスト・エンジンであるjqwikを使います。 jqwikを使う場合、先ほどのコードを実行可能なプロパティにするために必要となるのは、次の微調整だけです。 import java.util.*; import net.jqwik.api.*; class AggregatorProperties { @Property boolean allMeasuredValuesShowUpAsKeys( @ForAll List<Integer> measurements) { Aggregator aggregator = new Aggregator(); measurements.forEach(aggregator::receive); return measurements.stream() .allMatch(m -> aggregator.tally().containsKey(m)); } } このコードを詳しく見てみます。 プロパティは、コンテナ・クラスの中のメソッドです。メソッドには、わかりやすい名前をつけるべきです。すべての測定値がキーとして出現することを示すallMeasuredValuesShowUpAsKeysという名前では、プロパティの意図が適切に要約されています。 メソッドをプロパティ・メソッドとしてマークするためには、IDEやビルド・ツールでプロパティ・メソッドとして認識されるように、@Propertyアノテーションを付加する必要があります(IDEやビルド・ツールがJUnitプラットフォームをサポートしている場合)。 パラメータに@ForAllアノテーションを付加することで、フレームワークにインスタンスを生成させたいことをjqwikに伝えることができます。パラメータの型であるList<Integer>は、基本的な事前条件と見なされます。 プロパティの必要条件を伝えるもっとも簡単な形は、ブール値を返すことです。別の方法として、AssertJやJUnit 5自体などの任意のアサーション・ライブラリを使うことができます。 jqwikプロパティの実行が成功した場合、JUnitのテストが成功したときのように、何も起きません。他に指示を与えていない場合、jqwikでは異なる入力パラメータを使って各プロパティ・メソッドが1,000回ずつ実行されます。必要に応じて、この数はいくらでも多くすることも少なくすることもできます。   失敗するプロパティ 失敗するプロパティについて確認するために、リストの3番目にあるプロパティ(集計に含まれる、出現回数の合計は、受信した測定値の数と等しくなる)を取り上げます。 @Property boolean sumOfAllCountsIsNumberOfMeasurements( @ForAll List<Integer> measurements) { Aggregator aggregator = new Aggregator(); measurements.forEach(aggregator::receive); int sumOfAllCounts = aggregator.tally().values() .stream().mapToInt(i -> i).sum(); return sumOfAllCounts == measurements.size(); } 現在の集計関数にはバグが含まれているため、どの値も一度しかカウントされません。この場合、jqwikはそのバグを検知する例を見つけてくれるはずです。そして、そのとおりになります。次に出力を示します。 org.opentest4j.AssertionFailedError: Property [AggregatorProperties:sumOfAllCountsIsNumberOfMeasurements] falsified with sample [[0, 0]] |--------------------jqwik----------------- tries = 11 | # of calls to property checks = 11 | # of not rejected calls generation-mode = RANDOMIZED | parameters are randomly generated seed = -2353742209209314324 | random seed to reproduce generated values sample = [[0, 0]] originalSample = [[2068037359, -1987879098, 1588557220, -130517, ...]] かなり多くの情報が出力されました。テストの試行回数(tries)、実際にテストを実行した回数(checks)、乱数のシード(seed)、不成立のサンプル(sample)が表示されているのがわかります。また、場合によって役立つこともあるその他の情報も表示されています。 この例では、jqwikによって、重複した要素を持つリストが生成され、うまくバグが突き止めてられています。自分でサンプル・テストを書いた場合、このパターンを考えついたことも、考えつかなかったこともあるかもしれません。PBTライブラリを使うことで、追加のサンプルを考え出さなくとも、掘り下げたテストが実現しました。ただし、プロパティベース・テストで行われないことには注意する必要があります。このテストでは、プロパティが正しいことは証明できません。行われるのは、プロパティが成立しないサンプルを見つけようとすることだけです。   jqwikとJUnit 5の統合 jqwikはスタンドアロン・フレームワークではなく、JUnit 5にフックするテスト・エンジンです。JUnit 5は、テストを書いて実行する最新のアプローチを提供するだけでなく、実にさまざまなテスト・エンジン向けのプラットフォームとして設計されています。jqwikの設計上のメリットは、IDEやビルド・ツールに必要なのがJUnitプラットフォームとの統合だけで、個々のテスト・エンジンとの統合は必要ない点です。テスト・エンジンの開発者は、テスト仕様を検出して実行するパブリックAPIなどに悩む必要がないため、この点は大きなメリットになります。テスト・エンジンでは、自動的にIDEとビルド・ツールのサポートが継承されます。 さらに、JUnitプラットフォームでは、任意の数のエンジンを並行して使うこともできます。必要なのは、MavenやGradleの設定に依存性を1つ追加することだけです。Javaでもっとも多く使われている2つのIDEであるIntelliJとEclipseでは、現時点で十分にJUnit 5をサポートしています。GradleとMavenも同様です。   その他のjqwik機能 現在、jqwikには、プロパティベース・テストを実施する際に求められる必須機能がすべて搭載されています。たとえば、多くの標準の型をすぐに生成できます。Number、String、Character、Booleanの各型に加え、組込みのコンテナ型であるList、Set、Stream、Iterator、Optionalが認識されます。そのため、Set<List<String>>型のパラメータを使用でき、jqwikで自動的に文字列のリストのセットを生成してくれます。 プロパティ・メソッドのシグネチャでの値生成に直接的に影響を与えられるアノテーションが多数存在します。そこで、次のようにしてSet<List<String>>型を拡張します。  @ForAll @Size(3) Set<List< @CharRange(min='a', max='f') String>> aSetOfListsOfStrings この変更により、aからfまでの文字だけで構成される文字列のリストを含み、長さが3であるセットだけが生成されます。 値は、完全にランダムに生成されるわけではありません。空文字列、数値0、範囲の最大値および最小値といった、極端なケースや一般的な境界値が考慮されます。制約が十分に厳しければ、jqwikは可能な値の組合せすべてを網羅的に生成してくれます。   プログラムによる値生成 場合によっては、jqwikにデフォルトのジェネレータがないクラスを扱うこともあるでしょう。また、プリミティブタイプに関するドメイン固有の制約が特殊なため、既存のアノテーションでは不十分なこともあります。そういった場合は、パラメータ・ジェネレータの提供をテスト・コンテナ・クラスの別のメソッドに委譲できます。次に示すのは、プロバイダ・メソッドを使ってドイツの郵便番号を生成する方法の例です。 @Property @Report(Reporting.GENERATED) void letsGenerateZipis(@ForAll("germanZipi") String zipi) { } @Provide Arbitrary<String> germanZipi() { return Arbitraries.strings() .withCharRange('0', '9') .ofLength(5) .filter(z -> !z.startsWith("00")); } @ForAllアノテーションのStringの値は、同じクラス内にあるメソッド名を参照しています。このメソッドは、@Provideアノテーションが付加され、Arbitrary<T>型のオブジェクトを返すものとする必要があります。Tには、提供するパラメータの型を静的に記述します。 通常、パラメータ提供メソッドでは、最初にArbitrariesの静的メソッドを呼び出します。そしてほとんどの場合、その後に1つまたは複数のフィルタリング、マッピング、または組合せのアクションを行います。次のセクションでは、この点について説明します。 ❝ランダムな生成によって起きる問題の1つは、ランダムに選択された不成立のサンプルと、失敗するプロパティの背後にある問題との関係が多くのノイズによって埋もれることが多いという点にあります。❞ フィルタリング、マッピング、組合せ すべての値生成のベースタイプとして、Arbitraryクラスにはいくつかのデフォルト・メソッドがあり、それらのメソッドを使って生成動作を変更することができます。通常は、Arbitrariesクラスに存在する静的ジェネレータ関数のいずれかを最初に呼び出します。ほとんどのジェネレータ関数は、Arbitraryの特定のサブタイプを返します。このサブタイプにより、美しいインタフェースを通じて追加設定を行うことができます。 ここでは、1から300までの整数のうち、6の倍数である数を生成するものとします。以下に示すのは、これを実現する2つの方法です。 Arbitraries.integers() .between(1, 300) .filter(anInt -> anInt % 6 == 0) 次のように記述することもできます。 Arbitraries.integers().between(1, 50) .map(anInt -> anInt * 6) いずれの方法が優れているでしょうか。優劣がスタイルや可読性の問題にすぎない場合もありますが、それ以外の場合、選択する方法によってはパフォーマンスに影響を及ぼす可能性もあります。先ほどの2つの選択肢を比べた場合、与えられた仕様に近いのは前者であることがわかりますが、生成されたすべての値のうち6分の5がフィルタリングによって破棄されます。そのため、後者の方が効率的ですが、多少わかりにくくなっています。通常、プリミティブ値の生成は非常に高速であるため、効率性よりも可読性の方が重視されます。 多くの場合、実際のドメイン・オブジェクトには、ほとんど関連性のない別個の部分がいくつか存在します。たとえば、人を表すPersonには、姓と名が必要でしょう。 そのため、無関係のベース・ジェネレータを複数使用した後に、それらの生成結果を組み合わせるのがよいでしょう。次の例では、2つのArbitraryエンティティを組み合わせて1つにすることで、ドメイン・クラスPerson用のArbitraryを作成しています。 @Provide Arbitrary<Person> validPerson() { Arbitrary<String> firstName = Arbitraries.strings() .withCharRange('a', 'z') .ofMinLength(2).ofMaxLength(10) .map(this::capitalize); Arbitrary<String> lastName = Arbitraries.strings() .withCharRange('a', 'z') .ofMinLength(2).ofMaxLength(20); return Combinators .combine(firstName, lastName).as(Person::new); } このテクニックを使用して、8つまでのArbitraryエンティティを1つに組み合わせることができます。必要に応じて、独自のArbitraryエンティティを登録し、ドメインの型のパラメータすべてに自動的に適用されるようにすることもできます。   縮小の重要性 ランダムな生成によって起きる問題の1つは、ランダムに選択された不成立のサンプルと、失敗するプロパティの背後にある問題との関係が多くのノイズによって埋もれることが多いという点にあります。この懸念については、次に示す簡単な例で説明できます。 @Property(shrinking = ShrinkingMode.OFF) boolean rootOfSquareShouldBeOriginalValue( @Positive @ForAll int anInt ) { int square = anInt * anInt; return Math.sqrt(square) == anInt; } このプロパティは、2乗した値の平方根は元の値に等しくなければならないという自明な数学的概念を表しています。最初の行では、shrinkingアノテーション属性を使って縮小をオフにしています。このプロパティを実行すると、次のようなメッセージが表示されて失敗します。 originalSample = [1207764160], sample = [1207764160] org.opentest4j.AssertionFailedError: Property [rootOfSquareShouldBeOriginalValue] falsified with sample [1207764160] jqwikで見つかった、失敗するサンプルは無作為に選択したものです。この数値自体からは、失敗の原因に関する明確な手がかりは得られません。かなり大きい数だという事実も、偶然のことかもしれません。この時点で、ログを追加するか、デバッガを起動してこの問題に関する情報をさらに収集するかのいずれかを行うことになるでしょう。 ❝PBTは、関数、コンポーネント、プログラム全体に対して汎用的で望ましいプロパティを見つけることができるという考え方に基づいています。多くの場合、そういったプロパティは、ランダムに生成されたテスト・データでは成立しないでしょう。❞ それでは、別の方法をとり、ShrinkingMode.FULLを使って縮小をオンにしたうえでプロパティを再実行してみます。失敗するのは同じですが、見つかった不成立のsampleは変化していることがレポートからわかります。 sample = [46341] originalSample = [1207764160] 46,341という数はかなり小さく、元のサンプルとも違う数です。jqwikは、1,207,764,160で失敗した後も、同じように失敗する、より簡単なサンプルを探し続けます。この検索フェーズを縮小と呼びます。元のサンプルから始め、小さい数を探そうとするからです。 それでは、このケースで46,341が特殊な点は何でしょうか。皆さんの想像どおりかもしれませんが、46,341の2乗は2,147,488,281で、Integer.MAX_VALUEよりも少しだけ大きな値になります。そのため、整数のオーバーフローが発生します。つまり、前述のプロパティが成立するのは、Integer.MAX_VALUEの平方根までの整数のみです。 縮小は、PBTにおける重要なトピックです。縮小により、失敗したプロパティの分析の多くがはるかに簡単になるからです。また、PBTの不確定性も減らしてくれます。ただし、優れた縮小を実装するのは、複雑なタスクです。理論的に言えば、検索空間が非常に大きい場合があるという、検索問題に遭遇します。掘り下げた検索には時間がかかるため、縮小を効率的かつ高速に行うために多くの経験則を適用します。   プロパティ検出のパターン PBTの最初の一歩を踏み出すとき、適切なプロパティを探すのは難しいタスクだと感じるかもしれません。プロパティの代表的な例に比べれば、現実世界でのプロパティの特定には別の種類の考え方が要求されます。プロパティを探す際に参考になる一連の便利なパターンが役立つかもしれません。幸いにも、そのすべてを自力で探す必要はありません。PBTが誕生してからしばらく時間がたっているため、小さいながらもよく知られている、プロパティベース・テストのパターンのコレクションが存在します。筆者個人のリストは当然ながら未完のものですが、ここではいくつかの典型的なソースを挙げてみます。 プロパティとしてのビジネス・ルール:ドメイン仕様自体をプロパティとして解釈し、記述できる場合があります。たとえば、「年間取引高がXユーロより大きく、請求書の額がZユーロよりも大きいすべての顧客に対し、Y%の追加値引きを適用する」というビジネス・ルールを考えてみてください。これは、XとZに対してArbitrariesを使い、計算された値引率が実際にYであることを確認することで、そのままプロパティに変換できます。 逆関数:関数に逆関数がある場合、まずその関数を適用し、次に逆関数を適用すれば、元の入力が返されます。 べき等関数:べき等関数を複数回適用しても、結果は変わりません。たとえば、リストを2回並べ替えても、結果は変わりません。 不変関数:コードのプロパティには、ロジックを適用しても変わらないものがあります。たとえば、ソートやマッピングでは、コレクションのサイズは変わりません。また、リストから値をフィルタで除外しても、残った値の順序は元の順序と同じです。 交換可能性:一連の関数が交換可能である場合、関数を適用する順番を変えても最終的な結果は変わりません。たとえば、ソートしてからフィルタリングしても、フィルタリングしてからソートしても、同じ結果となります。 テスト・オラクル:テスト対象の関数の代替実装を知っている場合もあるでしょう。その場合は、テスト・オラクルとしてその実装を使うことができます。関数を使った結果はすべて、元の実装と代替実装で同じになるはずです。代替実装のサンプルをいくつか示します。 簡単で遅いものと複雑だが速いもの パラレルとシングルスレッド 自作と商用 古いもの(リファクタリング前)と新しいもの(リファクタリング後) 計算しにくいが検証しやすい:ロジックによっては、実行することは難しいが確認するのは簡単というものがあります。たとえば、素数を探す作業と、素数かどうかを確認する作業について考えてみてください。 帰納法(最初に小さな問題を解くこと):ドメイン・チェックを、ベース・ケースと、そのベース・ケースから導出された汎用的なルールに分割できるかもしれません。 ステートフル・テスト:特にオブジェクト指向の世界では、オブジェクトの動作を、有限の状態セットと、その状態を変化させるアクションがあるステート・マシンとして記述できることがよくあります。状態遷移空間の調査は、PBTの重要なユースケースです。そのため、jqwikはこれに対する特別なサポートを提供しています。 ファジング:予期しないさまざまな入力データを大量に投入しても、コードは決して誤動作すべきではありません。そのため、このパターンの主な考え方は、多種多様な入力を生成し、テスト対象の関数を実行して、以下のことを確認するというものです。 例外が発生しない。少なくとも、予期しない例外は発生しない。 HTTPリクエストに対してリターン・コード5xxが発生しない。さらに進んで、常に2xxステータスを要求する場合もある。 すべての戻り値が有効である。 ランタイムに適切なしきい値が設定されている。 ファジングは、既存のコードやシステムの堅牢性を詳細に調べる場合にさかのぼって行われることが多い手法です。 前述のパターンをコードに適用できるようになるためには、訓練が必要です。しかし、こういったパターンは、テスト記述者がスランプに打ち勝つための優れた開始点となるでしょう。自分のコードのプロパティについて考えれば考えるほど、サンプルベース・テストからプロパティベース・テストを導き出すチャンスを認識するようになります。プロパティベース・テストは、ときには補完的役割を果たし、ときには古いテストを置き換えるものとなります。   まとめ PBTは新しい技術ではなく、HaskellやErlangなどの言語では、10年超にわたって効果的に使われ続けています。PBTは、関数、コンポーネント、プログラム全体に対して汎用的で望ましいプロパティを見つけることができるという考え方に基づいています。多くの場合、そういったプロパティは、ランダムに生成されたテスト・データでは成立しないでしょう。 jqwikは、JVMベースのプロパティ・テスト・エンジンです。JUnit 5プラットフォーム用に構築されているため、あらゆる最新のIDEやビルド・ツールとの統合がシームレスです。(まだ)JUnit 5を使っていない方は、いくつかの代替ツールも利用できます。本記事は、PBTの表面をなぞったにすぎません。さらに深く知りたい方は、こちらのブログ・シリーズからご覧ください。 Java Magazine December 2019の他の記事 Arquillian:簡単なJakarta EEテスト ArchUnitでアーキテクチャの単体テストを行う 新しいJava Magazine 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Johannes Link Johannes Link(@johanneslink):およそ25年にわたってプロのソフトウェア開発者として活躍。2001年という早い時期からテスト駆動開発のとりこになり、その関連書籍も執筆している。初期のJUnit 5における中心的コミッターの1人で、jqwikのメイン開発者でもある。

無数の値を使ってコードをテストする方法 著者:Johannes Link 2019年8月20日 JUnitなどのツールを使って単体テストを記述することは、コードの品質を確保するうえで欠かせない技術です。しかし、発生する可能性がある問題すべてを確認するために多くのテスト・ケースが必要となる関数の場合、テストは面倒でエラーが起こりやすくなります。その救世主となり得るのがプロパティベース・テスト(PBT)です...

新しいJava Magazine

読み心地を改善し、投稿頻度を高めた新しいホームにようこそ 著者:Andrew Binstock 2019年8月27日 (※編集部注:本記事はオリジナル版のJava Magazineについての情報を翻訳したものです。Java Magazine 日本版は、Blog記事形式でお届けします。また、発行時期についても、現在のところ不定期となっておりますのでご了承ください。) いよいよ、長い間予告していたWebベースのJava Magazineが始動します。しばらく時間をかけて作業を行ってきましたが、この移行によっていくつかのメリットが生まれるため、きっと気に入っていただけるのではないかと思っています。 もっとも明らかな改善点は、記事がレスポンシブHTMLで表示されるようになったことです。PDFが読み込まれるのを待つことなく、オンラインで各記事を読むことができます。この新しい形式は、どんなサイズのモバイル機器にも適応します。さらに、クリックしてページを進めたり戻したりしなければならない複数ページの形式ではなく、スクロールできる1つのページとして記事が表示されます。 本誌は、ダウンロードできるPDFファイルとしては提供されなくなります。レスポンシブHTMLへの移行によって、ダウンロードできるPDF形式をあえて廃止しています。モバイル機器で記事を読む読者が増えるほど、PDFドキュメントの不便さが目立つようになってきました。説明をたどるためにページを行ったり来たりする必要がある、多くのコードが掲載された長い記事では特にそうです。 PDFは完全に廃止しますが、PDFのバックナンバーをダウンロードしたい方のために、2年分をAll Issuesタブから自由にダウンロードできるようにしています。 さらに、スケジュールを変更して月刊といたします。これまでの隔月の発行では、タイムリーな内容をお届けするのが非常に困難でした。新しいスケジュールによって、最新情報や耳よりなお知らせを今までよりも早く受け取れるようになります。このように書くのは、少しばかり不正確かもしれません。実際には、記事は1か月にわたって随時(通常はテーマごとに)公開されます。その後、公開した記事へのリンク、各記事をまとめるテーマ、その他の投稿済み記事を含むお知らせをお送りします。 要するに、コンテンツが増えて読み心地も改善されます。 このようなプロジェクトではとてもよくあることですが、私たちは皆さんのフィードバックを非常に頼りにしています。皆さんの思慮深いコメントや批判に応えて、細かい部分を調整し続ける予定です(もちろん、賛辞も大歓迎です)。 ぜひ、javamag_us@oracle.comにお送りください。これまでに意見をお寄せくださった方なら、私がすべてのコメントに目を通し、お答えしていることをご存じでしょう。 移行中はご不便をおかけしました。そして、新しいJava Magazineにようこそ。   Java Magazine December 2019の他の記事 プロパティベース・テストを習得する Arquillian:簡単なJakarta EEテスト ArchUnitでアーキテクチャの単体テストを行う 作ってみよう:自分だけのテキスト・エディタ(パート1) クイズに挑戦:Collectorsの使用(上級者向け) クイズに挑戦:ループ構造の比較(中級者向け) クイズに挑戦:スレッドとExecutor(上級者向け) クイズに挑戦:ラッパー・クラス(中級者向け) 書評:Core Java, 11th Ed. Volumes 1 and 2 Andrew Binstock Andrew Binstock(javamag_us@oracle.com、@platypusguy):Java Magazine編集長。Dr. Dobb's Journalの元編集長。オープンソースのiText PDFライブラリを扱う会社(2015年に他社によって買収)の共同創業者。16刷を経て、現在もロング・テールとして扱われている、Cでのアルゴリズム実装についての書籍を執筆。以前は UNIX Review で編集長を務め、その前には C Gazetteを創刊し編集長を務めた。妻とともにシリコン・バレーに住んでおり、コーディングや編集をしていないときは、ピアノを学んでいる。

読み心地を改善し、投稿頻度を高めた新しいホームにようこそ 著者:Andrew Binstock 2019年8月27日 (※編集部注:本記事はオリジナル版のJava Magazineについての情報を翻訳したものです。Java Magazine 日本版は、Blog記事形式でお届けします。また、発行時期についても、現在のところ不定期となっておりますのでご了承ください。) いよいよ、長い間予告していたWebベースの...

Java Magazine December 2019

※Java Magazineは本号よりWEB記事化されました。 2019年12月 プロパティベース・テストを習得する 著者:Johannes Link 無数の値を使ってコードをテストする方法   Arquillian:簡単なJakarta EEテスト 著者:Josh Juneau Arquillianフレームワークを使ってJakarta EEアプリケーションをテストする方法   ArchUnitでアーキテクチャの単体テストを行う 著者:Jonas Havers アーキテクチャの欠陥をビルド時に発見 新しいJava Magazine 著者:Andrew Binstock 読み心地を改善し、投稿頻度を高めた新しいホームにようこそ   作ってみよう:自分だけのテキスト・エディタ(パート1) 著者:Ian Darwin 新連載:階層化設計と反復型開発を使ってライン・エディタをテキスト・エディタに進化させる   クイズに挑戦:Collectorsの使用(上級者向け) 著者:Simon Roberts、Mikalai Zaikin Collectorsクラスから想定どおりの結果を得るために注意すべきこと   クイズに挑戦:ループ構造の比較(中級者向け) 著者:Simon Roberts、Mikalai Zaikin ユーザーの手動入力をループ処理する場合に使用するループ構造、そこには多くの微妙な違いが...   クイズに挑戦:スレッドとExecutor(上級者向け) 著者:Simon Roberts、Mikalai Zaikin ExecutorServiceを使って行う具体的な処理の詳細   クイズに挑戦:ラッパー・クラス(中級者向け) 著者:Simon Roberts、Mikalai Zaikin Integerラッパー・クラスを使って2つの整数のインスタンスを作成したときに、値を比較する正しい方法

※Java Magazineは本号よりWEB記事化されました。 2019年12月 プロパティベース・テストを習得する 著者:Johannes Link 無数の値を使ってコードをテストする方法   Arquillian:簡単なJakarta EEテスト 著者:Josh Juneau Arquillianフレームワークを使ってJakarta EEアプリケーションをテストする方法   ArchUnitでアーキテクチ...

もしもみなみんがDBをクラウドで動かしてみたら 第16回 サービス制限について

window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-159254751-1'); もしもみなみんがDBをクラウドで動かしてみたら 連載Indexページ ※本記事は2019/12/15時点のものになります みなさん、こんにちは。 先日、Oracle Cloud InfrastructureでもExadata X8の利用が可能になりました! Release Note  X8 Shapes for Exadata DB Systems Exadata Cloud Service(以降ExaCS)をはじめ、Databaseサービスを利用しようとしている方に「ExaCSのX8を利用したいんですが、すぐ作成可能ですか?」「作成しようとしたけれど、シェイプが選択できない/表示されないんです」「ExaCSやBare Metalなどを誤って作成してしまって高額請求が発生しまうようなことを防ぐ方法はありますか?」といったことをよく聞かれます。 これらに関係するのが、サービス制限というサービスごとの利用数の制限設定です。今回は、そのサービス制限について解説します。   サービス制限とは サービス制限は、利用者保護を目的としたサービスごとのリソース使用量の制限になります。たとえば、「サービスの単価を認識せずに作成したら、単価の高いサービスだった」「部門やプロジェクト全体での利用など、利用者多い状況で一度にサービスを利用したら、意図せず利用量/数が大きくなっていた」といった、利用者が意図せず高額な請求をう受け取ってしまうことがないように、すべての環境(テナンシ)にデフォルトでサービスごとに利用できるリソース数を制限しています。 そのため、制限数以上の数に達した状態で新たにサービスを追加しようとすると、エラーもしくは使用したいシェイプが選択できずに作成ができません。制限数以上の作成をしたい場合には、サービス制限の引上げをリクエストすることで増やすことができます。このように、デフォルトで制限数を設けておくことによって、意図せず大幅な利用(リソース的にも金額的にも)をすることを防ぐようにしています。代表的なサービスでいうと、ExaCSの場合は全シェイプでデフォルトは0に設定されています。そのため、サービス制限で制限されているリソース数を増やす、つまりサービス制限の引上げがまずは必要になります。その他のサービスも、現在利用しているサービス数がサービス制限数に達している状態で新たにリソースを使う場合には、同様です。 また、サービス制限とは別に、コンパートメントごとの割り当て設定も可能です。2つの違いは、サービス制限はテナント全体に対しての制限で、制限数の変更はオラクルが行います。一方コンパートメント割当の制限は、テナント管理者がそのテナント内のコンパートメントに対して、IAMポリシーを利用して設定します。なので、最初に必要なのはテナントのサービス制限を確認することです。 マニュアル OCI Document Service > Service Essentials > Service Limits  英語 / 日本語   サービス制限の確認方法 環境内のサービスごとのサービス制限の内容は、コンソールの『ガバナンス』 >『制限、割当ておよび使用状況』 から確認可能です。(この情報を見ることのことのできるユーザーは、管理者グループに属するか、アクセス権限(Tenancyのinspect limits)をIAMポリシーで設定する必要があります)   Tokyo Regionの場合 サービス制限 : 利用可能なリソース数 使用量 : 現在利用しているリソース数 使用可能 : 作成可能なリソース数 (=(1)-(2))  (3)が0の場合、サービスを作成しようとするとエラー、もしくは作成時に選択ができません。 その場合、サービス制限の引上げをリクエストして(1)の数を増やすようにしましょう! また、デフォルトの制限に関してはマニュアル(英語 / 日本語) から確認可能なので、クラウド・アカウントをアクティベーションしてすぐ使い始めたいという人は事前にマニュアルで確認してみてください。 この画面に関してよくある質問 質問「全リソースの制限が0になっているのですが、全てにサービス制限がかかってしまったのでしょうか」 → 全リソースの制限が0になっている場合、そのテナント自体が利用停止している状態を示します。その場合は、サービス制限の引上げリクエストではなく、テナントの利用について問い合わせてください。 質問 「サービスでDatabaseを選択したのに、Autonomous Databaseしか表示されていないように見えるのですが、一部のサービスしか表示されていないのはなぜですか」 → Autonomous Databaseのサービス情報しか出ていないのは、スコープでリージョンを選択されているためです。Database Cloud Service(Virtual Machine/Bare Metal/Exadata)を表示させたい場合は、スコープでアベイラビリティ・ドメイン(AD)を選択してください。これはサービスの属性に依るものです。Autonomous Databaseはリージョン・リソースで、Database Cloud Service(Virtual Machine/Bare Metal/Exadata)はADリソースになります。そのため、[スコープ]の選択リストでリージョンを選択するか、ADを選択するかで表示されるサービスが変わるようになっています。 Databaseサービスの中に絞ると、 ・リージョン(例:東京の場合はap-tokyo-1)を選択 : Autonomous Databaseのみ ・AD(例:AP-TOKYO-1-AD-1)を選択 : Database (Virtual Machine、Bare Metal、Exadata) が表示されます。   サービス制限の引上げ方法 サービス制限の確認画面にある、『サービス制限の引上げ』をクリックするとリクエストを入力する画面に移ります。   連絡先 (名前とメールアドレス) : リクエスト内容についての自動送信メール(通知)や、内容について確認が必要な場合はメール(英語)が来る可能性があります リソース制限の引上げ : サービス・カテゴリ、リソース、可用性ドメインごとの引上げ後の制限値 リクエストの理由 以上を記入したら、『リクエストの送信』をクリックして完了です。利用者保護を目的として内容が確認されたうえで承認されることから数日要する可能性があるので、あらかじめ利用し始めたいタイミングが決まっていれば、前もってリクエストしておくことをお勧めします。 この画面に関してよくある質問 質問「ExaCS X7のサービス制限を引き上げたのですが、新しくでたX8を利用できますか」 → サービス制限はサービスのシェイプなど種類毎に設定されているので、X8を利用したい場合にはX8のシェイプ名を指定してサービス制限の引上げをしてください。   まとめ Oracle Cloud Infrastructureでは高性能や専有型といった単価が比較的高めのサービスも多く、テナント内での利用リソース数/量が大きくなるような利用も想定していることから、エンタープライズ領域での利用も意識したこのような仕組みがあるのですね。たとえばExaCSの場合は、対象のテナントにおいて、Monthly Flexでサービス制限の引上げ対象のサービスの最低料金以上をご購入いただいているか、という点もリクエストの承認の際に見られています。これも、「後から高額な請求が発生しないように」という目的があります。そういったチェックをすることで、未然に料金周りのトラブルを防ぎ、安心してお使いいただけるようにしています。 「すぐにxxサービスを利用開始したい」「xx月xx日から利用開始したい」という場合には、まずはこのサービス制限の値を確認してください。そして事前に希望の数まで利用可能な状態にしておくことで、希望されるタイミングからすぐにご利用いただけばと思います。   関連リンク ・Oracle Cloud Infrastructure ドキュメント サービス制限 英語/日本語 もしもみなみんがDBをクラウドで動かしてみたら 連載Indexページ

もしもみなみんがDBをクラウドで動かしてみたら 連載Indexページ ※本記事は2019/12/15時点のものになります みなさん、こんにちは。 先日、Oracle Cloud InfrastructureでもExadata X8の利用が可能になりました!Release Note  X8 Shapes for Exadata DB Systems Exadata...

Oracle CloudとGhostで無料ブログを簡単開設

オラクルは9月に、Oracle Cloudの新しいプラン、「Always Free」を発表しました。これで開発者や学生は、Oracle Cloudを完全に無料で使ってみることができます。Oracle Cloudを支持する開発者かつエバンジェリストである私は、このプランの熱烈なファンです。というのも、私は当社のクラウド・プラットフォームに全幅の信頼を寄せており、多くの開発者がOracle Cloudを体験するチャンスを手にすれば、その使いやすさを体感し、自社のクラウドへのニーズを満たすために間違いなくOracle Cloudを選択するであろうことを知っているからです。私はこのところ、新しい無料プランの使い道をいくつか紹介してきました。この記事を読んだ後は、私の他の記事もチェックして、無料プランをすぐに使ってみてください! Blast Off To The Cloud: Free Team Chat With Rocket.Chat In The Oracle Cloud Install & Run Discourse For Free In The Oracle Cloud Installing Node-RED In An Always Free VM On Oracle Cloud How To Setup And Run A Free Minecraft Server In The Cloud 本日の記事では、"Always Free" VMを1つ作成し、インターネット・アクセスができるように構成し、Docker(コンテナ管理用)、Ghost(Node.JSで記述された無料のブログ/CMSプラットフォーム。オープン・ソース)、Caddy Serverをインストールして、リバース・プロキシとして動作させ、TLS証明書を自動で管理し、新しいブログでHTTPS暗号化を使用できるようにします。複雑な手順はありません。この後のチュートリアルに従えば、15分であなたのブログもオンラインになるでしょう。 この後の手順は以下のようになっています。VMの作成方法をご存じの場合や、すでに作成している場合は、必要に応じて手順を飛ばしてください。 Always Free VMの作成 Ghostをインストールする前に Dockerのインストール Ghostのインストール Caddyのインストール Ghostの構成 Always Free VMの作成 Oracle Cloudを初めて使う場合は、まず完全無料のアカウントにサインアップします。クレジット・カードを登録する必要がありますが、「Always Free」サービスを使い続けている限り、料金を請求されることは絶対にありません。無料アカウントを作成したらログインして、Oracle Cloudダッシュボードを開きます。このような画面です。 さあ、VMを作成しましょう。「Create a VM instance」をクリックしてください。 インスタンスに名前を付け、必要に応じてイメージ・ソースを変更します。この後のインストラクションはデフォルトOS(Oracle Linux)用です。デフォルトのままにしておくのがいいかもしれません。 必要に応じて、「Show Shape, Network, Storage Options」をクリックし、可用性ドメインとインスタンス・タイプの両方が'Always Free Eligible'であることを確認してください。 インスタンスのシェイプも同じです。「Always Free Eligible」オプションを選択してください。 「Assign a public IP address」にチェックを入れておかないと、Webを通してVMにアクセスできません。 次に、公開鍵ファイルを選択します。このファイルには関連付けられた秘密鍵があり、VMの作成後、VMへのアクセスに使用されます。 「Create」をクリックすると、インスタンスの詳細ページに移動します。VMのステータスは'Provisioning'になっています。 少し待つと、インスタンスは'Available'になります。VMに割り当てられているパブリックIPアドレスをコピーします。このアドレスは、チュートリアルを進めていくなかで必要になります。 これでVMの準備ができました。VMの作成時にアップロードした公開鍵に関連付けられている秘密鍵を使用して、マシンにSSH接続します。 Ghostをインストールする前に Ghostをインストールする前に、いくつかの確認事項があります。この手順を省略すると、インストールできません。 ドメイン名レコード・セット まずは、VMのパブリックIPアドレスを、ドメイン名に関連付けます。Caddyでリバース・プロキシを作成し、無料でそのまま使用できるHTTPSを取得します。これはLet’s Encryptを使用して、通信用のSSLを自動で保護してくれます。私の場合は、ghost.toddrsharp.comというURLを使用するため、AレコードをDNSホストで追加し、私のVMのIPアドレスを指定します。 ドメイン(またはサブドメイン)にVMのIPアドレスを指定するには、ご使用のホスティング・プロバイダの指示に従ってください。これで、VMにSSH接続し、先に進む準備ができました。 ファイアウォールとセキュリティ・リストの構成 ファイアウォールとセキュリティ・リストでいくつかのポートを開いて、GhostアプリケーションをWebに公開する必要があります。まず、Oracle Cloudのダッシュボードで、VMのセキュリティ・リストに受信ルールを追加します。VMの詳細ページで、サブネットをクリックします。 サブネットの詳細ページで、「Security Lists」をクリックします。 デフォルトのセキュリティ・リストをクリックして、ルールを編集します。 「Add Ingress Rule」をクリックし、 'Source CIDR' 0.0.0.0/0(すべてのIPアドレス)にポート80,443を開くルールを入力します。 Dockerのインストール ここで、インスタンスにSSH接続し、インストール・プロセスを開始します。接続したら、sudo yum update -yを実行して、すべてを最新の状態にします。次に、Dockerをインストールします。   yum-config-manager --enable ol7_addons   yum install docker-engine       systemctl start docker     systemctl enable docker   view raw install-docker.sh hosted with ❤ by GitHub   次の手順に進む前に、以下のようにして、root以外のユーザーがDockerコマンドを実行できるようにします。   groupadd docker   service docker restart   usermod -a -G docker opc view raw enable-non-root.sh hosted with ❤ by GitHub   重要:opcユーザーがsudoを使わずにDockerコマンドを実行できるようにするには、ログアウトしてからログインし直す必要があります。 必要であれば、こちらを実行してDockerインストールを確認できます。 docker run hello-world Ghostのインストール VMにディレクトリを作成します。これは、ブログ関係の構成を保存したり、コンテナ・データの永続保存用にDockerコンテナにマッピングしたりするのに使用します。 mkdir /home/opc/ghost これでGhostをインストールできます。以下のコマンドを実行するだけです。   docker run -d \     --restart always \     --name ghost-blog \     -v /home/opc/ghost/content:/var/lib/ghost/content:z \     -p 2368:2368 \     -e url=https://ghost.toddrsharp.com \     ghost view raw install-ghost.sh hosted with ❤ by GitHub   ここでは、さまざまな引数を使ってdocker runを呼び出し、Docker Hubからghostイメージを実行しています(必要に応じて、run コマンドは実行前にイメージをpullします)。--restart alwaysを使うと、コンテナの終了時、またはDockerの再起動時(VMのリブートを含む)に、コンテナが毎回再起動するため、自分でサービスを作成する必要がありません。もちろんサービスを作成することもできますが、このアプリケーションではこのフラグがうまく機能します。コンテナの自動での起動について詳しく知りたい場合は、Dockerのドキュメントを参照してください。ここでは、VMの/home/opc/ghost/contentドライブを、Dockerコンテナの/var/lib/ghost/contentにマッピングしています。これで、コンテナが再起動しても、コンテンツとコンテナのSQLiteデータベースは保持されます。また、Ghostが実行されるポートであるポート2368を公開しています。コンテナがpullされて実行されたら、Caddyをインストールできます。途中でうまくいかなくなった場合、またはGhost Dockerコンテナの実行で問題が発生した場合は、Docker Hubのドキュメントを参照してください。 Caddyのインストール 先に進む前に、VMのポート80と443で、ファイアウォール・ポートを開く必要があります。以下のようにします。   sudo firewall-cmd --permanent --zone=public --add-port=80/tcp   sudo firewall-cmd --permanent --zone=public --add-port=443/tcp   sudo firewall-cmd —reload view raw firewall.sh hosted with ❤ by GitHub   Caddyをインストールするには、再びDockerを使用します。今回も1つのコマンドで完了します。ただし、そのコマンドを実行する前に、/home/opc/ghost/CaddyfileでCaddyの構成ファイルを作成し、vimまたはnanoで編集します。このように編集して、URLを、先ほどVMに指定したドメイン名に変更します。   https://your.domain.com {       proxy / ghost-blog:2368 {           transparent       }   } view raw Caddyfile hosted with ❤ by GitHub   このファイルによって、Caddyはドメインのリバース・プロキシとして動作し、すべてのトラフィックをhttp://ghost-blog:2368にリダイレクトします。さあ、Caddyを実行してみましょう。   docker run -d \     --restart always      --link ghost-blog:ghost-blog \     --name caddy \     -p 80:80 \     -p 443:443 \     -v /home/opc/ghost/Caddyfile:/etc/Caddyfile:z \     -v /home/opc/.caddy:/root/.caddy:z \     abiosoft/caddy view raw install-caddy.sh hosted with ❤ by GitHub   --linkフラグを使用して、Ghostコンテナに接続し、2つのコンテナ間でセキュアなトンネルを作成して、/etc/hostsファイルにエントリを追加し、ghost-blogをGhostコンテナのIPにマッピングします。VMボリュームをマウントしてCaddyfileを渡し、/home/opc/.caddyをマウントします。これで、CaddyがVMにTLS証明書を格納できるようになり、イメージが起動するたびに新しい証明書が生成されることがなくなります。このコマンドを実行すると、正しいTLS証明書が使われて、ドメインでブログが有効になります! Ghostの構成 構成したドメインでブログにアクセスし、URLの末尾に/ghostを追加して管理セクションにアクセスし、アカウントを作成し、構成を完了します。 アカウントを作成してログインすると、ブログをカスタマイズして、コンテンツを作成できるようになります!私のブログhttps://ghost.toddrsharp.comをご覧いただき、ご自分のブログではGhostを使ってどんなことができるか、参考にしてみてください。 Photo by Ante Hamersmit on Unsplash   ※本記事は、Todd Sharp (Developer Advocate)による”Stand Up A Free Blog In 15 Minutes With Ghost In The Oracle Cloud“を翻訳したものです。   AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

オラクルは9月に、Oracle Cloudの新しいプラン、「Always Free」を発表しました。これで開発者や学生は、Oracle Cloudを完全に無料で使ってみることができます。Oracle Cloudを支持する開発者かつエバンジェリストである私は、このプランの熱烈なファンです。というのも、私は当社のクラウド・プラットフォームに全幅の信頼を寄せており、多くの開発者がOracle Cloudを...

データの安全性を維持する - パート(4): クラウド・データベースの監査

寄稿者:Database Security、Senior Director、Ashok Swaminathan  Oracleデータベースは一般的には、きわめて機密性の高い情報が含まれる重要な資産となっています。そのため、データベースのアクティビティを定期的に監視して、データベース・アカウントが侵害されていないこと、および権限付きユーザーがアクセスしてはならないデータにアクセスしていないことを確認し、重要なデータにアクセスしようとする悪意のある操作を突き止め、調査する必要があります。この記事では、これらの問題への対処が可能となる、Data Safeの監査機能に焦点を当てて説明します。    Data Safe Activity Auditingを利用すれば、Oracle Cloudのデータベース上のユーザー・アクティビティを監視し、(業界や規制によるコンプライアンス要件に従って)監査レコードを収集、保持して、異常なアクティビティについてアラートをトリガーすることができます。機密データの変更、管理者やユーザーのアクティビティや、その他Center for Internet Security(CIS:米国インターネット・セキュリティー・センター)によって推奨されているアクティビティについて監査できます。データベース・パラメータや監査ポリシーが変更されたとき、管理者によるログインが失敗したとき、ユーザーのエンタイトルメントが変更されたとき、あるいはユーザーが作成または削除されたときのアラートを設定できます。Oracle Databaseには事前定義ポリシーが多数用意されており、そのいずれもData Safeで数回クリックするだけで有効化できます。  Data Safeダッシュボード(図1)ではアクティビティの傾向をすぐに確認できますが、ここにアラートの情報も含まれています。 このダッシュボードから、監査証跡(監査データを探すべきデータベース内の場所をData Safeに指定するもの)のステータスのチェックや、全体的な監査アクティビティの確認も可能です。 図1:Data Safe User Activity Auditingダッシュボード Data SafeのActivity Auditingの設定は、簡単な3つの手順で実行できます。  1.    監査するターゲットの選択 2.    収集する監査情報を示した監査ポリシーのプロビジョニング 3.    監査情報をどこから収集するかをData Safeに指定するための監査証跡の作成  この設定の完了後、Data Safeにより自動的に監査データが収集され、そのデータがセキュアなData Safeリポジトリに保存されます(このリポジトリは削除や変更ができないように、監査対象のデータベースとは分離されています)。Data Safe Activity Auditingでは、事前定義アラートに基づいて重要なイベントに関するアラートを設定できます。インタラクティブなレポートで監査データを確認し、必要に応じてフィルタを適用できます。また、セキュリティやコンプライアンスのニーズに合わせて、レポートを計画的に作成できます。  数種類のアクティビティ監査レポートが用意されています(図2)。たとえば、収集されたイベントやアラートのサマリー、監査対象のすべてのアクティビティ、監査ポリシーの変更、管理者のアクティビティ、ログイン・アクティビティ、データベース問合せ操作、DDL、DML、ユーザーおよびエンタイトルメントの変更に関するレポートがあります。生成されたアラートの表示、アラートへのフィルタの適用、アラートの検索も可能です。アラート・レポート、監査データ・レポートのいずれもカスタマイズして保存でき、PDF形式やXLS形式でダウンロードすることもできます。 図2:Admin Activityレポート Data Safeの監査機能は使いやすく、数回のクリックで有効化できます。Oracle Cloudでデータベースを運用していて、まだData Safeを利用されていない方には、このサービスを構成してデータベースの監査を最優先で行うことをお勧めします。 Data Safeはお使いのデータベース・サービスに含まれており、追加費用はかかりません。データをクラウド内で保護するための最高のツールの1つとなります。 Data Safeがユーザーやデータをクラウド内で保護する方法についての詳細情報は、このブログの以前の記事であるData Safe:Five Ways to Help Protect Your Digital AssetsおよびData SafeのWebページをご覧ください。   本記事は、Phil March (SR. Principal Product Marketing Director) による”Keeping your Data Safe Part 4 — Auditing your Cloud Databases“を翻訳したものです。   AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

寄稿者:Database Security、Senior Director、Ashok Swaminathan  Oracleデータベースは一般的には、きわめて機密性の高い情報が含まれる重要な資産となっています。そのため、データベースのアクティビティを定期的に監視して、データベース・アカウントが侵害されていないこと、および権限付きユーザーがアクセスしてはならないデータにアクセスしていないことを確認し、...

Oracle Cloud Notifications サービスを使ってみよう

クラウドの好きな機能をリストとしてまとめると、多くの開発者の"トップ10"リストに通知が入っていることはおそらくないでしょう。通知はどちらかというと"ユーティリティ"機能で、自動車のタイヤのようなもの。必要不可欠で、動かなければイライラさせられますが、順調に動いていれば考えることもほぼありません。 かつて私は通知をこのように捉えていましたが、最近になってオラクルのサービスOracle Notification Serviceを掘り下げるようになってからは変わりました。不思議なことに、このサービスについて学び色々と試すことにワクワクしている自分がいました。Oracle Notification Serviceは、Oracle Cloudの他のサービスと同じく、本当に使いやすく、分かりやすいように実装されています。また、Oracle Cloudの他のサービスだけでなく、外部のツールやサービスとも非常にスムーズに連携します。  ここでは、そんなOracle Notification Serviceについて詳しく見ていきます。 通知は広い概念を含む言葉であるため、その意味を明確にしましょう。アプリケーションで何かが起きたときに、ユーザーに電子メールを送信することがあります。たとえば、ファイルや注文の処理が終わったときに。 これが通知となる可能性があります。また、開発者やDevOpsエンジニアであれば、インフラストラクチャ内で何か変更があったときに、そのことを知りたいと思うのではないでしょうか。たとえば、DBのバックアップが開始した、完了したなど。 これも通知となる可能性があります。ユーザーや開発者が関わらない通知もあります。あるサーバーレス・ファンクションがあって、オブジェクトがObject Storageにアップロードされたときにこのファンクションを実行する必要がある場合に、その操作を通知によって処理できるのです。このように多種多様なアクティビティが"通知"という総称で表されますが、Oracle Notification Serviceは思い付く限りのすべてのシナリオに対処できます。  この記事で取り上げる内容は次のとおりです。 通知トピックの作成 トピックへのサブスクライブ 通知を受信するSlackアプリの作成 Oracle Cloud Infrastructure Java SDKによる通知の送信 Cloudのイベント経由での通知の自動送信 サービス・アラーム経由での通知の自動送信 Zapierによる通知からのGitHubイシューの自動作成 話題は盛りだくさんですので、すぐに1つ目に移りましょう! 通知トピックの作成 通知を使い始めるには、まずトピックを作成する必要があります。Oracle Cloudコンソールから、「Application Integration」→「Notifications」を選択します。 次に、「Create Topic」をクリックします。 トピック名と説明を入力して、「Create Topic」をクリックします。 これで、トピックのサブスクリプションのための準備が整いました。 トピックへのサブスクライブ 通知のサブスクリプションのために利用できるプロトコルはいくつかあります。 電子メール PagerDuty HTTPS(カスタムURL) Slack ヒント:この記事ではサブスクリプションとしての電子メールについては説明しませんが、電子メールのサブスクリプションを利用すれば、携帯電話の"非公開の組込み"電子メール・アドレスを使ってSMS通知を受け取ることができます。 ほとんどの通信会社でこの機能がサポートされています。便利な機能ですので、ぜひ試してみてください。 このブログ記事では、これらのプロトコルの一部について見ていきます。まずはSlackです。最初に、新しく作成したトピックをトピック・リストから選択します。 「Create Subscription」を作成します。 プロトコルとして「Slack」を選択します。このSlackサブスクリプションにはWebフックURLが必要になるため、このウィンドウを開いたままこのブログ記事の次のセクションに移り、新しいSlackアプリケーションを作成してWebフックURLを取得してください。 通知を受信するSlackアプリの作成 通知をSlackチャネルにパブリッシュするには、Slackアプリケーションを作成する必要があります。 まず、Slackを開いて「Create an App」をクリックし、アプリの名前を指定し、アプリを作成するワークスペースを選択して、「Create App」をクリックします。  次に、「Incoming Webhooks」をクリックします。 Webフックはデフォルトで無効であるため、有効にします。 「Add New Webhook to Workspace」をクリックします。 ワークスペースにアクセスするための権限を確認し、ポスト先のチャネルを選択して、「Allow」をクリックします。 これで新しく作成したWebフックURLを取得できます。このURLは少し後の手順で必要になります。 通知のポスト先のSlackチャネルを開き、歯車アイコンのメニューから「Add an app」をクリックします。 または、チャネル内で直接「Add an app」をクリックします。 新しいアプリを検索し、選択します。 チャネル内で確認メッセージが表示されます。 コンソールに戻り、Slack WebフックURLを貼り付けてサブスクリプション・ダイアログの入力を完了します。  この時点で、サブスクリプション確認用メッセージがこのSlackチャネルにポストされます。 このメッセージ内のリンクをクリックして、サブスクリプションを確認します。 次に、このSlackサブスクリプションをテストします。Oracle Cloudコンソールのトピック詳細ページに戻り、「Publish Message」をクリックします。 簡単なメッセージを入力し、「Publish」をクリックします。 Slackチャネルを開き、そのメッセージがポストされたことを確認します。 これで、Oracle Notification ServiceのトピックにサブスクライブできるSlackアプリの作成が完了しました。 Oracle Cloud Infrastructure Java SDKによる通知の送信 この記事ではすでに、かなり多くのことを学びました。通知トピックを設定し、そのトピックにサブスクライブし、トピックから通知を受信するためのカスタムのSlackアプリを作成し、簡単なテスト・メッセージをパブリッシュしました。しかし、すでに説明したように、アプリケーションからトピックやサブスクライバに通知を送信する必要があることも多いため、ここではトピックにメッセージをパブリッシュする小さなJavaアプリケーションについて見ていきます。トピック詳細ページからトピックのOCIDを取得する必要があります。このOCIDをコピーして、いつでも使える状態にします。 このデモの実行に必要なコード全体をGitHubで公開していますので、後でご自由にこのリポジトリを確認してください。 私はGradleが好きなので、まずはbuild.gradleファイルを作成して、Oracle Cloud Infrastructure Java SDKを依存先として含めます。 plugins {     id 'java'     id 'application' } group 'codes.recursive' version '0.1-SNAPSHOT' sourceCompatibility = 1.8 repositories {     mavenCentral() } application {     mainClassName = 'codes.recursive.OnsSendExample' } dependencies {     compile group: 'com.oracle.oci.sdk', name: 'oci-java-sdk-full', version:'1.9.0'     testCompile group: 'junit', name: 'junit', version:'4.12' } tasks.withType(JavaExec) {     systemProperties System.properties } view raw build.gradle hosted with ❤ by GitHub IDEでRun/Debugプロファイルを作成し、Oracle Notification ServiceのトピックOCIDを環境変数として設定します。 Ons.javaというクラスを作成します。このクラスを、SDKクライアントを呼び出してメッセージをパブリッシュするために利用します。このクラスには、引数としてtitleとmessageを受け取るsendNotfication()というメソッドが1つ含まれます。認証プロバイダを作成し、利用するプロファイルの名前を渡します(この例ではパスを指定していないため、デフォルトのOracle Cloud Infrastructure設定ファイルの場所[/.oci/config]が設定ファイル自体として利用されます)。次に、NotificationDataPlaneClientとMessageDetailsオブジェクトを作成します。このオブジェクトにタイトル(title)とメッセージ(message)が格納されます。  その後、MessageDetailsインスタンスを格納したPublishMessageRequestを作成し、最後にクライアント(client)にPublishMessageRequestを渡すことでメッセージをパブリッシュします。 この説明からは面倒で複雑だと感じられるかもしれませんが、以下のコードを見れば簡単だとお分かりいただけるはずです。 package codes.recursive; import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider; import com.oracle.bmc.ons.NotificationDataPlaneClient; import com.oracle.bmc.ons.model.MessageDetails; import com.oracle.bmc.ons.requests.PublishMessageRequest; public class Ons {     public void sendNotification(String title, String message) throws Exception {         String topicId = System.getenv("TOPIC_ID");         if( topicId == null ) {             throw new Exception("Please set a TOPIC_ID environment variable!");         }         ConfigFileAuthenticationDetailsProvider provider =  new ConfigFileAuthenticationDetailsProvider("DEFAULT");         NotificationDataPlaneClient client = NotificationDataPlaneClient.builder().region("us-phoenix-1")                 .build(provider);         MessageDetails messageDetails = MessageDetails.builder().title(title).body(message).build();         PublishMessageRequest publishMessageRequest = PublishMessageRequest.builder()                 .messageDetails( messageDetails )                 .topicId(topicId)                 .build();         client.publishMessage( publishMessageRequest );     } } view raw Ons.java hosted with ❤ by GitHub 次に、OnsSendExample.javaという必要最小限のメイン・クラスを作成し、このクラス内でOnsクラスのインスタンスを作成して通知を送信します。 package codes.recursive; import java.util.Date; public class OnsSendExample {     public static void main(String... args) throws Exception {         Ons ons = new Ons();         ons.sendNotification(                 "Test from Java",                 "This is a test notification sent by the Java SDK at " + new Date().toString()         );     } } view raw OnsSendExample.java hosted with ❤ by GitHub Slackチャネルをチェックして、配信されたことを確認できます。 Cloudのイベント経由での通知の自動送信 Cloudのイベントについては以前にこのブログで取り上げましたが、当時の背景情報は異なりますし、学び直すことは良いことですので、Cloudのイベント経由での通知の送信についても詳しく見ていきましょう。 そもそも、Cloudのイベントとはどういったものでしょうか。 多くのサービスはOracle Cloudで発行されるイベントであり、それらのイベントはCNCF Cloud Event仕様に従って構造化されたメッセージです。作成、読取り、更新、または削除(CRUD)の操作、リソースのライフサイクルの状態変更、あるいはリソースに影響を及ぼすシステム・イベントなどがイベントに該当します。  たとえば、バックアップの完了時または失敗時、あるいは Object Storage バケット内のファイルの追加時、更新時、または削除時にイベントが発行されます。 以下のように、Cloudのイベントを生成するさまざまなOCIサービスが存在します。 ブロック・ボリューム コンピュート データベース ネットワーク 通知 Object Storage サービスごとに使いやすいイベント・タイプが多数用意されているため、インフラストラクチャを監視するための大きな助けになります。例として、自律型データベースのイベント・タイプを見てみましょう。 バックアップ作成開始(Create Backup Begin) バックアップ作成終了(Create Backup End) インスタンス作成開始(Create Instance Begin) インスタンス作成終了(Create Instance End) リストア開始(Restore Begin) リストア終了(Restore End) さらに、ブロードキャストされるイベント・タイプ一式が存在するのは自律型データベースだけではありません。以下のように、Oracle Cloudのありとあらゆるデータベース関連要素にそれ独自のイベント・タイプが用意されています。 自律型データベース 自律型コンテナ・データベース 自律型Exadataインフラストラクチャ・インスタンス Exadataインフラストラクチャ VMクラスタ・ネットワーク VMクラスタ バックアップ先 データベース・ノード データベース・ホーム データベース Cloudのイベントを利用するには、ルールを作成します。ルールには、ルールがトリガーされる基になる特定のリソースや属性を指定するためのフィルタを含めることができます。さらに、ルールの条件が満たされたときに実行すべきアクションも作成します。 現時点では、ファンクション(Oracle Functionのサーバーレス・ファンクションを呼び出す)、ストリーミング(Oracle Streaming Serviceのストリームに対するメッセージを生成する)、通知(Oracle Notification Serviceトピックにイベントをパブリッシュする)の3つのタイプのアクションから選択できます。この3つ目のアクションについて、これから説明していきます。それでは、ルールを作成してみましょう。 Oracle Cloudコンソールのサイドバー・メニューで、「Application Integration」→「Events Service」を選択します。 次に、ルール・リストのページで、「Create Rule」を作成します。 名前と説明を入力します。 次に、このルールにフィルタを追加し、Object Storageサービスのイベント、特にObject Createイベントのみに制限するようにします。さらに、特定のバケットのみにフィルタを制限します。 次に、ルールがトリガーされたときに実行するアクションを定義します。この例では、Oracle Notification Serviceトピックを呼び出しましょう。 この時点でルールを保存してテストできます。テストするには、オブジェクトをObject Storageバケットにアップロードします。Slackチャネルにまったく新しいメッセージが送信されます。このメッセージは先ほど確認したものとは少し異なり、Cloudのイベント全体がJSON形式の文字列で表されていますが、このメッセージには、この通知からアクションを実行する必要がある場合に利用できる有用な情報が大量に含まれています。 サービス・アラーム経由での通知の自動送信 アラームはOracle Cloud内のリソースやインフラストラクチャを監視し続けるための非常に優れた手段です。アラームの作成は本当に簡単で、アラームが指定したしきい値に達すると、Oracle Notification Serviceに通知をパブリッシュできます。  ここでは、Object Storageバケットが1分に10回を超えるGetリクエストを受信した場合に通知をパブリッシュするアラームを作成してみましょう。 ただし、これはサンプルとしては不自然なものになっています。多くのサービスには便利なメトリックが用意されていて、それらを利用すればMonitoringサービスで継続的に監視できるのですから。 それでは、デモのアラームを作成してテストしてみます。コンソールのサイドバー・メニューで、「Monitoring」→「Alarm Definitions」を選択します。 次に、「Create Alarm」をクリックします。 名前を付け、重大性を選択し、アラーム・メッセージの本文を定義します。 次に、このアラーム用に評価されるメトリックを定義します。名前空間'oci_objectstorage'を選択し(他にも多数のオプションがあります)、メトリックに'GetRequests'を選択し、時間隔として1分、統計として'count'を選択します。ディメンション名として'resourceDisplayName'を追加し、特定のバケットをディメンション値として選択して、特定のObject Storageバケットだけになるようにこのメトリックをフィルタします。さらに、トリガー・ルールを'greater than'、値を1、トリガー間隔を1分とします。 これらの指定によって、1分間で1つを超えるGetリクエストが存在する場合にアラームがトリガーされます。 最後に、下にスクロールして通知の詳細を指定し、「Save alarm」をクリックします。 テストするには、指定したバケット内に保存されている画像に対して、何回か'GET'リクエストを実行します。最初のリクエストの後にアラームがトリガーされ、先ほどと同じようにSlackチャネルにメッセージがポストされます。 Zapierによる通知からのGitHubイシューの自動作成 記事の最後に、外部との統合の例を示そうと思っていましたが、今回は上記の例よりも少し"現実に近い"アプリケーションを取り上げることにします。この例では、Zapierによって作成されるHTTPS(カスタムURL)エンドポイントを使ってトピックにサブスクリプションを追加します。Zapierは、定められたトリガーに基づいて定められたアクションを実行する"Zap"を作成するためのプラットフォームであり、その考え方はIFTTT("if this then that")に似ています。 ここでは、Zapier Webフックをトリガー("これが起きたとき"というアクション)として作成し、GitHubを宛先として利用します("これをする"というアクション)。ここまでは大丈夫でしょうか?では、まず"Zap"を作成しましょう。'アプリ'として「Webhooks by Zapier」を選択し、トリガー・イベントとして「Catch Raw Hook」を選択します。 この設定によって、カスタムのWebフックURLが表示されます。この情報は後で必要になります。 次に、このZapのステップ2で、'アプリ'として「GitHub」を選択し、アクション・イベントとして「Create Issue」を選択します。 詳細情報として、プロジェクトのリポジトリ、イシューのタイトル、イシューの本文(この例ではOracle Notification Serviceからのメッセージ本文そのもの)を入力します。 保存し、この新しいWebフック用のサブスクリプションを作成します。 作成された新しいGitHubイシューを表示して、このサブスクリプションの動作を確認します。 有効にし、Oracle Cloudコンソールからメッセージをパブリッシュしてテストします。 CloudのイベントのJSONを解析することもできます。そのためには、一時的にZapのJavaScriptコードを利用して、その後GitHubイシューを作成して、整形されたチケットを生成します(さらに、特定のイベントタイプに絞り込むためのフィルタを追加するといったことも可能です)。 Zapierでは他にも、Jiraイシューの作成、SMSアラートの送信、Twitter統合など、実に多くの追加の統合機能を利用できます。  まとめ 私が通知を使い始めた当初はやや面白みがないと感じていました。しかしすぐに、通知が開発を容易にしてアプリケーションをよりインテリジェントにする大きな可能性を秘めていると分かりました。この記事の情報量が多いことは承知しており、 おそらく2~3つの記事に分割できたでしょうが、このような形でまとめたまま公開すべきものだと感じた次第です。この記事をぜひブックマークして、今後の参考資料としてお役立てください。ご質問については、以下のコメント欄からどうぞ。 お知らせ: この記事で使ったコードはGitHubでも公開されています。ぜひご覧ください。  https://github.com/recursivecodes/ons-demo Photo by AbsolutVision on Unsplash   ※本記事は、Todd Sharp (Developer Advocate)による”Complete Developers Guide To The Oracle Notification Service“を翻訳したものです。   AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

クラウドの好きな機能をリストとしてまとめると、多くの開発者の"トップ10"リストに通知が入っていることはおそらくないでしょう。通知はどちらかというと"ユーティリティ"機能で、自動車のタイヤのようなもの。必要不可欠で、動かなければイライラさせられますが、順調に動いていれば考えることもほぼありません。 かつて私は通知をこのように捉えていましたが、最近になってオラクルのサービスOracle...

全国のOTNおすすめ技術者向けセミナー&イベント(2019年12月)

12/5 一歩進んだ分析でビジネスにチカラを!! ~あなたもデータ アナリスト~ 本セミナーでは、Oracle Cloud を活用して、部門や社員が自ら一歩進んだ分析を行い、ビジネス上のインサイト(洞察)を獲得する方法を体験して頂きます。操作 PC をご用意しています。この機会にぜひご参加ください。 12/10 Oracle Cloud Infrastructure ハンズオン 「Oracle Cloud Infrastructure」は、オンプレミスからの大規模ワークロード移行に完全対応する次世代インフラ基盤です。本セミナーでは、Oracle Cloud Infrastructureのサービス概要のご紹介とともに、実際のクラウド環境を利用したハンズオンを半日で体感いただけます。 12/19 実践Kubernetesハンズオン ~OKEでKubernetesを体験しよう~ Oracle Cloudは大規模なコンテナの管理、デプロイおよび運用に適したクラウドサービスを複数提供しています。本ハンズオンセミナーではOracle Cloudが提供するコンテナ・サービスを実際に利用しKubernetes環境の構築からコンテナ・アプリケーションのデプロイ、CI/CDまでの一連の流れを体感いただけます。 AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。          

12/5 一歩進んだ分析でビジネスにチカラを!! ~あなたもデータ アナリスト~ 本セミナーでは、Oracle Cloud を活用して、部門や社員が自ら一歩進んだ分析を行い、ビジネス上のインサイト(洞察)を獲得する方法を体験して頂きます。操作 PC をご用意しています。この機会にぜひご参加ください。 12/10 Oracle Cloud Infrastructure ハンズオン 「Oracle...

もしもみなみんがDBをクラウドで動かしてみたら 第15回 Autonomous Databaseの自動スケーリングを設定してみよう

window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-159254751-1'); もしもみなみんがDBをクラウドで動かしてみたら indexページ ▶︎▶︎ ※本記事は2019/11/20時点のものになります みなさん、こんにちは。 今回は、第13回で紹介したAutonomous DatabaseのOCPUスケール・アップ/ダウンを自動で行ってくれる、自動スケーリング機能について紹介したいと思います!   Autonomous Databaseの自動スケーリング機能とは Autonomous Databaseの自動スケーリング機能は、負荷状況に応じてOCPUリソースを自動でアップ/ダウンしてくれる機能です。 ・負荷状況に応じて、OCPU数とI/O帯域が変動 ・有効にしているOCPU数の最大3倍(*1)まで自動で即座に増減 ・インスタンス再起動やコネクション切断なく動的に実施 ・課金は1時時間あたりのOCPU利用状況に応じて決定   (*1) Autonomous Database Serverlessの最大OCPU数は128 OCPUなので、3倍の数が128を超える場合は最大128まで 手動で実行する場合との違いはあるの? 自動スケーリングによるスケール・アップ/ダウンした場合は、OCPU数に応じて設定される各種設定はそのままの設定で動き続けます。具体的には、メモリサイズや事前定義済の接続サービスで設定されているパラレル実行数や同時実行セッション数等の設定などは、有効にしているベースのOCPU数に基づいた設定が利用されます。 事前定義済のサービスについてはこちら : Autonomous Databaseの接続サービスとシェアについて   設定方法 Autonomous Databaseを新規で作成する際に、そのインスタンスで自動スケーリング機能を有効にするかどうかを指定します。後からの変更も可能です。 新規作成時の設定 自動スケーリングを有効にする場合には、『自動スケーリング』にチェックをいれてインスタンスを作成します 設定情報は、サービス詳細ページの『Autonomous Database 情報』から確認できます。 設定の変更方法 コンソール(WebUI)やREST APIなどで設定変更が可能です。設定の変更も、オンライン(インスタンス再起動なし)で実施されます。 ・コンソール サービス詳細ページの上部の『スケール・アップ/ダウン』をクリック 『自動スケーリング』のチェック有無で有効化/無効化を切り替えられます。切り替えはオンラインで行われるので、インスタンスの再起動はありません。   ・OCI CLI #OCI CLIのセットアップは完了している前提ですすめますので、まだこれからという方は下記をご参考にセットアップしてみて下さい ・マニュアル Oracle Cloud Infrastructure Documentation > コマンド・ライン・インターフェース > クイックスタート ・Oracle Cloud 公式ブログ コマンドライン(CLI)でOCIを操作する – Oracle Cloud Infrastructureアドバンスド OCI CLIで操作する際に対象リソースの識別子としてインスタンスのOCIDの情報が必要になるので、事前に確認しておきましょう。 設定状況は、oci db autonomous-database get でインスタンスの情報を出力することで確認可能です。 $ oci db autonomous-database get --autonomous-database-id <Autonomous Databaseインスタンスのocid> 例 $ oci db autonomous-database get --autonomous-database-id xxxx --query 'data.{"1.display-name":"display-name","2.cpu-core-count":"cpu-core-count","3.is-auto-scaling-enabled":"is-auto-scaling-enabled"}' {   "1.display-name": "ATPEM",    "2.cpu-core-count": 2,    "3.is-auto-scaling-enabled": false } 変更は、oci db autonomous-database update で --is-auto-scaling-enabled の設定をtrueもしくはfalseに更新することで設定変更されます。 $ oci db autonomous-database update --autonomous-database-id <Autonomous Databaseインスタンスのocid> --is-auto-scaling-enabled [true/false] 例 $ oci db autonomous-database update --autonomous-database-id xxxx --is-auto-scaling-enabled true .... $ oci db autonomous-database get --autonomous-database-id xxxx --query 'data.{"1.display-name":"display-name","2.cpu-core-count":"cpu-core-count","3.is-auto-scaling-enabled":"is-auto-scaling-enabled"}' {   "1.display-name": "ATPEM",    "2.cpu-core-count": 2,    "3.is-auto-scaling-enabled": true } ・ マニュアル OCI CLI Command Reference DB > autonomous-database > update     自動スケーリング機能を使ってみよう 実際に自動スケーリングを使った場合と使わない場合で負荷をかけて、どのようになるかを違いをみてみました 本検証の内容と設定 ・ 利用サービス :Autonomous Transaction Processing (ADWでも可) ・ OCPU数 : 2  ・ CPUボトルネックになる処理を並列実行 ・ 接続サービスはLOWを利用 ・ 自動スケーリングを有効/無効した環境でのCPU使用率や実行数などを確認 テストデータや利用したSQLは第13回同様、しばちょう先生の連載を参考にしていますのでぜひご参考までに。 しばちょう先生の試して納得!DBAへの道 第53回 SQLパフォーマンスの高速化の限界を目指せ!(1)   結果 Autonomous Databaseのサービス・コンソールから確認できるアクティビティ情報の各グラフを利用して、解説していきます。(平均値が表示されているグラフなので左右で全く同じグラフにはなりません) 左側が自動スケーリングが無効なインスタンスで、右側が有効にしているインスタンスです。09:59頃から処理を流し始め、10:03頃からCPU使用率が高くなっています。 まずはCPU使用率からみてみましょう。 無効化しているインスタンスは、処理数を増やしたところからずっとCPU使用率が100%で張り付き、リソースが逼迫している状態で動き続けています。対して有効化しているインスタンスは処理数を増やしたところで一気にCPU使用率が上昇しますが、スケール・アップされたため利用可能なコア数が増えことから、100%にはならずにリソースに少し余裕がある状況で実行されていますね。(もちろん負荷によっては3倍のリソースでも不足することもあるので、スケール・アップしたとしてもリソース枯渇する可能性はあります) 次に、Database Activityの情報を見てみます。 無効化しているインスタンスは、処理数を増やしたところからグレーの層(Scheduler)が出てきていますね。これは待機している処理/セッションがある状態を示しています。対して有効化しているインスタンスは、処理数が増えてCPU使用率が上昇したことから自動的にコア(OCPU)が増やされたため、処理に対して割り当てられるコアが増え、待機せずに処理が動いていることがわかるかと思います。 その結果、無効化の場合には22分かかった処理が、有効化にした場合には7分で完了しました。 さて、最後に課金がどのようになったのか見てみます。こちらもサービス・コンソールの画面から確認できるOCPU数のグラフ(1時間単位)です。今回、下記のグラフの矢印のあたりが自動スケール・アップされた時間帯ですが、、、あれ?OCPU数が2のまま?!お得?! 課金に関しては、ベースのOCPU数もしくは最大OCPU数 x 平均CPU使用率のどちらか大きい方になります。今回はスケールアップされたのは数分のみだったこともあり、上記計算式で課金対象のOCPU数はスケール・アップされたOCPU数ではなくベースの有効にしている2のほうが大きくなったので課金も2になったようですね。もちろん、計算式で最大OCPU数 x 平均CPU使用率の方が大きくなれば結果は変わるのでご注意ください。 ※課金の部分に関しては2019/11時点の情報であり利用状況によって異なりますので、あくまで参考情報として見てください。   まとめ 自動スケーリングを実際に利用してみて、CPU使用率が上昇し割り当て済のリソースよりも多くのリソースが必要となる状態において、処理実行中においても影響なく自動でコアが増え(スケール・アップ)、それにより処理が遅延せずに実行されたことがわかりました。 負荷状況に応じて自動でスケール・アップ/ダウンされる場合、課金面や実行中のトランザクションへの影響について気になる人も多いと思います。実行中のトランザクションの影響に関しても、インスタンスの再起動なく行われ、実際に高負荷な状況になっている際に勝手にリソースが増えていたので、実行中の処理に影響なくリソースが割り当てられて即座に利用できるというのは助かりますね。課金に関しては、ベースのOCPU数もしくは最大OCPU数 x 平均CPU使用率のどちらか大きい方。1時間あたりの最大値ではなく実際の利用状況に応じた決定になるというのはいい点ですね。     関連リンク ・Oracle Cloud Infrastructure ドキュメント Autonomous Database 英語/日本語 ・Autonomous Transaction Processing マニュアル 英語/日本語 ・Autonomous Data Warehouse マニュアル 英語/日本語 ・Release Note(英語) Auto scaling Autonomous Databases  ・Autonomous Database サービス・アップデート 日本語 ・Autonomous Database 技術詳細資料 日本語   もしもみなみんがDBをクラウドで動かしてみたら indexページ ▶︎▶︎

もしもみなみんがDBをクラウドで動かしてみたら indexページ ▶︎▶︎ ※本記事は2019/11/20時点のものになります みなさん、こんにちは。 今回は、第13回で紹介したAutonomous DatabaseのOCPUスケール・アップ/ダウンを自動で行ってくれる、自動スケーリング機能について紹介したいと思います!   Autonomous Databaseの自動スケーリング機能とは Autonomous...

データの安全性を維持する - パート(3):クラウド・データベースの評価

Russ Lowenthal Senior Director この記事は同時掲載記事です。オリジナル記事はこちらをご覧ください データベースのセキュリティを確保するための最初のステップは、データベースの現在の状態を把握することです。それには、データベースの構成方法、ユーザーの詳細、システムに格納されるデータの種類を知る必要があります。その一助となるのがOracle Data Safeです。データベースの構成の分析、データベース・ユーザーのリスク調査、データベース内に存在する機密データの種類やその保存されているデータの容量の分析を簡単に実行できます。 この記事では、Data Safeの評価機能に焦点を当てて説明します。なお、機密データの検出機能については後日取り上げます。Data Safeの評価には、「セキュリティ」と「ユーザー」の2種類があります。                      セキュリティ評価は、構成、セキュリティ制御の利用状況、およびユーザーの管理方法(権限、ロール付与を含む)を調査するものです。セキュリティ評価を利用することで、環境に対して不必要なリスクをもたらす可能性のある構成を特定できます。脆弱なパスワード・ポリシー、機密データベース・オブジェクトへの不必要なアクセス、アクセス制御の非適用などが当てはまります。セキュリティ評価結果のそれぞれで、調査で判明した内容の詳細、それが重要である理由、および(適宜)CIS、STIG、EU GDPRなどの該当するセキュリティ・フレームワークへの参照が示されます。以下の画像は調査結果の一例です。この例では、Datapump_EXP_FULL_DATABASEロールが複数のユーザーに付与されていて、そのロールに伴ってEXEMPT REDACTION POLICY権限が間接的に付与されています。この調査結果は助言的な性質のものであり、このロールや権限が付与されたユーザーに対してOracle Data Redactionのポリシーの効果が消失していることが分かるだけのものになっています。                      ユーザー評価はデータベース・アカウントに焦点を当てて、それらのアカウントのシステムに対するリスクのレベルを詳細に分析します。つまり、ユーザーのアカウントが侵害された場合、その侵害によってどの程度のダメージが発生し得るか、ということです。以下の画面から、ユーザーが誰であるかを確認し、あるユーザーを掘り下げて、その作成者、アカウントのステータス、最終ログオン日時、付与されているロールと権限を確認できます。また、パスワードの最終変更日時を確認し、「View Activity」をクリックして、そのユーザーがデータベース内で実行した操作まで掘り下げることもできます。このData Safeの機能は特に注目に値します。Oracleが製品を問わずこの種のビューを提供するのは初めてだからです。データベース侵害の最大の原因がアカウント侵害であることは、おそらく皆さんお気づきでしょう。だからこそ、侵害されたアカウントの立場からリスクへのアプローチを開始する必要があることは一理あります。Oracleは現在、ユーザー・アカウント内のリスク評価に役立つ機能を強化しており、Data Safeのこの分野も今後1年で急速に成長する見込みです。                      Oracle Cloudでデータベースを運用していて、まだData Safeを利用されていない方には、このサービスを構成してデータベースの評価を最優先で行うことをお勧めします。Data Safeはお使いのデータベース・サービスに含まれており、追加費用はかかりません。データをクラウド内で保護するための最高のツールの1つとなります。 Data Safeがユーザーやデータをクラウド内で保護する方法についての詳細情報は、Data Safeのホワイト・ペーパーか、新登場のデータベース・セキュリティEブック(第3版)のData Safeに関する新しい章をご覧ください。また、まだご覧でない場合は、Data Safeを紹介する全5回にわたるブログ記事シリーズのパート1、パート2をお読みください。   ※本記事は、Russ Lowenthal (Senior Director) による”Keeping your Data Safe, Part (3): Assessing Cloud Databases“を翻訳したものです。   AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

Russ Lowenthal Senior Director この記事は同時掲載記事です。オリジナル記事はこちらをご覧ください データベースのセキュリティを確保するための最初のステップは、データベースの現在の状態を把握することです。それには、データベースの構成方法、ユーザーの詳細、システムに格納されるデータの種類を知る必要があります。その一助となるのがOracle Data Safeです。データベー...

GraalVM によるOracle Cloud Infrastructure Monitoringサービスのパフォーマンス改善

Esteban Ginez 技術スタッフ主要メンバー GraalVMは汎用の仮想マシンであり、あらゆるプログラミング言語向けに高いパフォーマンスと完全な相互運用性を発揮するように作られています。 Oracle Cloud Infrastructureの多くのチームが、自チームのサービスをGraalVMイメージ上で運用することでパフォーマンスが向上したことを確認しています。Oracle Cloud InfrastructureのMonitoringサービスは先日GraalVMへの移行を完了し、現在は本番環境で運用されています。 MonitoringはOracle Cloud Infrastructure内部の基本サービスです。内部の全チームが、担当するサービスの健全性を監視するためにこのサービスを利用しています。Monitoringはメモリを大量に消費するアプリケーションで、Java Native Interface(JNI)呼び出しを非常によく利用します。Monitoringサービスはアプリケーションに対して、ホストやアプリケーションのメトリックの収集と操作、アラーム生成、通知のためのREST APIを提供しています。このサービスは、Oracle Cloud Infrastructureのすべてのサービスを起点とする数千万のデータ・ポイントを常時処理しています。また、Oracle Cloud Infrastructureのどこからでも利用でき、数十億件のメトリックを取り込んで数百万件のリクエストを処理しています。   GraalVMによる改善効果 GraalVM Enterprise Edition version 19.1コンパイラの最適化によってオブジェクトの割当て件数が減少し、全体的な実行スピードが改善しました。その結果、ガベージ・コレクションによる一時停止回数が減り、より少ない処理能力でワークロードを実行できるようになりました。Monitoringサービスが消費するCPUは全体で5 %減少し、さらにスループットが向上し、ガベージ・コレクションやその他のシステム・アクティビティにかかる時間も大幅に短縮されました。それぞれについて、以降のセクションで説明します。   ガベージ・コレクションの処理時間の短縮 Java 8 update 212と比較して、Monitoringサービスのガベージ・コレクションの処理時間は25 %少なく、アプリケーションの一時停止時間も17 %少なくなりました。アプリケーションの一時停止時間の減少について、以下のグラフに示します。   スループットの向上 Monitoringサービスに対するGraalVMの最適化によって、以下のグラフのとおり、Java 8 update 212と比較して1秒あたりトランザクション件数が10 %増加しました。   移行 MonitoringサービスのGraalVMへの移行プロセスはシンプルで透過的に行われました。サービスのコードとJVM構成を変更することなく、切り替えを実行できました。 結論として、幅広いケースやさまざまな負荷状況下で、GraalVMはJava 8 update 212よりも高いパフォーマンスを発揮します。Monitoringサービスはそのメリットを得られた格好の例と言えます。 Oracle Cloud InfrastructureはGraalVM Enterprise Editionを無償で提供しています。ぜひ実際にお試しいただき、Javaワークロードのパフォーマンス向上を体験してください。   ※本記事は、Esteban Ginez (PRINCIPAL MEMBER OF TECHNICAL STAFF) による”GraalVM Powers Oracle Cloud Infrastructure“を翻訳したものです。   AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

Esteban Ginez 技術スタッフ主要メンバー GraalVMは汎用の仮想マシンであり、あらゆるプログラミング言語向けに高いパフォーマンスと完全な相互運用性を発揮するように作られています。 Oracle Cloud Infrastructureの多くのチームが、自チームのサービスをGraalVMイメージ上で運用することでパフォーマンスが向上したことを確認しています。Oracle Cloud In...

Oracle Autonomous Data Warehouse アーキテクチャと戦略:Part3(全3回)

Bill Kleyman Switch、Digital Solutions、EVP | 業界インフルエンサー   3ブログ・シリーズのパート3:世界初、世界で唯一の自己保護型データベース・クラウド・サービス   ITやセキュリティの担当者は、データ侵害について考えただけで肝を冷やしますが、それにはもっともな理由があります。私たちは、データ侵害のコストが金銭的なものにとどまらないことを知っているのです。データ損失の影響は、ブランド、お客様、パートナーシップなど、さまざまなものに及びます。そしてデータをクラウドで管理するようになると、セキュリティ対策はいっそう複雑になります。 オラクルによる最近のセキュリティ・レポートによれば、クラウドとテナントの「Shared Responsibility Security Model」(責任共有セキュリティ・モデル:SRSM)にまつわる混乱が、多大なコストを発生させているとのことです。今年の調査に参加した企業のうち3分の1以上が、そのような混乱が原因でマルウェアに攻撃されたと答えています(34%)。またほぼ同じ割合の回答者(32%)が、監査リスクが増大したと答えました。 責任共有セキュリティ・モデルへの理解が不足しているため、データもリスクにさらされており、結果として権限のない人がデータにアクセスするという事例を30%の企業が経験していました。さらに29%の回答者が、混乱が生じた結果、パッチ未適用または構成を誤ったシステムが侵害されたと答えました。このことから、パブリック接続を使用しているクラウド・インフラストラクチャは、適切に構成されていないパブリック・サービスを狙うボットネットの攻撃を常に受けていることがよく分かります。 御社のクラウド環境は、セキュリティを念頭に置いて設計されている場合のみ、セキュリティが確保されているということを忘れないでください。たとえば最近の調査によれば、全S3サーバーのうちの7%が認証なしに外部から完全にアクセス可能であり、35%は暗号化されていないということです。過去6か月ほどの間に発生したインシデントから推測すれば(Risk Based Securityの最近の調査によると、2019年の前半だけで、3,813件のデータ侵害が報告され、41億件以上のレコードが流出したとのこと)、それらは決して価値の低いデータを格納していたわけではないはずです。   先に進む前に、3回連載のOracle Autonomous Data Warehouseのブログ・シリーズのパート1とパート2を読んでおくことをお勧めします。しかし、そんなことよりセキュリティについて今すぐに知りたいというのであれば、それもやむを得ないでしょう――セキュリティは重要で、急を要するトピックですから。 Oracle Database Securityのシニア・バイス・プレジデントであるVipin Samarはこのように述べています。「データは最も重要な資産ですが、適切に保護されていない場合は、非常に大きな重荷になります」。それでは、Oracle Autonomous Data Warehouseというソリューションを利用すると、他にはないどのようなメリットがあるのでしょうか。私の見たところでは、セキュリティ面が優れているようです。アーキテクチャ全体のDNAに、セキュリティが組み込まれているのです。説明しましょう。 Oracle Autonomous Data Warehouseは、すべてのデータを暗号化して保存します。承認されたユーザーとアプリケーションのみが、データベースへの接続時にデータにアクセスできます。それ以降、Autonomous Data Warehouseへのすべての接続では、証明書ベースの認証とSecure Sockets Layer(SSL)暗号化が使用されます。つまり、Autonomous Data Warehouseへの許可のないアクセスは発生せず、クライアントとサーバーとの間の通信は完全に暗号化され、妨害や改竄は不可能であるということになります。したがって、悪意ある攻撃(中間者攻撃など)が発生した場合でも、完全に暗号化された通信が傍受されることはなく、Autonomous Data Warehouseは安全に稼働し続けます。 優れた点は他にもあります。データやデータベースへの接続を暗号化するのに、手動による構成は一切必要ありません。Autonomous Data Warehouseがあなたの代わりにやってくれるからです――まさに自律的に。なぜそれが重要なのでしょうか。クラウド・プロバイダーの中には、ストレージ・リポジトリやバケットを実際には暗号化しないところもあるからです。前述のように、セキュリティ企業Skyhigh Networksによれば、すべてのS3バケットのうち、35%は暗号化されていません。そして、このようなセキュリティの欠如はすでに、大手企業に影響を与えています。 Autonomous Data Warehouseは自律的に通信を暗号化するだけではなく、Oracle Cloudのセキュリティ標準に基づいて、すべてのユーザーに強力なパスワードの複雑さのルールを適用しています。まさかと思うかもしれませんが、パスワード・ポリシーについては、今でも多くの企業が問題を抱えています。そのため、ユーザーがパスワードをもっと頻繁に変更していれば、またはもっと複雑なパスワードにしていれば防げたかもしれないデータ侵害が発生しているのです。強力なパスワードの複雑さのルールを適用していれば、御社の最も重要なデータ・ポイントが、厳しいセキュリティ・ポリシーから外れることはありません。 さらに制限を厳しくするには、ネットワーク・アクセス制御リスト(ACL)を指定します。ネットワークACLを指定することで、特定のAutonomous Data WarehouseデータベースのみがACLにあるアドレスからの接続を受け入れ、他のクライアント接続はすべて拒否されます。つまり、悪意のあるアクセス試行やなりすまし攻撃は失敗します。ネットワーク・アクセス制御リストでは、ADWデータベースにアクセスできるデバイスを細かく指定できます。 Oracle Autonomous Data Warehouseには、セキュリティのベスト・プラクティスをお客様のデータに実装する以外にも、他にはない特長があります。お客様のデータウェアハウスを自動で保護するのです。これがどんなにすばらしいかと問われれば、非常にすばらしいと私は答えます。   世界初、世界で唯一の自己保護が可能な自律型ウェアハウス これについては、Autonomous Data Warehouseブログ・シリーズのパート1とパート2で詳しく取り上げています。しかし、このサービスがユーザーのために実行する、強力な自律型プロセスが多数あることに触れておくのは重要なことです。 Oracle Autonomous Data Warehouseが自己稼働型であるというのは、ネットワーク構成、ストレージ、データベースのパッチ適用およびアップグレードをお客様に代わって行う、完全に管理されたデータウェアハウス・クラウド・サービスであるという意味です。お客様側ではDBAは必要ありません。 Oracle Autonomous Data Warehouseは自己修復型でもあります。すべてのコンポーネントは高可用性を念頭に置いて設計されており、バックアップは完全に自動化されています。つまり、このアーキテクチャは停止時間に対する保護を備えており、その保護は設計の中心に組み込まれています。データベースを稼働させ続けるためにデータ・プラットフォームがアクティブに働いてくれているのを知れば、あなたも夜や週末の時間を自由に使えるようになるでしょう。 Oracle Autonomous Data Warehouseは自己保護型です。 この種のデータベースとしては最初の自己保護型自動ウェアハウス・データベースですが、自己保護はOracle Cloudインフラストラクチャとデータベース・サービスのセキュリティから始まっています。Oracle Cloudインフラストラクチャの一部であるAutonomous Data Warehouseエコシステムの中では、セキュリティ・パッチは必要に応じて自動で適用されるため、脆弱性の存在する期間が短くなり、パッチが適用されていないシステムが抱えるリスクを軽減できます。 さらに、パッチ適用はスタック全体、つまりファームウェア、オペレーティング・システム(OS)、クラスタウェア、データベースを対象とします。お客様側で必要な手順はありません。パッチ・リリースを手動で追跡したり、スタックのさまざまなレイヤーで複数のパッチを追跡したりした日々はもう過去のものです。まさに「自己保護型」という言葉がぴったりです。 Oracle Autonomous Data Warehouseの自己保護型サービスは、データベースを含めたインフラストラクチャのセキュリティの状態を管理します。すべての処理が自動で行われ、ヒューマン・エラーの入り込む余地はありません。このエコシステムではここから、送受信中も、保存中も、バックアップされている間も、お客様のデータは常に暗号化されます。暗号化鍵は自動で管理され、ここでもお客様の介入は一切必要ありません。また、市場に出ている一部のデータ・ソリューションとは異なり、暗号化をオフにすることはできません。デフォルトでオンになっています。これほどまでにデータ侵害が蔓延している今の時代に、御社の大事なデータを暗号化せずにいていいはずがありません。 最後に、Oracle Autonomous Data Warehouse Cloudの管理作業は、ログに記録されて集められ、異常なアクティビティがないかどうか監視されます。そうです、ご想像の通り、Autonomous Data Warehouseサービスが異常な動作や異常なユーザー・アクセスをスキャンして、評価します。つまり、Autonomous Data Warehouseは定義済みのポリシーを使用してデータベース監査を行うため、お客様は何らかの異常のアクセスがあった場合にログを確認できます。 Autonomous Data Warehouseによる事前予防的かつインテリジェントな保護があるとはいえ、お客様はデプロイしているワークロードとデータに対して、セキュリティのベスト・プラクティスが適用されるように引き続き努めなければなりません。Oracle Database Securityのシニア・バイス・プレジデントであるVipin Samarはこのように述べています。「クラウドでのデータベースの保護は、共有責任です。オラクルがインフラストラクチャとネットワークを保護し、OSとネットワークの動作を監視し、OSとデータベースにパッチおよび更新を適用し、暗号化、適切な責任の分散、さまざまな認証を処理します」。 Samarはさらに続けます。「お客様企業は引き続き、アプリケーション、ユーザー、データを保護していく必要があります。そのためには、自社を標的とする攻撃をアプリケーションが阻止できるようにし、自社のユーザーがセキュリティのベスト・プラクティスに従い、ふさわしい管理によって機密データが保護されている状態を保つ必要があります。ある意味では、こうした要件は企業が現在利用しているオンプレミス・データベースの場合と同じであり、異なるのはセキュリティに関するインフラストラクチャの部分をオラクルがすでに引き受けているということだけです」。 自動で保護、自律的にインテリジェント 昨今の脅威を拡散させている媒体の規模、スピード、破壊力を考えると、当面の間、ビジネス・リーダーは心の安まるひまがなく、テクノロジーも停滞してはいられないでしょう。しかし、Oracle Autonomous Data Warehouseソリューションの一部である自動化されたセキュリティ・テクノロジーと、クラウドベースのID管理により、企業はリスクを管理できるようになります。 データとインフラストラクチャへの攻撃は、さまざまな形を取って行われます。国家を含む悪意ある攻撃者、APT攻撃、組織的犯罪、そして意図的ではない(または何らかの不満を抱いてなされる)内部の人間による脅威はすべて、御社のビジネスにも大きく関係しています。御社のインフラストラクチャ、オペレーティング・システム、アプリケーション、ユーザー、そしてもちろんデータベースが標的になる可能性があるのです。 データセットの価値がいよいよ増している今、いったん足を止めて、データベースについて十分に理解し、自社がどのようにデータを活用しているかを把握しましょう。 信じられないかもしれませんが、データなくしては何も進まない今の世の中で、自社のデータベースがどれほど安全なのか、機密データはどこに保存されているのか、実際にどれほどの量のデータを保有しているのかといったことを把握していない企業が多数あるのです。御社がそうであるなら、データの海を自分たちだけで泳いでいこうとはしないでください。 たとえばオラクルは先般、Oracle Autonomous Databaseの機能であるOracle Database Security Assessment Toolをリリースしました。このツールを使用すれば、先ほど挙げたような質問に答えられるようになります。このツールはさまざまなセキュリティ構成パラメータを確認して、不足している点を特定し、必要なセキュリティ・パッチを探します。そして暗号化、監査、アクセス制御などのセキュリティ対策が施されているかを確認し、ベスト・プラクティスと照らし合わせます。 このAssessment Toolで、自社の機密データはどこに格納されているか、どれほどのデータがあるのかを確認できます。Oracle Database Security Assessment Toolは個人を特定する情報、仕事のデータ、健康状態に関するデータ、財務データ、情報技術に関するデータなど、50種類以上の機密データについて、データベースのメタデータを検索します。そうしたデータのセキュリティ上のリスクを把握するためです。 また、この評価ツールは、検索結果に注目させたり、推奨事項を提示したりする機能があるため、グローバル企業の規制遵守に役立ちます。検索結果や推奨事項は、欧州連合の一般データ保護規則(EU GDPR)とCenter for Internet Security(CIS)ベンチマークの双方に対応しています。 御社のデータ(と評判)を守りたいのであれば、データ・セキュリティへの第一歩として、問題解決につながる質問に対する答えを考え、現在のデータの使用方法を把握し、スマートで自律したソリューションを活用することで、データの管理方法とデジタル・マーケットへのアプローチの方法を刷新することをお勧めします。覚えていてほしいのですが、まず取りかかるべきなのは、自社のデータ要件を十分に理解することです。つまり、以下の質問に答えられるようになってください。 データ量は増えているのか。管理が複雑になっているか。 セキュリティに関して「恐怖」を感じたことがあり、ポリシーの改善が必要とされているか。 現在使用しているデータ・システムには、インテリジェンスが全般的に不足していないか。 データ分析を適切に利用できていないために、競争上の優位性を失っていないか。 データを可視化できる優れたソリューションを使用しているか。 データの使用場所を増やしたり分散させたりしようとしているか。 ふさわしい種類のデータ駆動型アーキテクチャを見極めるのに役立つ質問は、他にもたくさんあります。Oracle Autonomous Data Warehouseがあれば、この難題に取り組むときに、当て推量で進むのを避けられます。自己稼働型、自己修復型、そして自己保護型であるという特長はすべて、御社がデータウェアハウスを最大限に活用できるようにするための設計です。 私が最初の投稿で書いたように、データは御社の業務にとって不可欠なものです。セキュリティも同じです。セキュリティは非常に重要であり、手抜きをする余地などありません。何よりも、時代遅れのアーキテクチャに足を引っ張られることのないように気をつけてください。環境が複雑化し、断片化が進むと、管理が難しくなるだけではなく、セキュリティのリスクが増大します。実際に、データ侵害の発生事例のうち85%は、すでに入手可能であったパッチが適用されていれば防げたかもしれないものです。Oracle Autonomous Data Warehouseのようなソリューションと、それを支える自己保護型アーキテクチャがあれば、そうした種類の脅威を排除し、本当に価値のあるもの、つまりユーザー、ビジネス、データに注意を集中させることができます。 Photo by Steven Su on Unsplash   ※本記事は、Bill Kleyman(EVP of Digital Solutions, Switch | Industry Influencer) による”Oracle Autonomous Data Warehouse: The world’s first and only self-securing database cloud service“を翻訳したものです。   AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

Bill Kleyman Switch、Digital Solutions、EVP | 業界インフルエンサー   3ブログ・シリーズのパート3:世界初、世界で唯一の自己保護型データベース・クラウド・サービス   ITやセキュリティの担当者は、データ侵害について考えただけで肝を冷やしますが、それにはもっともな理由があります。私たちは、データ侵害のコストが金銭的なものにとどまらないことを知っているのです。デー...

Database

基本からわかる!高性能×高可用性データベースシステムの作り方 第14回 AWRレポート作成とAWRスナップショット取得(PDB単位)

基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ 第13回ではCDB全体のAWRレポートの作成とAWRスナップショットの取得に関するコマンドラインでの操作について説明しました。今回はPDB単位でのAWRについてです。Oracle Database 12c Release 2からはPDB単位でもAWRレポートを作成できるようになっています。CDB全体とは異なり、PDB単位のAWRスナップショット取得はデフォルトでは有効になっていません。 PDB単位のAWRスナップショット自動取得の有効化 CDB全体のAWRスナップショット取得はCREATE DATABASEした時点でデフォルトで有効になっています。CDB全体で作成したAWRレポートにはすべてのPDBのアクティビティが混在して記載されます。しかし、PDB単位のAWRスナップショットの自動取得はデフォルトでは無効になっています。 PDB単位のAWRスナップショット自動取得を有効にするには初期化パラメータAWR_PDB_AUTOFLUSH_ENABLEDをTRUEに設定します。この設定には2階層あって、CDB$ROOTで設定するとすべてのPDBで有効になります。個別のPDBで設定するとそのPDBでのみ有効になります。 SQL> SHOW PDBS     CON_ID CON_NAME                       OPEN MODE  RESTRICTED ---------- ------------------------------ ---------- ----------          2 PDB$SEED                       READ ONLY  NO          3 SIPDB19A1                      READ WRITE NO          4 SIPDB19A2                      READ WRITE NO SQL> ALTER SESSION SET CONTAINER=SIPDB19A1; セッションが変更されました。 SQL> ALTER SYSTEM SET AWR_PDB_AUTOFLUSH_ENABLED = TRUE; システムが変更されました。 SQL> SHOW PARAMETERS AWR_PDB_AUTOFLUSH_ENABLED NAME                                 TYPE                              VALUE ------------------------------------ --------------------------------- ------------------------------ awr_pdb_autoflush_enabled            boolean                           TRUE PDBごとのAWRスナップショットの取得間隔と保存期間の設定はPDBごとに設定でき、CDB全体の場合と同じくDBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGSプロシージャを使用します。各PDB上で実行し、設定単位は分です。以下の例は取得間隔(interval)を10分、保存期間(retention)を44640分(=60分×24時間×31日)に設定しています。 SQL> EXEC DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS (interval=>10,retention=>44640); PL/SQLプロシージャが正常に完了しました。 設定の確認はAWR_PDB_WR_CONTROLビューを見ます。 SQL> SELECT CON_ID,SNAP_INTERVAL,RETENTION FROM AWR_PDB_WR_CONTROL;     CON_ID SNAP_INTERVAL        RETENTION ---------- -------------------- --------------------          3 +00000 00:10:00.0    +00031 00:00:00.0 PDB単位でのAWRスナップショットの手動取得もCDB全体の場合と同じくDBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOTプロシージャまたはファンクションを実行します。個別のPDB上で実行するとそのPDBのAWRスナップショットが作成されます。ファンクションをSELECT文で実行するとAWRスナップショットIDが返されるのはCDB全体の場合と同じです。PDBごとのAWRスナップショットIDはAWR_PDB_SNAPSHOTビューで調べることができます。 SQL> SELECT DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT() FROM DUAL; DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT() ------------------------------------------                                         14 SQL> SELECT MAX(SNAP_ID) FROM AWR_PDB_SNAPSHOT; MAX(SNAP_ID) ------------           14 PDB単位でのAWRスナップショットIDはPDBごとに独立したシーケンスです。CDB全体のスナップショットIDとも異なります。 PDB単位のAWRレポートの作成コマンド PDB単位のAWRレポートの作成にはsqlplusでOracleインスタンスに接続し、該当のPDBにログインしてAWRレポート作成のSQLスクリプトを実行します。CDB全体の場合と異なるのは個別のPDB上でSQLスクリプトを実行するというところです。 AWRレポートはHTMLもしくはテキスト形式のファイルとして出力されますが、そのファイルはsqlplusを起動したカレント・ディレクトリに作成されるため、ファイルを出力させたいディレクトリに移動してからsqlplusを起動します。管理者権限でログインします。 $ sqlplus / as sysdba SQL> ALTER SESSION SET CONTAINER=SIPDB19A1; セッションが変更されました。 AWRレポート作成のSQLスクリプトもCDB全体の場合と同じで、もっとも基本的なものがawrrpt.sqlです。awrrpt.sqlはログインしたデータベースのDBIDとOracleインスタンスでのAWRスナップショットからAWRレポートを作成します。CDB全体の場合と異なり、途中でPDB単位のレポートを作成するかが問われます。 sqlplusは@マークを付けたテキストファイルを読み取りそこに記述されているSQLスクリプトを実行します。awrrpt.sqlは$ORACLE_HOME/rdbms/admin/ディレクトリにあります。sqlplusは”?”の記号をORACLE_HOMEのディレクトリと解釈するため以下のように記述できます。 SQL> @?/rdbms/admin/awrrpt awrrpt.sqlを実行するとまず出力するファイル形式を問われます。デフォルトはHTML形式です。 Specify the Report Type ~~~~~~~~~~~~~~~~~~~~~~~ AWR reports can be generated in the following formats.  Please enter the name of the format at the prompt.  Default value is 'html'. 'html'          HTML format (default) 'text'          Text format 'active-html'   Includes Performance Hub active report report_typeに値を入力してください: 旧   1: select 'Type Specified: ',lower(nvl('&&report_type','html')) report_type from dual 新   1: select 'Type Specified: ',lower(nvl('','html')) report_type from dual Type Specified:                                  html ファイル形式はtextではなくデフォルトのhtmlをお勧めします。text形式はコピー&ペーストして報告書の作成などには便利ですが、長いSQL文が途中で省略されてしまいます。HTML形式はSQLが全文出力されます。「AWRレポートを提供してください」と言われたときは(デフォルトの)HTML形式のことだと思っておくとよいでしょう。 次にPDB単位のレポートを作成するかが問われます。PDB単位のレポートを作成するのでAWR_PDBを指定します。 Specify the location of AWR Data ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AWR_ROOT - Use AWR data from root (default) AWR_PDB - Use AWR data from PDB awr_locationに値を入力してください: AWR_PDB Location of AWR Data Specified: AWR_PDB 次はDBIDとOracleインスタンスの指定です。awrrpt.sqlの場合はこれらが今接続しているOracleインスタンスに決め打ちです。 Current Instance ~~~~~~~~~~~~~~~~ DB Id          DB Name        Inst Num       Instance       Container Name -------------- -------------- -------------- -------------- --------------  4081308537     SIDB19A                     1 sidb19a        SIPDB19A1 Root DB Id      Container DB Id AWR DB Id --------------- --------------- ---------------    4140346382      4081308537      4081308537 Instances in this Workload Repository schema ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   DB Id      Inst Num   DB Name      Instance     Host ------------ ---------- ---------    ----------   ------   4081308537     1      SIDB19A      sidb19a      jphppt07.jp. Using 4081308537 for database Id Using          1 for instance number 次に入力するnum_daysは何日前のAWRスナップショットまでさかのぼってリストに出すかです。何も入力せずにreturnを押すと記録が残っているすべてのAWRスナップショットがリストされます。以下の例では直近の1日分を出すために1と指定しています。 Specify the number of days of snapshots to choose from ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Entering the number of days (n) will result in the most recent (n) days of snapshots being listed.  Pressing <return> without specifying a number lists all completed snapshots. num_daysに値を入力してください: 1 Listing the last day's Completed Snapshots Instance     DB Name      Snap Id       Snap Started    Snap Level ------------ ------------ ---------- ------------------ ---------- sidb19a      SIDB19A              7  13 11月 2019 13:49   1                                   8  13 11月 2019 13:53   1 num_daysを入力するとAWRスナップショットを取得した時刻とそのSnap Idが列挙されます。2つのSnap Idを指定した間のAWRレポートが作成されます。begin_snapにはレポートする開始時刻のSnap Idを入力します。end_snapは終了時刻のSnap Idです。 Specify the Begin and End Snapshot Ids ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin_snapに値を入力してください: 7 Begin Snapshot Id specified: 7 end_snapに値を入力してください: 8 End   Snapshot Id specified: 8 最後に出力するファイル名を入力します。デフォルトの名前は指定したSnap Idから生成されています。enterを押すとAWRレポートが生成されます。画面にはHTMLが流れますが、それがsqlplusを起動したカレント・ディレクトリにファイルとして記録されます。 Specify the Report Name ~~~~~~~~~~~~~~~~~~~~~~~ The default report file name is awrrpt_1_7_8.html.  To use this name, press <return> to continue, otherwise enter an alternative. report_nameに値を入力してください: Using the report name awrrpt_1_7_8.html <p /> <p /> <p /> End of Report </body></html> Report written to awrrpt_1_7_8.html SQL> exit これでAWRレポートが生成されました。sqlplusからexitするとカレント・ディレクトリに指定したファイル名で出力されています。 基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ  

基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ 第13回ではCDB全体のAWRレポートの作成とAWRスナップショットの取得に関するコマンドラインでの操作について説明しました。今回はPDB単位でのAWRについてです。Oracle Database 12c...

データベースのセキュリティ評価・ユーザーリスク評価を可能にする Oracle Data Safe とは

  ユーザーは、Oracle Cloudの多くのメリットを利用することを熱望していますが、データの保護に役立つツールへ簡単にアクセスする必要もあります。   幸いなことに、Oracle Databaseのユーザーは、オンプレミスとクラウドの両方におけるデプロイメントをサポートする豊富なセキュリティ制御を利用できます。ただし、これらのソリューションのデプロイメントと継続的なサポートは、多くの場合は“自分でする”ことになっています。 Oracle Data Safeは、使いやすくオンプレミスでのデプロイメントを必要としない1つの統合されたクラウド・サービスで、5つの重要なデータ・セキュリティ機能をユーザーに提供します。 この記事では、次のそれぞれの機能を取り上げます。 セキュリティ評価 ユーザー評価 アクティビティ監査 データ検出 データ・マスキング たとえOracle Autonomous Databaseのようなマネージド・データベース・サービスを使用しても、ユーザーがサービスにアクセスするための構成方法にはかなりの自由があります。Data Safeのデータベース・セキュリティ評価機能は、セキュリティにマイナスの影響を与える構成の決定事項を表示し、脆弱性につながるギャップを特定するのに役立ちます。Data Safeのセキュリティ評価は、データベース構成の包括的なチェックを実行して、ユーザーのアカウント、権限およびロール付与、認可の制御、きめ細かな制御、監査、暗号化、構成パラメータなどの分野を調査します。また、組織のベスト・プラクティスと比較してギャップを特定し、優先順位付けされた推奨事項とEU GDPR、DISA STIGs、CISベンチマークなどの一般的なコンプライアンス条件へのマッピングを含む実用的なレポートを提供します。 Data Safeが実装する独自の新機能により、セキュリティ管理者はさまざまなデータベース・ユーザーによるリスクを評価できます。ユーザー・リスク評価機能は、データベース・ユーザーの評価を実行し、もっともリスクのあるユーザーを特定するためにユーザーのプロファイルの静的および動的な特性を調査します。ユーザー・リスクはグラフィカルに表示されるため、管理者は権限を越えている可能性のあるユーザーを迅速に判断したり、監査などの補正コントロールの適用を要求したりできます。 データベース監査は、おそらくデータベース・セキュリティと規制遵守のためにもっとも重要な制御です。Data Safeのユーザー・アクティビティ監査機能を使用すると、管理者は事前定義されたさまざまな監査ポリシーから選択をし、それらを1度のマウス・クリックでデータベースで有効化できます。そして、クラウド・データベースから監査記録の収集を開始し、それらはData Safeサービスに保存されてセキュアに維持されます。Data Safeのユーザーは、ユーザー・アクティビティの追跡や科学捜査の目的でインタラクティブ・レポートにアクセスでき、ルーチンの収集やレポート作成の目的でサマリー・レポートにアクセスできます。これらのレポートは、PDFでダウンロードでき、組織のコンプライアンス・プログラムに役立ちます。また、管理者は事前定義された多数のアラート・ポリシーから選択ができ、セキュリティ侵害を示す異常なアクティビティがあった場合はただちに通知を受け取ります。 データベース内に含まれるデータのタイプとデータの機密性により、そのデータを保護するために使用すべき制御が決定されます。Data Safeに含まれる機密データ検出機能により、セキュリティ管理者は、“自分はどのタイプの機密データを保持しているのか?”や“自分はどのくらいの機密データを保持しているのか?”といった重要な質問に素早く答えることができます。Data Safeの機密データ検出機能により、個人を識別できる情報、財務情報、健康情報、仕事に関連する情報、教育情報などのカテゴリーにわたって125を超える機密データタイプを自動検出できます。機密データ検出によって、ユーザーはデータの価値を理解しやすくなり、防御の優先順位付けができるようになります。 機密データのマスキングにより、テストシステムおよび開発システムからセキュリティ・リスクが排除され、エンタープライズによって保存される機密データ量が最小化されます。Data Safeのデータ・マスキング機能は、事前定義された50を超えるマスキング・フォーマットのライブラリによって機密アプリケーション・データを素早くマスキングする機能を提供します。デフォルトのマスキング・フォーマットは、機密データ検出機能を使用して検出された機密データのタイプを基に自動的に提案されます。データ・マスキングは、誕生日やクレジット・カード番号などの機密情報の列を変換するために使用でき、条件付きマスキングや複合マスキングなどのより複雑なデータ・マスキングのユースケースもサポートできます。  Oracle Databaseで使用可能なセキュリティのテクノロジーや機能により、顧客は高度にセキュアなデータベース環境を維持できます。Oracle Data Safeでは、これらの重要な機能をシンプルなクリックアンドセキュア・インタフェースで使用できるようになりました。セキュリティに関する詳しい専門知識は必要ありません。Data Safeはデプロイメントを必要としないサービスとして提供されるため、顧客はデータベースの保護に関連する運用コストを削減でき、規模に関係なくすべての顧客がデータを安全に維持できます。Data Safeによって、今やまさにセキュリティはクラウドへ移行する理由となりました。 5つの機能のうちの最初の機能であるセキュリティ評価へのドリルダウンを開始しますので、来週の同じ時間にアクセスしてください。Data Safeについての詳細情報は、こちらをご覧ください。このシリーズの最初のブログをお読みでない場合は、パート1を参照して製品の全体的な案内をご覧ください。    ※本記事は、Michael Mesaros (Director of Product Management) による”A Guided Tour of Oracle Data Safe “を翻訳したものです。 AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

  ユーザーは、Oracle Cloudの多くのメリットを利用することを熱望していますが、データの保護に役立つツールへ簡単にアクセスする必要もあります。  ...

無料クラウドへ -AWSからOCIへの移行

先週のOracle Open Worldで、オラクルは驚くべき発表をしました。Oracle Cloudで完全に無料のサービス枠(「Free Tier」)を提供するというものです。Twitterでは批判の声を見かけましたし、本当だろうかと疑っている人もいるでしょう。完全無料だなんて、ウソでしょう?いえ、本当です。完全に無料の枠があるのです。1か月限定ではありません。12か月だけでもありません。ずっと無料です。「Always Free」のサービスにはAutonomous Databaseが含まれ、2つのインスタンス(それぞれ1つのOCPUと20 GBのストレージを搭載)を利用できます。これだけあれば何ができるでしょうか。実にいろいろなことができます――それについては近いうちにまた記事を書きますので、注目しておいてください。2台の仮想マシン(それぞれ1/8 OCPUと1 GBのメモリを搭載)のコンピューティング能力も利用できます。驚くべき速さ、というわけにはいきませんが、一定のアプリケーションを実行するには十分ですから心配は無用です。この点についてもいずれ、ブログに記事を書くつもりです。ストレージも用意されており、2つのブロック・ボリューム(合計100 GB)、10 GBのオブジェクト・ストレージと10 GBのアーカイブ・ストレージ、ロードバランサ(1インスタンス)、帯域幅は10 Mbpsとなります。他も監視、通知、電子メール配信などの機能が提供されます。このチャンスを見逃す手はありません。ぜひ詳しい情報をご覧になり、今すぐにサインアップしてください。確認のためにクレジット・カード情報を入力する必要はありますが、知らないうちに課金されるということはありません。最近、他にもいくつか、クラウド・プロバイダの無料サービスにサインアップしてみたのですが、いずれの場合もまずクレジット・カード情報を登録する必要がありました。 実際に使ってみた 私はOracle Cloudの支持者ですが、開発者の1人ですから(マーケティングや販売の担当ではありません)、まずFree Tierを自分の手で触ってみて、その価値を確かめ、他の開発者にも役立ちそうであると確信してからでなければ、このような記事を書くことはしません。そのようなわけで、私はまず個人アカウントを作成し、自分のプライベートなブログを、Amazon Web ServicesからOracle CloudのFree Tierに移すことにしました。Oracleに入る前は、個人ブログをホストするのにAWSを何年も使っていて、Oracle Cloudに移行しようと動いたことはまだなかったので、今回Free Tierで試してみるというのはうってつけの機会でした。私のブログは非常にシンプルなアプリケーションになっています。データベースにはAmazon RDSでMySQLを使用し、ブログウェアはカスタマイズしたGrailsアプリケーションで、Apache TomcatでWARファイルとしてデプロイしています。イメージのホスティングにはS3、電子メール配信にはAmazon SESを使用しています。移行プランの概要はこうです。 DBをMySQL RDSからAutonomous DBに移行 イメージをS3からOCI Object Storageに移行 電子メール配信をOCI向けのSESに切り替え OCI VMでアプリケーションをデプロイ 最初の手順はもちろん、無料アカウントにサインアップして、新しいDBインスタンスとVMを起動することです。サインアップのプロセスと、最初の無料Autonomous DBインスタンスの起動については、以前に記事を書いていますので、必要であれば参照してください。 DBの移行 DBの移行は、SQL Developerを使用すれば面倒なこともなく、簡単です。SQL Developerでは、ウィザードの案内に従って移行を進めることができます。ただし注意点が1つ。移行を実行するには、いくつかの大きな権限を付与されたユーザーを使用する必要があります。移行を始める前に、このドキュメントをすべて読んでおいてください。いや、正直になりましょう。ドキュメントを最初から最後まで、本当に読みますか?そんなことしませんよね。でも、少なくともこのセクションだけは読んでください。移行時のユーザーに必要な権限について説明されています。  データの移行後には、MySQLではなくOracle DBを使うために、Grailsアプリケーションに少し変更を加える必要がありました。Hibernateの言語の設定を変更する、自動採番のキーではなくシーケンスが使用されるようにする、などの作業です。特別やっかいな作業はありません。アプリケーションのバックエンドを変更する場合は、こうした小さな調整作業は避けられないものです。 オブジェクトをS3から移行 私の場合、移動しなければならないイメージが100個ほどしかなかったので、これは比較的楽な作業でした。S3からすべてを手動でダウンロードし、Oracle Cloud Object Storageに自分でアップロードしました。もっと複雑な移行にも、もちろん対応しています。必要な場合はこちらのホワイトペーパーをご覧ください。オブジェクトの移動が済んだところで、SQLの更新クエリーを実行して、私の全ブログ記事にあるリンクを、OCI Object Storageの新しいリンク先に差し替えました。最後にコードを修正して、S3に指定されているものをOracle Cloudに変える必要がありました。そうすれば、新しくアップロードしたものも、古いAWSのバケットではなく、Object Storageに保存されることになります。私のGrailsアプリケーションはAWS SDKをGrailsプラグイン経由で使用するので、OCI SDK向けに変更しなければならないかと思っていましたが、OCI Object Storageには、既存のAWS SDKで使用できる、互換性のあるS3エンドポイントが用意されているので、問題ありませんでした。プラグインで手を加える必要があったのは、エンドポイントの変更と、いくらかの設定だけでした。私のControllerで、3行のコード(以下の4~6行目)を実行すれば完了です。 次に、Grails Mailプラグインの設定を、AWS SESサーバーからOCIサーバーに切り替えました。コンソールのサイドバーにあるメニュー、「Email Delivery」→「Email Configuration」で設定できます。 このようになりました。 Configurationページの「Manage SMTP Credentials」をクリックすると、ユーザー管理セクションに移動し、アプリケーションで使用する認証情報を生成できます。 アプリケーションのデプロイ さて、この時点で、DBを作成して移行し、オブジェクトを移行し、アプリケーションを構成して、新しい環境で使えるようになりました(Oracle CloudでDB、オブジェクト・ストア、電子メール配信サービスが使えるようになった)。次のステップは、アプリケーション自体のデプロイです。つまりコンピュート・インスタンスの作成が必要になります。まず、コンソールのダッシュボードに戻って、「Create a VM Instance」をクリックします。 インスタンスに名前を付け、OSイメージを選択します。 次に、インスタンスへの接続に使用するSSH公開鍵をアップロードし、「Create」をクリックします。 インスタンスを作成すると、インスタンスの詳細が表示されます。パブリックIPアドレスをメモします。これはマシンにSSH接続する際に使用されます(ユーザー名'opc'と、先ほど指定したSSH鍵を使用)。Webトラフィックを許可するには、受信ルールをいくつか追加する必要があります。ここに表示されているサブネットをクリックします。 サブネットの詳細ページの左のサイドバーで「Security Lists」をクリックし、デフォルトのセキュリティ・リストを選択して編集します。 受信ルールを追加して、ポート80と443のトラフィックを許可します。 これでコンピュート・インスタンスの準備ができました。トラフィックがブロックされている場合は、VM自体でローカルのファイアウォール・ポートを開く必要がある場合もあります。 ここで私は、Tomcatをインストールして、WARファイルをアップロードし、デプロイしました。私の場合、SSLの証明書をセットアップするという追加作業が必要になりましたが、この移行作業もたやすいものでした。 AWSとOCIの比較 さて、この移行で何が成し遂げられたのか、詳しく振り返ってみましょう。 コスト これは回答の出しやすい問題です。私はブログをホストするために、Amazonに毎月35ドル支払う必要がなくなりました。OCIの「常に無料」のサービスは、そう、常に無料です。AWSの無料枠のように、12か月限定ということもありません。 コスト:「常に無料」のOCIが文句なしの勝者です。 コストは重要ですが、他の点も考えてみましょう。 信頼性 AWSの数値データはなかなか見つからないので、比較は困難です。しかし、Autonomous DBは自己保護と自己修復が可能であり、実行中に実際に自らパッチを適用します。SLAでは99.995 %の信頼性が保証されています。1か月あたりの停止時間は2.5分未満ということです(パッチ適用を含む)。AWSの定期メンテナンス、パッチ適用、アップデートは、これにまったく及びません。 信頼性:Autonomous DBとAutonomous OS(Oracle Linux)は停止時間が少なく、Oracle Cloudの方が信頼性が高いことを、データは示しています。勝者はOCIです。  ユーザー・エクスペリエンス スクリーンショットを何枚かご覧ください。それが一番分かりやすいと思います。どちらのコンソールの方が統一感があり、見やすく、整理されていて、使いやすいか、ご自分の目で確かめてほしいのですが、結果は一目瞭然ではないでしょうか。以下のサンプルはすべて、1つ目がOCI、2つ目がAWSの順になっています。 コンピュート・インスタンスの一覧: セキュリティ・ルールの編集: オブジェクト・ストレージ・バケットの一覧。S3のインタフェースは使いやすくなってはいますが、AWSで提供される他のサービスの見た目や使い勝手とはまったく統一が取れていません。 DBインスタンスの作成。こちらも同じく、RDSのインタフェースはすっきりしてはいますが、他のAWSサービスとの統一感はありません。一方、OCIのインタフェースは整然としていて見やすく、統一感もあります。OCIコンソールに慣れてしまえば、ダッシュボードで他のサービスを使用する場合も戸惑うことはありません。Oracle Cloudのその他のサービスと、見た目や操作性が同じだからです。 ユーザー・エクスペリエンス:AWSにも素敵なインタフェースがいくつかありますが(サービスによって異なる)、EC2のように、時代遅れで古くさいものもあります。この分野の勝者はOCIです。OCIのインタフェースは整然としていて見やすく、統一感もあります。すっきりしていて、ごちゃごちゃした感じはありません。これまでのオラクル製品のユーザー・インタフェースの多くは、この点で優れていたとは言いがたいものもありますが、今回は近代的で見やすく、使いやすくなっています。  まとめ オラクルにはFree Tierがあります。本当に、無料です。支払いは一切発生しません。ずっと無料です。すばらしいことです。ぜひ使用すべきです。  Oracle CloudのFree TierでコンピュートおよびAutonomous DBを使用するにあたっての、あなたのアイデアをお聞かせください。共有してくださったアイデアは、今後のブログやビデオでご紹介させていただくことがあります。 Photo by Nghia Le on Unsplash   ※本記事は、Todd Sharp (OracleのDeveloper Advocate) による”Journey To The Free Cloud - Migrating From AWS To OCI“を翻訳したものです。 AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

先週のOracle Open Worldで、オラクルは驚くべき発表をしました。Oracle Cloudで完全に無料のサービス枠(「Free Tier」)を提供するというものです。Twitterでは批判の声を見かけましたし、本当だろうかと疑っている人もいるでしょう。完全無料だなんて、ウソでしょう?いえ、本当です。完全に無料の枠があるのです。1か月限定ではありません。12か月だけでもありません。ずっと無...

Oracle Autonomous Data Warehouse アーキテクチャと戦略:Part2(全3回)

3ブログ・シリーズのパート2:高度なデータ・プラットフォームの設計によるデータ管理のサポート 今日のデータドリブンな世界では、‘スマートな’つまりコグニティブなソリューションがブームになっています。中でも人気なのが、AI、機械学習、データ分析など、ビジネスが‘思考’し、データをより効果的に活用することを支援するソリューションです。何十億もの投資がコグニティブ・ソリューション分野に流れ込むため、これらのコグニティブ・ソリューションは今後数年にわたって広まると予想されます。 しかし、コグニティブ・データ・ソリューションの市場を推進するものは何でしょうか?第一に、データは非常に重要で価値のあるものです。第二に、ビジネス・プロセスをもっと直感的にインテリジェントにして、現代のビジネス環境での競争上の優位性を高めたいという一般的な願望があります。このビジネスのスマート化は、リーダーが市場動向に対応し、カスタマー・エクスペリエンスにプラスの影響を与え、高速で進化し続けるデジタル経済に適応できるようにするために絶対に必要です。このようなスマートなソリューションがないと、ビジネスは停滞し、受け身のまま市場ダイナミクスに反応することになってしまいます。  肝心なこととして、データドリブン・ソリューションの需要が増していることは、さまざまな業界で大量のデータが生成され、デジタル化されていることの直接の結果です。そして、そのデータ・フットプリントはひたすら増加し続けます。この3パートのブログ・シリーズの最初の投稿で、私は世界で生成されるデータ量は2018年の33ゼタバイト(ZB)から2025年には175 ZBに増加すると記しました。これを基に計算すると、世界のデータの90%はこの2年間で生成されたことになります。そして、このデータすべての管理に関する市場の反応として、世界のコグニティブ・ソリューション市場は2018~2022年の期間にほぼ50%のCAGRで成長するだろうとアナリストは予測しています。 説得力のある統計ではありますが、私にどういう関係があるのかと疑問に思われることでしょう。それはもっともで、その理由は次のとおりです。ビジネス・プロセス・データからインサイトを引き出し、データをベースとした予測によって人間による意思決定能力を向上させるのは、これらのコグニティブ・ソリューションなのです。これだけでもかなり重要なことですが、もしあなたが何もする必要がなかったとしたら、つまりデータの取得と処理を自動化できたら、あなたには何ができるかを想像してください。私に言わせれば、それこそがわくわくするような部分(経営陣を関与させる部分)が生まれるときです。 ビジネスがスマートなソリューションを活用し、デジタル・トランスフォーメーションの最先端のレベルの視界で適切な意思決定を行えることで、組織が市場の勢いを真に捉えることができるというのは素晴らしいことです。データウェアハウスの支援によって事前に検索可能なパターンに基づいて、特定の市場でどの製品の調子が良いかが分かることを想像してみてください。また、データや、クライアントとの以前の相互作用に基づいて、小売りやショッピングの体験を動的にカスタマイズできることを想像してみてください。競合の観点からすると、センチメント分析のようなソリューションを使用すると、機械学習を利用することで自社のサービスと同時に、競合他社のサービスに関連する市場センチメントをより深く理解できます。 コグニティブ・ソリューションについて、セキュリティの例があります。AIを使用したセキュリティ機能を使用すると、異常な行動を検出して事前に対応できます。同様に、コグニティブ・システムを使用することで、データ・メトリクスに基づいて不正を検出して阻止することができます。コグニティブ・エンジンについては、スマートで迅速にというのが新たな常識となっています。 Oracle Autonomous Data Warehouseが行うのは、まさにこのことです。Oracle Autonomous Data Warehouseは、応用機械学習を使用して自己チューニングし、データベースの稼働中に自動的にパフォーマンスを最適化します。まさに、提供するサービスや製品の中断と変換をサポートするために市場に対する展望を与えるソリューションを使用しているのです。Oracle Autonomous Data Warehouseは、次世代の自律型テクノロジーで構築されており、人工知能を使用してこれまでにない信頼性、パフォーマンス、そして柔軟性に優れたデータ管理を提供することで、データウェアハウスのデプロイを数秒で実現します。Oracle Autonomous Data Warehouseは、自動的つまり‘自律型’のデータ管理の概念に新たな意味をもたらします。次にその意味を説明します。 自己稼働。もしOracle Autonomous Data Warehouseに車輪があったら、それ自身で操縦をすることでしょう。ただし、ここでの自己稼働の要素は、ネットワーク構成、ストレージ、そしてデータベースのパッチおよびアップグレードを処理する完全に管理されたデータウェアハウスのクラウド・サービスを指します。顧客のDBAは必要ありません。 自己保護。この部分はまさに革命的で、業界では今まで類を見ません。データベースの自己保護部分により、アーキテクチャは常に最新のセキュリティ・パッチを実行できます。また、稼働中であっても、自律的に、すべて自分で異常行動を検出して更新を実行するのです!さらに、保存中のデータは、透過的データ暗号化(TDE)を使用してデフォルトで暗号化されます。最終的に、データベース・クライアントはSSL/TLS 1.2暗号化および相互に認証された接続を使用します。(独自の自己保護アーキテクチャについては、シリーズの3番目のブログで詳しく取り上げます。) 自己修復。誰も停止を経験したくありません。停止は大きなストレスの原因となり、ビジネスの流れに影響して止めてしまうこともあります。Oracle Autonomous Data Warehouseは、停止時間からの自動保護を備え、設計の中核に合わせて構築されています。すべてのコンポーネントに高可用性が組み込まれており、バックアップは完全に自動化されています。これは、活発に稼働して操作を維持するデータ・プラットフォームを入手したことで、夜と週末を取り戻すことができることを意味します。 素晴らしいではありませんか。この自律型のデータ車両のボンネットを開けて、実際にどう動くのかを見てみましょう。 Oracle Autonomous Data Warehouseの仕組み Oracle Autonomous Data Warehouseは、DevOpsプロセス全体への直接的なエンジンおよび統合ポイントです。何より、データドリブンのアプリケーションが機械学習を活用することによって、サードパーティのソリューションと並んでローカル・サービスを使用しながら強力な結果を提供できます。これは、既存の開発者向けツール、データ統合サービス、データ可視化、およびクラウド・オブジェクト・ストレージが、クラウドの能力を利用しながらOracle Autonomous Data Warehouseと簡単に統合することを意味します。 データから最大の価値を引き出すために、必要とされるあらゆる方法でデータを可視化できます。Oracle Data Visualization Desktopを利用するか、自身のサードパーティのビジネス・インテリジェンスやデータ可視化ソリューションを使用してください。 Oracleデータの可視化 最後に、そしてこれがより革命的な部分ですが、Oracleの機械学習は、SQLユーザー向けに設計されたノートブック・アプリケーションを提供し、高度な分析およびデータ・モデルに基づいたレポートの開発、記録、共有、および自動化を可能にするインタラクティブなデータ分析を提供します。 Oracle Machine Learning Notebook Apache ZeppelinテクノロジーをベースとするOracle Machine Learning SQLのノートブックを使用すると、予測モデルや分析手法の構築、評価、デプロイをチームで共同で実施することができます。 そのため、このSQLノートブックは、データ・サイエンティストがOracle Autonomous Data Warehouse(ADW)で機械学習を実行するためのインタフェースとして機能します。これらのノートブック・テクノロジーは、前提条件、アプローチ、根拠の文書化をサポートしながらスクリプトの作成をサポートすることで、データ・サイエンス・チームの生産性を向上させます。 優れたレベルの組込み自動化およびインテリジェント機能により、データウェアハウスを強力な機械学習とコグニティブ・ソリューションに結合できます。これにより、Oracleプラットフォームおよびそのクラウド・サービスのスケーラビリティとパフォーマンスを利用することで、データ・サイエンティスト、開発者、ビジネス・ユーザー間の迅速で容易なコラボレーションが可能になります。 要約しましょう。まとめると、データドリブンの自律型ソリューション、特にOracle Autonomous Data Warehouseには以下のようなメリットがあります。 データおよびデータウェアハウス・リソースの簡素化されたエンド・ツー・エンド管理 高パフォーマンスを含め、データ要件に合わせて完全に調整され‘すぐに使用可能’ アイドル状態のコンピューティング・シャットオフに関するインテリジェント機能による完全に柔軟な拡張 依存性およびリアルタイムのワークロード要件に基づく自動拡張 オンプレミス、ハイブリッド、またはマルチクラウドで実行されるソリューションをサポートする機能 ネイティブまたはサードパーティのデータ統合ツールを利用する機能 高パフォーマンスの問合せと同時ワークロード:さまざまなタイプのユーザー向けに事前構成されたリソース・プロファイルに基づいて、問合せパフォーマンスが最適化 大量のデータを移動する強力なデータ移行ユーティリティ データ・ストレージ、リポジトリ、およびAmazon AWS Redshift、SQL Server、他のデータベースを含む処理エンジンとの緊密な統合 セキュリティに関して不安のある方のために(不安のない方にも)、シリーズのパート3でこの重要なトピックについて取り上げ、そこではAutonomous Data Warehouseがすべてのデータ(休止中および稼働中)を暗号化されたフォーマットで保管する方法について詳述します。 最終的な結論:これからはデータドリブンです。データの準備を整えてください 業種や企業の規模に関係なく、データは未来に影響を与えます。データを利用するだけでなく、利用を簡単にする方法を見つけた組織こそが、デジタル経済において有意義で競争力のあるメリットを目にします。 私の見方では、オラクルのAutonomous Data Warehouseは、柔軟な拡張が可能で、迅速なクエリー・パフォーマンスを実現し、データベース管理を必要としない、使いやすくて完全に自律型のデータベースを提供します。これは、データの使用にまつわる複雑さを排除する種類のテクノロジーです。何よりも、これによって、データの力を真に利用し、データドリブンの未来において革新的で収益を可能にする活動を行うことができます。   ※本記事は、Bill Kleyman(EVP of Digital Solutions, Switch | Industry Influencer) による”The Oracle Autonomous Data Warehouse: Architecting Advanced Data Platforms to Support Data Management“を翻訳したものです。 AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

3ブログ・シリーズのパート2:高度なデータ・プラットフォームの設計によるデータ管理のサポート今日のデータドリブンな世界では、‘スマートな’つまりコグニティブなソリューションがブームになっています。中でも人気なのが、AI、機械学習、データ分析など、ビジネスが‘思考’し、データをより効果的に活用することを支援するソリューションです。何十億もの投資がコグニティブ・ソリューション分野に流れ込むため、これらの...

Database

基本からわかる!高性能×高可用性データベースシステムの作り方 第13回 AWRレポート作成とAWRスナップショット取得(CDB全体)

基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ 第12回では、Oracle Databaseの性能分析をするとき、何を調べるときにどんなツールがあるかを俯瞰しました。今回はその1つ、AWRレポートの作成とAWRスナップショットの取得に関するコマンドラインでの操作についてです。「AWRレポートを提供してください」と言われたときに最低限知っておくべきことに絞って説明します。 AWRレポートとは Automatic Workload Repositoryとは、Oracle Database 10gで導入されたOracleインスタンス全体の実行統計を取得する仕組みです。AWRの機能を使用するためにはEnterprise EditionのDiagnostics Packのライセンスが必要です。Oracle初期化パラメータcontrol_management_pack_accessがDIAGNOSTICS+TUNING(デフォルト)もしくはDIAGNOSTICSである必要があります。 SQL> SHOW PARAMETERS control_management_pack_access NAME                                 TYPE    VALUE ------------------------------------ ------- ------------------- control_management_pack_access       string  DIAGNOSTIC+TUNING   Oracleインスタンスは起動している間、使用したCPU時間やI/O量などの実行統計値を観測しています。AWRスナップショットとは、Oracleインスタンスが起動されてからの累積実行統計値を特定時刻で表にINSERTしたものです。CREATE DATABASEした時点で、デフォルトでAWRスナップショットが1時間に1回取得されるように設定されています。AWRレポートとは、指定した2点のAWRスナップショット間の実行統計を、人間が読むのに適した形に整形したHTMLもしくはテキスト形式のファイルです。   AWRレポートの作成に指定する2点は連続している必要はなく、離れていてもかまいません。例えば24時間離れた2点を指定すると、1日の平均アクティビティを調べることができます。ただし、Oracleインスタンスを停止してしまうと実行統計がリセットされてしまうため、Oracleインスタンス再起動をまたいだ2点を指定したAWRレポートは無効です。 一般的には、性能分析には24時間といった長時間の平均値はあまり役に立ちません。そのため、多くの場合は分析したい時間帯に絞った連続した2点間のAWRレポートを作成することになります。 AWRレポートの作成コマンド AWRレポートの作成にはsqlplusでOracleインスタンスに接続し、AWRレポート作成のSQLスクリプトを実行します。AWRレポートはHTMLもしくはテキスト形式のファイルとして出力されますが、そのファイルはsqlplusを起動したカレント・ディレクトリに作成されるため、ファイルを出力させたいディレクトリに移動してからsqlplusを起動します。管理者権限(SYSまたはSYSTEMユーザー)でログインします。 $ sqlplus / as sysdba コンテナ・データベース構成でこの方法でログインすると、CDB$ROOTにログインしたことになります。CDB$ROOTでAWRレポートを作成すると、Oracleインスタンス全体の、つまりこのコンテナ・データベース上のすべてのプラガブル・データベース(PDB)の統計が出力されます。Oracle Database 12c Release 2からPDBごとのAWRスナップショットの取得やAWRレポートの作成ができるようになっています。今回はPDBごとのAWRの説明はしません。以下の説明はすべてコンテナ・データベース全体の場合のものです。 AWRレポート作成のSQLスクリプトにはいくつかあるのですが、もっとも基本的なものがawrrpt.sqlです。awrrpt.sqlはログインしたデータベースのDBIDとOracleインスタンスでのAWRスナップショットからAWRレポートを作成します。クラスタ構成のOracle Real Application Clusters(RAC)は複数のOracleインスタンスが1つのデータベースをマウントしています。RACでawrrpt.sqlを実行すると、そのsqlplusが接続している1つのOracleインスタンスのAWRレポートを作成します。 sqlplusは@マークを付けたテキストファイルを読み取りそこに記述されているSQLスクリプトを実行します。awrrpt.sqlは$ORACLE_HOME/rdbms/admin/ディレクトリにあります。sqlplusは”?”の記号をORACLE_HOMEのディレクトリと解釈するため以下のように記述できます。 SQL> @?/rdbms/admin/awrrpt awrrpt.sqlを実行するとまず出力するファイル形式を問われます。デフォルトはHTML形式です。 Specify the Report Type ~~~~~~~~~~~~~~~~~~~~~~~ AWR reports can be generated in the following formats.  Please enter the name of the format at the prompt.  Default value is 'html'. 'html'          HTML format (default) 'text'          Text format 'active-html'   Includes Performance Hub active report report_typeに値を入力してください: ファイル形式はtextではなくデフォルトのhtmlをお勧めします。text形式はコピー&ペーストして報告書の作成などには便利ですが、長いSQL文が途中で省略されてしまいます。HTML形式はSQLが全文出力されます。「AWRレポートを提供してください」と言われたときは(デフォルトの)HTML形式のことだと思っておくとよいでしょう。 Instances in this Workload Repository schema ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   DB Id      Inst Num   DB Name      Instance     Host ------------ ---------- ---------    ----------   ------   1650164401     2      RAC19B       rac19bst2    ptvm37.jp.or * 1650164401     1      RAC19B       rac19bst1    ptvm36.jp.or Using 1650164401 for database Id Using          1 for instance number Specify the number of days of snapshots to choose from ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Entering the number of days (n) will result in the most recent (n) days of snapshots being listed.  Pressing <return> without specifying a number lists all completed snapshots. num_daysに値を入力してください: ファイル形式の次はDBIDとOracleインスタンスの指定です。awrrpt.sqlの場合はこれらが今接続しているOracleインスタンスに決め打ちです。 次に入力するnum_daysは何日前のAWRスナップショットまでさかのぼってリストに出すかです。何も入力せずにreturnを押すと記録が残っているすべてのAWRスナップショットがリストされます。以下の例では直近の1日分を出すために1と指定しています。 num_daysに値を入力してください: 1 Listing the last day's Completed Snapshots Instance     DB Name      Snap Id       Snap Started    Snap Level ------------ ------------ ---------- ------------------ ---------- rac19bst1    RAC19B            3191  09 10月 2019 00:00   1                                3192  09 10月 2019 01:00   1                                3193  09 10月 2019 02:00   1                                3194  09 10月 2019 03:00   1                                3195  09 10月 2019 04:00   1                                3196  09 10月 2019 05:00   1                                3197  09 10月 2019 06:00   1                                3198  09 10月 2019 07:00   1                                3199  09 10月 2019 08:00   1                                3200  09 10月 2019 09:00   1                                3201  09 10月 2019 10:00   1                                3202  09 10月 2019 11:00   1                                3203  09 10月 2019 12:00   1                                3204  09 10月 2019 13:00   1                                3205  09 10月 2019 14:00   1                                3206  09 10月 2019 15:00   1                                3207  09 10月 2019 16:00   1 Specify the Begin and End Snapshot Ids ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin_snapに値を入力してください: num_daysを入力するとAWRスナップショットを取得した時刻とそのSnap Idが列挙されます。このSnap Idを2つ指定した間のAWRレポートが作成されます。begin_snapにはレポートする開始時刻のSnap Idを入力します。end_snapは終了時刻のSnap Idです。 Specify the Begin and End Snapshot Ids ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ begin_snapに値を入力してください: 3206 Begin Snapshot Id specified: 3206 end_snapに値を入力してください: 3207 End   Snapshot Id specified: 3207 Specify the Report Name ~~~~~~~~~~~~~~~~~~~~~~~ The default report file name is awrrpt_1_3206_3207.html.  To use this name, press <return> to continue, otherwise enter an alternative. report_nameに値を入力してください: 最後に出力するファイル名を入力します。デフォルトの名前は指定したSnap Idから生成されています。enterを押すとAWRレポートが生成されます。画面にはHTMLが流れますが、それがsqlplusを起動したカレント・ディレクトリにファイルとして記録されます。 <p /> <p />End of Report </body></html> Report written to awrrpt_1_3206_3207.html SQL> これでAWRレポートが生成されました。sqlplusからexitするとカレント・ディレクトリに指定したファイル名で出力されています。 $ ls *.html awrrpt_1_3206_3207.html 自動取得されるAWRスナップショットの制御 ここからは、AWRスナップショットの取得を制御する方法について説明します。Oracle Database Enterprise Editionでは、デフォルトでAWRスナップショットが定期的に取得されており、それは1時間ごとで保存期間は8日です。その設定はDBA_HIST_WR_CONTROLビューで確認することができます。 SQL> SELECT SNAP_INTERVAL,RETENTION FROM DBA_HIST_WR_CONTROL; SNAP_INTERVAL        RETENTION -------------------- -------------------- +00000 01:00:00.0    +00008 00:00:00.0 本番運用するデータベースでは、性能問題が発生した場合に、過去の問題がなかった時点の性能統計と比較することが問題個所の特定に役立つことがあります。保存期間をデフォルトの8日よりもかなり大きな値にしておくのはよくある運用です。また、取得間隔は狭いほどその時間帯の事象の解像度があがります。そのため自動取得される間隔をデフォルトの1時間よりも短い15分や30分にするのもまたよくある運用です。 AWRスナップショットの自動取得間隔と保存期間を変更するにはDBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGSプロシージャを使用します。設定単位は分です。以下の例は取得間隔(interval)を30分、保存期間(retention)を44640分(=60分×24時間×31日)に設定しています。 SQL> EXEC DBMS_WORKLOAD_REPOSITORY.MODIFY_SNAPSHOT_SETTINGS (interval=>30,retention=>44640); PL/SQLプロシージャが正常に完了しました。 SQL> SELECT SNAP_INTERVAL,RETENTION FROM DBA_HIST_WR_CONTROL; SNAP_INTERVAL        RETENTION -------------------- -------------------- +00000 00:30:00.0    +00031 00:00:00.0 AWRスナップショットの手動取得 性能テストを行うような場合、テスト開始と終了の間の時間帯に限定したAWRレポートを作成したくなります。そのためにはテストの開始と終了の時点でAWRスナップショットを取得しておきます。DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOTプロシージャを実行すると、その時点のAWRスナップショットが取得されます。 SQL> EXEC DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT; PL/SQLプロシージャが正常に完了しました。 Webでよくみかけるのはこのプロシージャ実行の方法です。 AWRレポートを作成するにはスナップショットIDの指定が必要になりますが、レポートを作成するためにawrrpt.sqlを実行したときに取得時刻とスナップショットIDを目視で突合するのは少し不便です。CREATE_SNAPSHOTには実はプロシージャだけではなく、ファンクションもあります。この「ファンクション」の戻り値はスナップショットIDです。そのため、以下のSELECT文を実行するとAWRスナップショットが取得され、そのスナップショットIDが返ります。 SQL> SELECT DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT() FROM DUAL; DBMS_WORKLOAD_REPOSITORY.CREATE_SNAPSHOT() ------------------------------------------                                       3258 まとめ 今回は「AWRレポートを提供してください」と言われたときに最低限知っておくべきことに絞って説明しました。 AWRレポートを作成するためには管理者権限(SYSまたはSYSTEMユーザー)でログインし、SQLスクリプト$ORACLE_HOME/rdbms/admin/awrrpt.sqlを実行します。ファイル形式はtextと依頼されない限りデフォルトのHTMLがよいでしょう。レポートを作成したい時間帯の開始と終了の2点のスナップショットIDを指定します。 基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ  

基本からわかる!高性能×高可用性データベースシステムの作り方 indexページ 第12回では、Oracle Databaseの性能分析をするとき、何を調べるときにどんなツールがあるかを俯瞰しました。今回はその1つ、AWRレポートの作成とAWRスナップショットの取得に関するコマンドラインでの操作についてです。「AWRレポートを提供してください」と言われたときに最低限知っておくべきことに絞って説明します。...

Japan Oracle User Group (JPOUG) Oracle Databaseを中心とした座談会’19

    去る2019年5月17日に開催された Oracle Code Tokyo 2019 は、大勢の方にご来場いただき、大盛況のうちに終了することができました。 ご多忙中、足をお運びくださいました皆様 この場をお借りして改めて御礼申し上げます。 Oracle Code Tokyo 2019 講演資料ダウンロードページ:こちら Oracle Code Tokyo 2019においてJPOUGによるセッションが開催され、Oracle Database 19cをテーマに深く語りあっていただきました。 この座談会にて使用されたスライドと登壇者発言録および参加された会場のみなさんとのかけあいがまとめられたものを、JPOUGメンバーの方々から『Oracle Databaseを中心とした座談会'19』レポートとして書き下ろしていただきました。 ぜひご覧いただき当日の雰囲気含め楽しんでいただければと思います。 『Oracle Databaseを中心とした座談会'19』レポート * Japan Oracle User Group (JPOUG)は、Oracle Databaseを中心にMySQLやJavaなどのオラクル製品およびサービスはもちろんIT関連技術全般にわたる情報交換の場です。技術者やユーザーが主体となって世界のオラクル・ユーザー・グループの一員として活動しています。 JPOUGホームページ:http://www.jpoug.org/ * JPOUG主催のイベントの開催案内は、以下のコミュニティサイトを通じて登録者の方に通知されます。イベントやセミナーに参加してみたい方やJPOUGの活動に興味のある方は、ぜひメンバー登録をお願いします。 JPOUG Doorkeeperコミュニティ :https://jpoug.doorkeeper.jp/   AutonomousDatabaseを無期限 / 無料(Always Free)で使用可能になりました。 Cloudをまだお試しでない方は、無料トライアルをご利用下さい。  

    去る2019年5月17日に開催された Oracle Code Tokyo 2019 は、大勢の方にご来場いただき、大盛況のうちに終了することができました。 ご多忙中、足をお運びくださいました皆様 この場をお借りして改めて御礼申し上げます。 Oracle Code Tokyo 2019 講演資料ダウンロードページ:こちら Oracle Code Tokyo...

もしもみなみんがDBをクラウドで動かしてみたら

window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-159254751-1'); 本連載では、主にOracle CloudのOracle Database関連サービスをまだ触ったことがない方を対象に、Oracle Cloud 上でOracle Databaseを利用するためのステップや関連機能、Tipsなどをお届けしていきます。実際に触っていただく際のご参考にしていただければ幸いです。   著者紹介 南野 英梨子(みなみの えりこ) 日本オラクルに新卒で入社。以来、主にOracle Maximum Availability Architecture(MAA)に関わる機能や製品を担当。特に好きなのは、Oracle Active Data Guard や Oracle GoldenGate。Oracle Database の魅力やベストプラクティス、そしてそれを簡単に使えるOracle Cloudの魅力をお客様に伝えようと、日々邁進中。 目次 第1回 [OCI Classic] Oracle Database Cloud Serviceを使ってみよう 2017.9.20 公開 第2回 [OCI Classic] Oracle Database Cloud Serviceの中身をみてみよう 2017.10.20公開 第3回 [OCI Classic] 状態を見てみよう - モニタリングツール 2017.11.25公開 第4回 [OCI Classic] 必要な時に必要なだけ - リソース拡張 2017.12.18公開 第5回 [OCI Classic] 可用性構成を作ってみよう - Real Application Clusters 編 2018.1.26公開 第6回 [OCI Classic] 可用性構成を作ってみよう - Data Guard 編 - 2018.3.27公開 第7回 [OCI Classic] バックアップ&リカバリ 2018.4.23公開 第8回 [OCI Classic] 環境を複製してみよう 2018.7.20公開 第9回 Oracle Cloud InfrastructureでOracle Databaseを使ってみよう 2018.12.20公開 第10回 Oracle Cloud Infrastructure Exadata を使ってみよう 2019.1.24公開 第11回 Oracle Cloud Infrastructure Exadata の構成について 2019.4.19公開 第12回 リソース追加してみよう - スケール・アップ/ダウン OCI Exadata 編 2019.5.17公開 第13回 リソース追加してみよう - スケール・アップ/ダウン Autonomous Database 編 2019.5.17公開 第14回 Oracle Cloud Infrastructure Database を使ってみよう 2019.8.28公開 第15回 Autonomous Databaseで自動スケーリングを設定してみよう 2019.11.20公開 第16回 サービス制限について 2019.12.15公開 第17回  課金と停止について - Autonomous Database/DBCS/ExaCS 2020.02.25公開   Oracle Cloud Infrastructure Database 関連リンク Oracle Cloud Infrastructure (OCI) ・Oracle Cloud Infrastructure 概要 ・Oracle Cloud Platform ご利用ガイド (使い始めていただく方へ) /Onboarding Session ・チュートリアル : Oracle Cloud Infrastructure を使ってみよう ・Oracle Cloud(PaaS/IaaS) : セミナー情報  ・マニュアル Oracle Cloud Infrastructure Document 英語 / 日本語 ・リリース・ノート 英語 ・Oracle Cloud Infrastructure トレーニング -オンデマンド・ビデオ/学習ラボ/資格など OCI Database サービス全体 ・サービス概要 Oracle Cloud Database Services  ・Oracle Database Cloud Service - 概要/価格/マニュアル/トライアル/事例 ・マニュアル Oracle Cloud Infrastructure Document Database 英語 / 日本語 ・Oracle Cloud Infrastructure 上で利用可能なOracle Databaseのサービスの比較 Autonomous Database ・サービス概要 Autonomous Data Warehouse / Autonomous Transaction Processing  ・Oracle Autonomous Data Warehouse Cloud(ADW) - 概要/価格/マニュアル/トライアル/事例 ・マニュアル Oracle Cloud Infrastructure Document Autonomous Database 英語 / 日本語 ・Autonomous Database 技術詳細 ・Autonomous Database サービス・アップデート ・しばちょう先生連載 番外編  Autonomous Database = 究極のOracle Database OCI Database - VM/BM (DBCS)  ・サービス概要 Database Cloud Service Virtual Machine / Bare Metal  ・Oracle Database Cloud Service - 概要/価格/マニュアル/トライアル/事例 ・マニュアル Oracle Cloud Infrastructure Document Database VM/BM 英語 / 日本語 ・使ってみよう!Oracle Cloud Infrastructure - Database OCI Exadata Cloud Service (ExaCS) ・サービス概要 Exadata Cloud Service ・Oracle Exadata Cloud Service - 概要/価格/マニュアル/トライアル/事例 ・マニュアル Oracle Cloud Infrastructure Document Exadata 英語 / 日本語 Gen 2 Exadata Cloud at Customer (ExaCC) ・サービス概要 Exadata Cloud at Customer ・マニュアル Oracle Cloud Infrastructure Document Exadata Cloud at Customer 英語 / 日本語 Oracle Cloud を今すぐ始める! Always Free サービス Oracle Cloud Free Tier + 30日間無償トライアルはこちら      

本連載では、主にOracle CloudのOracle Database関連サービスをまだ触ったことがない方を対象に、Oracle Cloud 上でOracle Databaseを利用するためのステップや関連機能、Tipsなどをお届けしていきます。実際に触っていただく際のご参考にしていただければ幸いです。   著者紹介 南野 英梨子(みなみの えりこ)日本オラクルに新卒で入社。以来、主にOracle...