背景
Springbootは、今日で最も主流のJava Web開発フレームワークの1つになりました。 MyBatisは非常に軽量で使いやすいORMフレームワークです。 Redisは、今日の非常に主流の分散キー価値データベースです。 Web開発では、それを使用してデータベースのクエリ結果をキャッシュします。
このブログでは、Springbootを使用してWebアプリケーションをすばやく構築し、MyBatisをORMフレームワークとして使用する方法を紹介します。パフォーマンスを改善するために、MyBatisの2番目のレベルキャッシュとしてRedisを使用します。コードをテストするために、ユニットテストを作成し、H2インメモリデータベースを使用してテストデータを生成しました。このプロジェクトを通じて、読者が現代のJava Web開発のスキルとベストプラクティスをすばやく習得できることを願っています。
この記事のサンプルコードは、github:https://github.com/lovelcp/spring-boot-mybatis-with-redis/tree/masterでダウンロードできます。
環境
開発環境:MAC 10.11
IDE:Intellij 2017.1
JDK:1.8
スプリングブート:1.5.3.Release
Redis:3.2.9
mysql:5.7
スプリングブート
新しいプロジェクトを作成します
まず、スプリングブートプロジェクトを初期化する必要があります。 IntellijのSpring Initializerを通じて、新しいスプリングブートプロジェクトを簡単に作成できます。まず、Intellijで新しいプロジェクトを選択します。
次に、インターフェイスで依存関係を選択するには、Web、MyBatis、Redis、MySQL、H2をチェックしてください。
新しいプロジェクトが成功した後、下の図に示すように、プロジェクトの初期構造を確認できます。
Spring Initializerは、スタートアップクラスを自動的に生成するのに役立ちました - SpringBootMyBatisWithRedisApplication。このクラスのコードは非常に簡単です:
@SpringBootApplicationPublic Class SpringBootmyBatisWithRedisApplication {public static void main(String [] args){springApplication.run(SpringBootmyBatisWithRedisApplication.class、args); }}@SpringBootApplication Annotationとは、Spring Bootの自動構成機能を有効にすることを意味します。さて、私たちのプロジェクトのスケルトンは、興味のある読者がIntellijを通じて結果を開始できるように成功しているため、成功裏に構築されました。
新しいAPIインターフェイスを作成します
次に、Web APIを書きます。当社のWebエンジニアリングが、商人の製品(製品)の処理に責任があるとします。製品IDに基づいて製品情報を返すGETインターフェイスと、製品情報を更新するプットインターフェイスを提供する必要があります。最初に、製品ID、製品名、価格を含む製品クラスを定義します。
パブリッククラスの製品実装シリアル化可能{private static final long serialversionuid = 143551595276255188l;プライベートロングID;プライベート文字列名;プライベートの長い価格; //ゲッターセッター}次に、コントローラークラスを定義する必要があります。 Spring BootはSpring MVCを内部的にWebコンポーネントとして使用するため、注釈を通じてインターフェイスクラスをすばやく開発できます。
@RestController @requestMapping( "/product")public class productcontroller {@getMapping( "/{id}")public product getProductinfo( @pathvariable( "id")long productid){// todo return null; } @putMapping( "/{id}")public product updationproductinfo( @pathvariable( "id")long productid、@requestbody product newproduct){// todo return null; }}上記のコードで使用されている注釈の関数を簡単に紹介しましょう。
@RestController:クラスがコントローラーであり、RESTインターフェイスを提供することを意味します。つまり、すべてのインターフェイスの値はJSON形式で返されます。この注釈は、実際には@Controllerと@ResponseBodyの注釈を組み合わせたものであり、REST APIの開発を促進します。
@RequestMapping、@getMapping、@putMapping:インターフェイスのURLアドレスを表します。クラスで注釈付けされた@RequestMappingアノテーションは、クラスの下のすべてのインターフェイスのURLが /製品から始まることを意味します。 @getMappingは、これがget httpインターフェイスであることを意味します。
@PathVariable、@RequestBody:パラメーターのマッピング関係を表します。 get request Access /product /123を想定すると、リクエストはgetProductinfoメソッドによって処理され、URLの123がProductIDにマッピングされます。同様に、それがプットリクエストの場合、要求された本体は新しい製品オブジェクトにマッピングされます。
ここでは、インターフェイスのみを定義します。実際の処理ロジックはまだ完了していません。これは、製品の情報がデータベースに存在するためです。次に、MyBatisをプロジェクトに統合し、データベースと対話します。
MyBatisの統合
データソースを構成します
まず、構成ファイルでデータソースを構成する必要があります。 MySQLをデータベースとして使用します。ここでは、YAMLを構成ファイルの形式として使用します。リソースディレクトリに新しいapplication.ymlファイルを作成します。
スプリング:#データベース構成データソース:url:jdbc:mysql:// {your_host}/{your_db} username:{your_username}パスワード:{your_password} driver-class-name:org.gjt.mm.m.mysql.driverSpring Bootには自動構成機能があるため、新しいDataSource構成クラスを作成する必要はありません。 Spring Bootは、構成ファイルを自動的にロードし、構成ファイル情報に基づいてデータベース接続プールを確立します。これは非常に便利です。
著者は、YAMLを構成ファイル形式として使用することを推奨しています。 XMLは長く見え、プロパティには階層構造がありません。 Yamlは、両方の欠点を補うだけです。これが、Spring BootがデフォルトでYAML形式をサポートする理由でもあります。
MyBatisを構成します
Spring InitializerからPOM.xmlのMyBatis-Spring-Boot-Starteライブラリを導入しました。これにより、MyBatisの初期化が自動的に役立ちます。まず、application.ymlでmybatisの関連する構成を記入します。
#mybatis構成mybatis:#マッピングクラスが配置されている場所のパッケージ名を構成しますtype-aliase-package:com.wooyoo.learning.dao.domain#マッパーXMLファイルが配置されているパスを構成します。
次に、コード内のProductMapperクラスを定義します。
@mapperpublic interface productmapper {product select(@param( "id")long id); void update(製品製品);}ここでは、@mapperアノテーションを追加する限り、Spring BootはMyBatisを初期化するときに自動的にマッパークラスをロードします。
Spring Bootが非常に人気がある最大の理由は、自動構成機能です。開発者は、個々のコンポーネントを初期化する方法を気にせずにコンポーネントの構成(データベース接続情報など)に注意を払う必要があります。これにより、ビジネスの実装に焦点を合わせて開発プロセスを簡素化できます。
データベースへのアクセス
MyBatis構成を完了したら、インターフェイスのデータベースにアクセスできます。 ProductControllerの下で@Autowiredを介してMapperクラスを紹介し、対応するメソッドを呼び出して、製品のクエリと更新操作を実装します。ここでは、クエリインターフェイスを例として取ります。
@retscontroller @requestmapping( "/crodce")public class productcontroller {@autowired privatemapper productmapper; @getMapping( "/{id}")Public Product getProductinfo( @pathvariable( "id")long productid){return productmapper.select(productId); } //長すぎて避けて、updateproductinfoのコードを省略します}次に、いくつかの製品情報をMySQLに挿入すると、プロジェクトを実行してクエリが成功しているかどうかを確認できます。
これまでのところ、MyBatisをプロジェクトに統合し、データベースと対話する機能を追加しました。しかし、それで十分ではありません。最新のWebプロジェクトは、キャッシュでデータベースクエリを間違いなく高速化します。次に、RedisをMyBatisのセカンダリキャッシュに科学的に統合して、データベースクエリの自動キャッシュを実現する方法を紹介します。
統合レディス
Redisを構成します
データベースにアクセスするのと同じように、Redis接続情報を構成する必要があります。次の構成をApplication.ymlファイルに追加します。
春:Redis:#Redisデータベースインデックス(デフォルトは0)。インデックス3のデータベースを使用して、他のデータベースデータベースとの競合を回避します。3#Redisサーバーアドレス(デフォルトはローカルホスト)ホスト:localhost#redisポート(デフォルトは6379)ポート:6379#Redisアクセスパスワード(NULL)最大アクティブ:8#アイドル接続の最大数(デフォルトは8、負の数値は無限)最大項目:8#アイドル接続の最小数(デフォルトは0、この値は有効です)最大接続待合時間を取得する接続プール(デフォルトは-1、ユニットはミリセコンド、負の数字は無限になります)。
上記のすべてが一般的に使用される構成であり、読者はコメント情報を使用して各構成項目の特定の役割を理解できます。 POM.xmlにSpring-Boot-Starter-Data-Redisライブラリを導入したため、Spring BootはRedis接続と特定の構成クラスを自動的にロードするのに役立ちます
org.springframework.boot.autoconfigure.data.redis.redisautoconfiguration。このConfigurationクラスを通じて、基礎となるレイヤーがデフォルトでJedisライブラリを使用し、redistemplateとStringTemplateをボックスから提供することがわかります。
Redisをレベル2キャッシュとして使用します
Mybatisの二次キャッシュの原則については、この記事では説明しません。読者は、MyBatisのセカンダリキャッシュがデータベースクエリを自動的にキャッシュできることを知る必要があり、データを更新するときにキャッシュを自動的に更新できることを知る必要があります。
MyBatisの二次キャッシュの実装は非常に簡単です。 org.apache.ibatis.cache.cacheインターフェイスを実装するために新しいクラスを作成するだけです。
このインターフェイスには5つの方法があります。
string getId():mybatisキャッシュ操作オブジェクトの識別子。マッパーは、MyBatisキャッシュ操作オブジェクトに対応します。
void putobject(オブジェクトキー、オブジェクト値):クエリの結果をキャッシュに詰めます。
Object GetObject(Object Key):キャッシュからキャッシュクエリの結果を取得します。
Object RemoveObject(Object Key):対応するキーと値をキャッシュから削除します。ロールバックするときにのみ発射されました。一般的に、実装する必要はありません。特定の使用方法については、org.apache.ibatis.cache.decorators.transactionalcacheを参照してください。
void clear():更新が発生したときにキャッシュをクリアします。
int getsize():オプションの実装。キャッシュの数を返します。
readwriteLock getReadWritelock():オプションの実装。原子キャッシュ操作を実装するために使用されます。
次に、キャッシュインターフェイスを実装するための新しい再発行クラスを作成します。
パブリッククラスの再発行性はcache {private static final logger logger = loggerfactory.getLogger(rediscache.class);プライベート最終readwritelock readwritelock = new ReentrantreadWritelock();プライベート最終文字列ID; // Cache Instance ID Private Redistemplate Redistemplate;プライベート静的最終long expire_time_in_minutes = 30; // redis expiration time public rediscache(string id){if(id == null){throw new IllegalargumentException( "Cache Instances required required id"); } this.id = id; } @Override public String getId(){return id; } / ** *クエリの結果をRedis * * @param key * @param value * / @override @suppresswarnings( "unchecked")public void putobject(object key、object value){redistemplate redistemplate = getredistemplate(); valueperations opsforvalue = redistemplate.opsforvalue(); opsforvalue.set(key、value、expire_time_in_minutes、timeunit.minutes); logger.debug( "redisにクエリ結果を置く"); } / ** * redisのキャッシュクエリの結果を取得 * * @param key * @return * / @Override public object getObject(object key){redistemplate redistemplate = getRedistemplate(); valueperations opsforvalue = redistemplate.opsforvalue(); logger.debug( "redisからのキャッシュクエリの結果を取得"); return opsforvalue.get(key); } / ** * redisからキャッシュクエリの結果を削除 * * @param key * @return * / @override @suppresswarnings( "unchecked")public object remaidObject(object key){redistemplate redistemplate = getRedistemplate(); redistemplate.delete(key); logger.debug( "redisからキャッシュクエリの結果を削除"); nullを返します。 } / ** *このキャッシュインスタンスをクリア * / @Override public void clear(){redistemplate redistemplate = getRedistemplate(); redistemplate.execute((rediscallback)connection-> {connection.flushdb(); return null;}); logger.debug( "Redisからのすべてのキャッシュクエリの結果をクリア"); } @Override public int getSize(){return 0; } @Override public readwriteLock getReadWritelock(){return readwritelock; } private redistemplate getRedistemplate(){if(redistemplate == null){redistemplate = applicationContextholder.getBean( "redistemplate"); } Redistemplateを返します。 }}上記のコードのいくつかの重要なポイントを説明させてください。
実装する2番目のレベルのキャッシュには、IDを備えたコンストラクターが必要です。そうしないと、エラーが報告されます。
スプリングカプセル化された再装備を使用して、Redisを動作させます。レベル2の二次キャッシュをRedisに紹介するすべての記事は、Jedis Libraryを直接使用していますが、著者はこれで十分な春のスタイルではないと考えています。さらに、Redistemplateは、基礎となる実装をカプセル化します。将来Jedisを使用しない場合は、上部コードを変更せずに基礎となるライブラリを直接交換できます。より便利なのは、RediStemplateを使用してRedis接続のリリースを気にする必要がないことです。そうしないと、初心者が接続をリリースし、アプリケーションが停止するのを忘れてしまいます。
再課税はスプリングコンテナの豆ではないため、自動車を介して再装備することはできないことに注意する必要があります。したがって、この豆を取得するには、コンテナのGetBeanメソッドを手動で呼び出す必要があります。特定の実装方法については、GitHubのコードを参照してください。
使用するRedisシリアル化方法は、デフォルトのJDKシリアル化です。したがって、データベースクエリオブジェクト(製品クラスなど)は、シリアル化可能なインターフェイスを実装する必要があります。
このようにして、スプリングスタイルのエレガントで科学的でRedisキャッシュクラスを実装します。
レベル2キャッシュをオンにします
次に、ProductMapper.xmlでレベル2キャッシュを有効にする必要があります。
<?xml version = "1.0" encoding = "utf-8"?> <!doctype mapper public " - // mybatis.org//dtd mapper 3.0 // en" "http://mybatis.org/dtd/mybatis-3-mapper.dtd namespace = "com.woooyoo.learning.dao.mapper.productmapper"> <! - redisベースのセカンダリキャッシュを有効にする - > <キャッシュタイプ= "com.wooyoo.lediscache"/> <select id = "resulttype =" product "> select * select * parametertype = "crodce" flushcache = "true">更新製品set name =#{name}、price =#{price} where id =#{id} limit 1 </update> </mapper><cache type = "com.woooyoo.learning.util.rediscache"/>は、Redisベースのセカンダリキャッシュを有効にすることを意味し、更新ステートメントではFlushcacheをTrueに設定するため、製品情報を更新すると、キャッシュを自動的に無効にすることができます(基本的に、明確な方法が呼び出されます)。
テスト
H2メモリデータベースを構成します
この時点で、すべてのコード開発を完了しました。次に、コードの品質をテストするためにユニットテストコードを記述する必要があります。開発プロセスでは、MySQLデータベースを使用し、一般的にテスト中にメモリ内データベースを使用しました。ここでは、テストシナリオで使用されるデータベースとしてH2を使用します。
また、H2を使用するのは非常に簡単です。MySQLを使用するときに構成するだけです。 Application.ymlファイル:
---スプリング:プロファイル:テスト#データベース構成データソース:URL:JDBC:H2:H2:MEM:テストユーザー名:ルートパスワード:123456ドライバークラス名:org.H2.ドライバースキーマ:クラスパス:schema.sqlデータ:クラスパス:data.sql
デフォルトの構成との競合を回避するために、新しい段落を開始し、プロファイルを使用して使用します。これがテスト環境の構成であることを示すテストです。次に、@ActiveProfiles(profiles = "TEST")の注釈をテストクラスに追加して、テスト環境で構成を有効にして、ワンクリックでMySQLデータベースからH2データベースに切り替えることができます。
上記の構成では、schema.sqlを使用してテーブル作成ステートメントを保存し、data.sqlを使用して挿入データを保存します。このようにして、テストすると、H2はこれら2つのファイルを読み取り、必要なテーブル構造とデータを初期化し、テストの最後に破壊します。これはMySQLデータベースに影響を与えません。これは、メモリ内データベースの利点です。また、pom.xmlでテストするためにH2の依存関係の範囲を設定することを忘れないでください。
Spring Bootの使用は簡単です。コードを変更せずに、さまざまな環境でデータベースを簡単に切り替えることができます。
テストコードの作成
Spring Initializerまで初期化されているため、すでにテストクラス-SpringBootMyBatisWithRedisApplicationSがあります。
Spring Bootは、TestRestTemplateなどのWebインターフェイステストを実施できるようにするツールクラスを提供します。次に、構成ファイルで、ログレベルを調整してデバッグを調整して、デバッグログの観察を容易にします。特定のテストコードは次のとおりです。
@runwith(springrunner.class)@springboottest(webenvironment = springboottest.webenvironment.random_port)@activeProfiles(profiles = "test")public class springbootmybatiswithidisapplicationtests {@localserverport private int port; @autowired private testRestTemplate RESTEMPLATE; @test public void test(){long productid = 1;製品製品= RESTTEMPLATE.GETFOROBJECT( "http:// localhost:" + port + "/product/" + productid、froduct.class); assertthat(product.getprice())。isequalto(200); Product NewProduct = new Product(); long newprice = new Random()。nextlong(); newProduct.setName( "new Name"); newProduct.setPrice(NewPrice); RESTTEMPLATE.put( "http:// localhost:" + port + "/product/" + productId、newProduct); Product TestProduct = retttemplate.getForObject( "http:// localhost:" + port + "/product/" + productid、froduct.class); assertthat(testproduct.getPrice())。isequalto(newPrice); }}上記のテストコードで:
最初にGETインターフェイスを呼び出し、Assertステートメントを使用して、予想されるオブジェクトが取得されたかどうかを判断します。この時点で、製品オブジェクトはRedisに保存されます。
次に、Putインターフェイスを呼び出して製品オブジェクトを更新すると、Redisキャッシュが無効になります。
最後に、GETインターフェイスを再度呼び出して、新しい製品オブジェクトを取得したかどうかを判断します。古いオブジェクトが取得された場合、キャッシュが無効なコードが実行されず、コードにエラーがあることを意味します。そうしないと、コードが問題ないことを意味します。
ユニットテストを書くことは、良いプログラミング習慣です。あなたには一定の時間がかかりますが、将来的にいくつかのリファクタリング作業を行う必要がある場合、過去にユニットテストを書いたことに感謝します。
テスト結果を表示します
Intellijでテストケースを実行するためにクリックします。テスト結果は次のとおりです。
緑が表示され、テストケースが正常に実行されたことを示します。
要約します
この記事では、Spring Boot、MyBatis、Redisを使用して最新のWebプロジェクトをすばやく構築する方法を紹介し、Spring Bootでユニットテストを優雅に記述する方法を紹介して、コードの品質を確保します。もちろん、このプロジェクトには別の問題があります。つまり、MyBatisのレベル2キャッシュは、DB全体を洗い流すことによってのみ無効にされる可能性があります。現時点では、無効化する必要のない一部のキャッシュも無効になる可能性があるため、特定の制限があります。