システムアーキテクト~My batis編~

14,578 views
14,919 views

Published on

うらがみがJavaまわりのORMを知りたい会

Published in: Software
0 Comments
15 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
14,578
On SlideShare
0
From Embeds
0
Number of Embeds
7,585
Actions
Shares
0
Downloads
23
Comments
0
Likes
15
Embeds 0
No embeds

No notes for slide

システムアーキテクト~My batis編~

  1. 1. 本日のお話
  2. 2. MyBatis
  3. 3. 数億を超える 社内きっての大規模プロジェクト
  4. 4. 可用性 99.99%  絶対に止まらないシステム データ件数 2億件  ビックデータへの対応 連携装置 3万台  負荷に対応できるシステム
  5. 5. このプロジェクトに MyBatisで挑みました! (`・ω・)
  6. 6. 本日は ・MyBatisの紹介 ・プロジェクトに適用した  MyBatisの技術事例 についてお話をしよう と思います!
  7. 7. つまりですね
  8. 8. これは、高可用・大規模プロジェクトに挑んだ 知られざるシステムアーキテクトの話である
  9. 9. 主題歌「地上の星」 中島 みゆき
  10. 10. 一般的な中堅SIer 社内きっての 大規模プロジェクト
  11. 11. 可用性 99.99% 許される年間停止時間 53分未満
  12. 12. 現行システムに性能遅延 連 携 装 置 3 万 台
  13. 13. デー タ 件 数     2 億 件 以 上 ! 移 行 時 も シ ス テ ム 停 止 は 許 さ れ な い !
  14. 14. インフルエンザ の猛威! 次々倒れるチームメンバ (平均年齢35才) 新チーム結成
  15. 15. シスアーキ の意地! 負荷テストで システムダウン!
  16. 16. 迫られるO/R Mapperの 選択 MyBatisで行く!
  17. 17. 押し寄せる 寝不足 ドラクエX
  18. 18. 挑め!99.99%! ~大規模プロジェクトに見る  MyBatisの技術事例~ presents by
  19. 19. すいません お待たせしました m(__)m
  20. 20. オープニングは前回の 使いまわしです。 # もう一度使ってみたかった
  21. 21. ちなみに
  22. 22. 可用性 99.99%! データ件数 2億件! 連携装置 3万台! をどのように実現したのか
  23. 23. 可用性 99.99%! データ件数 2億件! 連携装置 3万台! をどのように実現したのか などの話はしません
  24. 24. 話すのはMyBatisの内容ね
  25. 25. 難しい話はできません
  26. 26. ごめんね
  27. 27. MyBatis 自己紹介自己紹介 <名前> こざけさんじゅうはっさい <メッセージ> はい、ビールが好きです! Twitter@s_kozake <最近のお気に入り> ニャンコ先生
  28. 28. MyBatis MyBatis #とは MyBatis入門 MyBatisの活用事例 まとめ AgendaAgenda
  29. 29. MyBatis MyBatis #とは MyBatis入門 MyBatisの活用事例 まとめ AgendaAgenda
  30. 30. MyBatis MyBatis #とは ・XMLまたはアノテーションを用いてストアドプロシージャ  やSQL文をオブジェクトと紐付ける永続性フレームワーク ・Apache License 2.0によるオープンソースソフトウェアとして提供 ・以前はiBATISとして知られていた wikiより転載 http://ja.wikipedia.org/wiki/MyBatis
  31. 31. MyBatis MyBatis #とは ・他のO/Rマッピングフレームワークとは異なりデータベースと  オブジェクトをマッピングするのではなく、SQL文とオブジェクト  のマッピングを行う ・レガシーな環境や非正規化されたデータベース、またはSQL文  の実行を完全に制御したい場合に、よい選択肢となる ・一番の特徴は、XMLに記述したSQL文を普通のオブジェクト  と組み合わせられることである wikiより転載 http://ja.wikipedia.org/wiki/MyBatis 特徴
  32. 32. MyBatis MyBatis #とは ・他のO/Rマッピングフレームワークとは異なりデータベースと  オブジェクトをマッピングするのではなく、SQL文とオブジェクト  のマッピングを行う ・レガシーな環境や非正規化されたデータベース、またはSQL文  の実行を完全に制御したい場合に、よい選択肢となる ・一番の特徴は、XMLに記述したSQL文を普通のオブジェクト  と組み合わせられることである wikiより転載 http://ja.wikipedia.org/wiki/MyBatis 特徴 プロジェクトにMyBatisを 採用した理由は この特徴が大きいです。
  33. 33. MyBatis MyBatis #とは MyBatis入門 MyBatisの活用事例 まとめ AgendaAgenda
  34. 34. MyBatis MyBatis入門 ・「例示は理解の試金石」 by 数学ガール ・MyBatisのSimpleなサンプル実装をMyBatisの概念図と  紐付けて示します。
  35. 35. MyBatis MyBatis #とは 用意したDB ID INT (PK) NAME VARCHAR(100) SEX CHAR(1) COMMENT CLOB CREATED TIMESTAMP ユーザ(USER) ID INT (PK) NAME VARCHAR(100) アイテム(ITEM) USER_ID INT (PK) ITEM_ID INT (PK) ユーザ所有アイテム (USER_BELONG_ITEMS)1 * 1 *
  36. 36. MyBatis MyBatis入門
  37. 37. MyBatis MyBatis入門 MyBatisの設定ファイル DB接続定義やMapper SQL Statementなどの定義
  38. 38. MyBatis MyBatis入門 MyBatisの設定ファイル DB接続定義やMapper SQL Statementなどの定義 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="org.h2.Driver"/> <property name="url" value="jdbc:h2:tcp://localhost/C:MyFilesormdaoh2db;schema=orm"/> <property name="username" value="ORM"/> <property name="password" value="orm"/> </dataSource> </environment> </environments> <mappers> <mapper resource="sample/sql/UserMap.xml" /> <mapper class="sample.mapper.ItemMapper" /> </mappers> </configuration>
  39. 39. MyBatis MyBatis入門 MyBatisの設定ファイル DB接続定義やMapper SQL Statementなどの定義 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="org.h2.Driver"/> <property name="url" value="jdbc:h2:tcp://localhost/C:MyFilesormdaoh2db;schema=orm"/> <property name="username" value="ORM"/> <property name="password" value="orm"/> </dataSource> </environment> </environments> <mappers> <mapper resource="sample/sql/UserMap.xml" /> <mapper class="sample.mapper.ItemMapper" /> </mappers> </configuration> Databaseへの接続設定
  40. 40. MyBatis MyBatis入門 MyBatisの設定ファイル DB接続定義やMapper SQL Statementなどの定義 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="org.h2.Driver"/> <property name="url" value="jdbc:h2:tcp://localhost/C:MyFilesormdaoh2db;schema=orm"/> <property name="username" value="ORM"/> <property name="password" value="orm"/> </dataSource> </environment> </environments> <mappers> <mapper resource="sample/sql/UserMap.xml" /> <mapper class="sample.mapper.ItemMapper" /> </mappers> </configuration> SqlMapの情報
  41. 41. MyBatis MyBatis入門 SQLとオブジェクトとのマッピング定義
  42. 42. MyBatis MyBatis入門 SQLとオブジェクトとのマッピング定義 <?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" > <mapper namespace="sample.mapper.UserMapper" > <select id="selectUser" resultType="sample.entity.User" > select * from USER where id =#{id} </select> </mapper>
  43. 43. MyBatis MyBatis入門 SQLとオブジェクトとのマッピング定義 <?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" > <mapper namespace="sample.mapper.UserMapper" > <select id="selectUser" resultType="sample.entity.User" > select * from USER where id =#{id} </select> </mapper> Sqlの定義 パラメータや戻り値との Mapping指定
  44. 44. MyBatis MyBatis入門 Javaオブジェクト
  45. 45. MyBatis MyBatis入門 Javaオブジェクト public class User { private Integer id; private String name; private String sex; private Date created; private String comment; // Define setter and getter } public class Item { private Integer id; private String name; // Define setter and getter }
  46. 46. MyBatis MyBatis入門 ユーザーコード
  47. 47. MyBatis MyBatis入門 ユーザーコード public class MapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init() throws IOException { String resource = "sample/context/sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void test1() { SqlSession session = sqlSessionFactory.openSession(); try { User user = (User) session.selectOne("sample.mapper.UserMapper.selectUser", 1); assertThat(user.getName(), is("小酒")); } finally { session.close(); } } }
  48. 48. MyBatis MyBatis入門 ユーザーコード public class MapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init() throws IOException { String resource = "sample/context/sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void test1() { SqlSession session = sqlSessionFactory.openSession(); try { User user = (User) session.selectOne("sample.mapper.UserMapper.selectUser", 1); assertThat(user.getName(), is("小酒")); } finally { session.close(); } } } sqlMapConfigの設定から sqlSessionFactoryを生成 通常システム起動時に行えばよい
  49. 49. MyBatis MyBatis入門 ユーザーコード public class MapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init() throws IOException { String resource = "sample/context/sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void test1() { SqlSession session = sqlSessionFactory.openSession(); try { User user = (User) session.selectOne("sample.mapper.UserMapper.selectUser", 1); assertThat(user.getName(), is("小酒")); } finally { session.close(); } } } sqlSessionFactoryから SqlSessionオブジェクトの生成 SqlSessionオブジェクトは トランザクション制御から Query実行、Mapper提供 などのAPIを提供する、 MyBatisの主要オブジェクト
  50. 50. MyBatis MyBatis入門 ユーザーコード @Test public void test1() { SqlSession session = sqlSessionFactory.openSession(); try { User user = (User) session.selectOne("sample.mapper.UserMapper.selectUser", 1); assertThat(user.getName(), is("小酒")); } finally { session.close(); } } } <mapper namespace="sample.mapper.UserMapper" > <select id="selectUser" resultType="sample.entity.User" > select * from USER where id =#{id} </select> </mapper> SqlMapで定義されたSQL を呼び出し、オブジェクトに Mappingした結果を受け取れる。
  51. 51. MyBatis MyBatis入門 ユーザーコード @Test public void test2() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.selectUser(1); assertThat(user.getName(), is("小酒")); } finally { session.close(); } } public interface UserMapper { User selectUser(int id); }
  52. 52. MyBatis MyBatis入門 ユーザーコード @Test public void test2() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.selectUser(1); assertThat(user.getName(), is("小酒")); } finally { session.close(); } } public interface UserMapper { User selectUser(int id); } Javaインタフェースを定義して、 型安全にSql定義と紐付けることも可能。 内部ではProxyを用いて実現している。
  53. 53. MyBatis MyBatis入門 ユーザーコード @Test public void test3() { SqlSession session = sqlSessionFactory.openSession(); try { ItemMapper itemMapper = session.getMapper(ItemMapper.class); List<Item> items = itemMapper.selectByName("天空%"); assertThat(items.size(), is(2)); assertThat(items.get(0).getName(), is("天空の剣")); assertThat(items.get(1).getName(), is("天空の鎧")); } finally { session.close(); } } public interface ItemMapper { @Select("select * from ITEM where name like #{id} order by id") List<Item> selectByName(String name); }
  54. 54. MyBatis MyBatis入門 ユーザーコード @Test public void test3() { SqlSession session = sqlSessionFactory.openSession(); try { ItemMapper itemMapper = session.getMapper(ItemMapper.class); List<Item> items = itemMapper.selectByName("天空%"); assertThat(items.size(), is(2)); assertThat(items.get(0).getName(), is("天空の剣")); assertThat(items.get(1).getName(), is("天空の鎧")); } finally { session.close(); } } public interface ItemMapper { @Select("select * from ITEM where name like #{id} order by id") List<Item> selectByName(String name); } アノーテーションを用いてSQLを定義 することも可能。
  55. 55. MyBatis ・MyBatisにはデータベースのスキーマ情報を元にソースを自動生成  してくれるGeneratorがある。 ・自動生成されるソースは次のとおり。  ・Entityオブジェクト  ・Mapper XML  ・Mapperインタフェース  ・Criteriaオブジェクト https://github.com/mybatis/generator 自動生成 MyBatis入門
  56. 56. MyBatis DB MyBatis Generater Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース 自動生成設定(XMLファイル) 自動生成リソース MyBatis入門
  57. 57. MyBatis DB MyBatis Generater Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース 自動生成設定(XMLファイル) 自動生成リソース <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="sample2" targetRuntime="MyBatis3"> <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin" /> <plugin type="org.mybatis.generator.plugins.SerializablePlugin" /> <jdbcConnection driverClass="org.h2.Driver" connectionURL="jdbc:h2:tcp://localhost/C:MyFilesormdaoh2db;schema=hoge" userId="ORM" password="orm"> </jdbcConnection> <javaModelGenerator targetPackage="sample.entity" targetProject="gen" /> <sqlMapGenerator targetPackage="sample.sql" targetProject="gen" /> <javaClientGenerator targetPackage="sample.mapper" targetProject="gen" type="XMLMAPPER" /> <table tableName="USER" /> <table tableName="ITEM" /> </context> </generatorConfiguration> MyBatis入門
  58. 58. MyBatis DB MyBatis Generater Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース 自動生成設定(XMLファイル) 自動生成リソース <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="sample2" targetRuntime="MyBatis3"> <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin" /> <plugin type="org.mybatis.generator.plugins.SerializablePlugin" /> <jdbcConnection driverClass="org.h2.Driver" connectionURL="jdbc:h2:tcp://localhost/C:MyFilesormdaoh2db;schema=hoge" userId="ORM" password="orm"> </jdbcConnection> <javaModelGenerator targetPackage="sample.entity" targetProject="gen" /> <sqlMapGenerator targetPackage="sample.sql" targetProject="gen" /> <javaClientGenerator targetPackage="sample.mapper" targetProject="gen" type="XMLMAPPER" /> <table tableName="USER" /> <table tableName="ITEM" /> </context> </generatorConfiguration> MyBatis入門 自動生成するためのスキーマ定義を提供する Databaseへの接続定義
  59. 59. MyBatis DB MyBatis Generater Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース 自動生成設定(XMLファイル) 自動生成リソース <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="sample2" targetRuntime="MyBatis3"> <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin" /> <plugin type="org.mybatis.generator.plugins.SerializablePlugin" /> <jdbcConnection driverClass="org.h2.Driver" connectionURL="jdbc:h2:tcp://localhost/C:MyFilesormdaoh2db;schema=hoge" userId="ORM" password="orm"> </jdbcConnection> <javaModelGenerator targetPackage="sample.entity" targetProject="gen" /> <sqlMapGenerator targetPackage="sample.sql" targetProject="gen" /> <javaClientGenerator targetPackage="sample.mapper" targetProject="gen" type="XMLMAPPER" /> <table tableName="USER" /> <table tableName="ITEM" /> </context> </generatorConfiguration> MyBatis入門 生成リソースのpackageや生成フォルダ、 生成リソースの種類などを定義
  60. 60. MyBatis DB MyBatis Generater Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース 自動生成設定(XMLファイル) 自動生成リソース <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="sample2" targetRuntime="MyBatis3"> <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin" /> <plugin type="org.mybatis.generator.plugins.SerializablePlugin" /> <jdbcConnection driverClass="org.h2.Driver" connectionURL="jdbc:h2:tcp://localhost/C:MyFilesormdaoh2db;schema=hoge" userId="ORM" password="orm"> </jdbcConnection> <javaModelGenerator targetPackage="sample.entity" targetProject="gen" /> <sqlMapGenerator targetPackage="sample.sql" targetProject="gen" /> <javaClientGenerator targetPackage="sample.mapper" targetProject="gen" type="XMLMAPPER" /> <table tableName="USER" /> <table tableName="ITEM" /> </context> </generatorConfiguration> MyBatis入門 生成するテーブルやビューを指定
  61. 61. MyBatis DB MyBatis Generater Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース 自動生成設定(XMLファイル) 自動生成リソース MyBatis入門 C:. ├─entity │ Item.java │ ItemExample.java │ User.java │ UserExample.java │ ├─mapper │ ItemMapper.java │ UserMapper.java │ └─sql ItemMapper.xml UserMapper.xml
  62. 62. MyBatis public class MapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init() throws IOException { String resource = "sample/context/sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void test1() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.selectByPrimaryKey(1); assertThat(user.getName(), is("小酒")); assertThat(user.getComment(), is("こんにちは")); } finally { session.close(); } } } MyBatis入門
  63. 63. MyBatis public class MapperTest { private static SqlSessionFactory sqlSessionFactory; @BeforeClass public static void init() throws IOException { String resource = "sample/context/sqlMapConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } @Test public void test1() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); User user = userMapper.selectByPrimaryKey(1); assertThat(user.getName(), is("小酒")); assertThat(user.getComment(), is("こんにちは")); } finally { session.close(); } } } MyBatis入門 主キーによる検索メソッドが 自動生成されている。
  64. 64. MyBatis @Test public void test2() { SqlSession session = sqlSessionFactory.openSession(); try { ItemMapper itemMapper = session.getMapper(ItemMapper.class); ItemExample itemEx = new ItemExample(); itemEx.createCriteria().andNameLike("天空%"); itemEx.or().andNameEqualTo("こんぼう"); itemEx.setOrderByClause("ID desc"); List<Item> items = itemMapper.selectByExample(itemEx); assertThat(items.size(), is(3)); assertThat(items.get(0).getName(), is("天空の鎧")); assertThat(items.get(1).getName(), is("天空の剣")); assertThat(items.get(2).getName(), is("こんぼう")); } finally { session.close(); } } } MyBatis入門
  65. 65. MyBatis @Test public void test2() { SqlSession session = sqlSessionFactory.openSession(); try { ItemMapper itemMapper = session.getMapper(ItemMapper.class); ItemExample itemEx = new ItemExample(); itemEx.createCriteria().andNameLike("天空%"); itemEx.or().andNameEqualTo("こんぼう"); itemEx.setOrderByClause("ID desc"); List<Item> items = itemMapper.selectByExample(itemEx); assertThat(items.size(), is(3)); assertThat(items.get(0).getName(), is("天空の鎧")); assertThat(items.get(1).getName(), is("天空の剣")); assertThat(items.get(2).getName(), is("こんぼう")); } finally { session.close(); } } } MyBatis入門 Criteriaによる検索条件を指定可能。上記の例では select * from ITEM where name like '天空%' or name = 'こんぼう' ordery by ID desc のクエリーが発行されている。
  66. 66. MyBatis @Test public void test3() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); UserExample userEx = new UserExample(); userEx.createCriteria().andNameEqualTo("小酒"); List<User> users = userMapper.selectByExample(userEx); assertThat(users.size(), is(1)); assertThat(users.get(0).getName(), is("小酒")); assertThat(users.get(0).getComment(), is(nullValue())); users = userMapper.selectByExampleWithBLOBs(userEx); assertThat(users.get(0).getComment(), is("こんにちは")); } finally { session.close(); } } MyBatis入門
  67. 67. MyBatis @Test public void test3() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); UserExample userEx = new UserExample(); userEx.createCriteria().andNameEqualTo("小酒"); List<User> users = userMapper.selectByExample(userEx); assertThat(users.size(), is(1)); assertThat(users.get(0).getName(), is("小酒")); assertThat(users.get(0).getComment(), is(nullValue())); users = userMapper.selectByExampleWithBLOBs(userEx); assertThat(users.get(0).getComment(), is("こんにちは")); } finally { session.close(); } } MyBatis入門 テーブルにBlobやClobなどのLarge Object情報が ある場合、BlobありとBlobなしの二種類の 検索方法が自動生成で用意される。 ※性能的な理由によるものと思われる。
  68. 68. MyBatis @Test public void test4() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); User user = new User(); user.setId(3); user.setName("にゃんこ先生"); user.setSex("M"); user.setCreated(new java.util.Date()); userMapper.insert(user); session.commit(); assertThat(userMapper.countByExample(new UserExample()), is(3));   : } finally { session.close(); } } MyBatis入門
  69. 69. MyBatis @Test public void test4() { SqlSession session = sqlSessionFactory.openSession(); try { UserMapper userMapper = session.getMapper(UserMapper.class); User user = new User(); user.setId(3); user.setName("にゃんこ先生"); user.setSex("M"); user.setCreated(new java.util.Date()); userMapper.insert(user); session.commit(); assertThat(userMapper.countByExample(new UserExample()), is(3));   : } finally { session.close(); } } MyBatis入門 追加はinsertメソッドで sessionオブジェクトのcommitメソッドおよび rollbackメソッドでトランザクションを制御できる。
  70. 70. MyBatis @Test public void test4() { SqlSession session = sqlSessionFactory.openSession(); try {   : user.setComment("にゃー!"); userMapper.updateByPrimaryKeyWithBLOBs(user); session.commit(); user = userMapper.selectByPrimaryKey(3); assertThat(user.getName(), is("にゃんこ先生")); assertThat(user.getComment(), is("にゃー!")); userMapper.deleteByPrimaryKey(3); session.commit(); assertThat(userMapper.countByExample(new UserExample()), is(2)); } finally { session.close(); } } MyBatis入門
  71. 71. MyBatis @Test public void test4() { SqlSession session = sqlSessionFactory.openSession(); try {   : user.setComment("にゃー!"); userMapper.updateByPrimaryKeyWithBLOBs(user); session.commit(); user = userMapper.selectByPrimaryKey(3); assertThat(user.getName(), is("にゃんこ先生")); assertThat(user.getComment(), is("にゃー!")); userMapper.deleteByPrimaryKey(3); session.commit(); assertThat(userMapper.countByExample(new UserExample()), is(2)); } finally { session.close(); } } MyBatis入門 更新はupdateメソッドで Blobあり/なしで二種類のメソッドが自動生成されている。 主キーを用いた更新や、Criteriaを用いた条件による更新が可能
  72. 72. MyBatis @Test public void test4() { SqlSession session = sqlSessionFactory.openSession(); try {   : user.setComment("にゃー!"); userMapper.updateByPrimaryKeyWithBLOBs(user); session.commit(); user = userMapper.selectByPrimaryKey(3); assertThat(user.getName(), is("にゃんこ先生")); assertThat(user.getComment(), is("にゃー!")); userMapper.deleteByPrimaryKey(3); session.commit(); assertThat(userMapper.countByExample(new UserExample()), is(2)); } finally { session.close(); } } MyBatis入門 削除はdeleteメソッドで 主キーを用いた削除や、Criteriaを用いた条件による削除が可能
  73. 73. MyBatis MyBatis入門 More infomation ・公式サイトの日本語情報が充実 ・http://mybatis.github.io/mybatis-3/ja/
  74. 74. MyBatis MyBatis #とは MyBatis入門 MyBatisの活用事例 まとめ AgendaAgenda
  75. 75. MyBatis ・MyBatisは多機能なO/Rマッパーなので、プロジェクトに応じて  様々な使い方ができます。 MyBatisの活用事例 ・ここでは、実際のプロジェクトでMyBatisを活用した際のいくつか  の技術事例を紹介します。
  76. 76. MyBatis Sessionを管理したい ・SqlSessionのAPIでMapperオブジェクトの取得や  commit/rollbackを制御する。 ・処理間(メソッド間)でSqlSessionの引き回しはしたくない。 MyBatisの活用事例
  77. 77. MyBatis Sessionを管理したい ・SqlSessionのAPIでMapperオブジェクトの取得や  commit/rollbackを制御する。 ・処理間(メソッド間)でSqlSessionの引き回しはしたくない。 MyBatisの活用事例 ・SqlSessionManagerを使うことでスレッド単位でSqlSession  を管理できる。
  78. 78. MyBatis Sessionを管理したい MyBatisの活用事例 private static SqlSessionManager sessionManager; @BeforeClass public static void init() throws IOException { InputStream inputStream = Resources.getResourceAsStream("sample/context/MapperConfig.xml"); sessionManager = SqlSessionManager.newInstance(new SqlSessionFactoryBuilder().build(inputStream)); } @Before public void before() { sessionManager.startManagedSession(); } @After public void after() { sessionManager.close(); } @Test public void test() { UserMapper userMapper = sessionManager.getMapper(UserMapper.class); User user = new User(); user.setId(3); user.setName("にゃんこ先生"); user.setSex("M"); user.setCreated(new java.util.Date()); userMapper.insert(user); sessionManager.rollback(); assertThat(userMapper.countByExample(new UserExample()), is(2)); }
  79. 79. MyBatis Sessionを管理したい MyBatisの活用事例 private static SqlSessionManager sessionManager; @BeforeClass public static void init() throws IOException { InputStream inputStream = Resources.getResourceAsStream("sample/context/MapperConfig.xml"); sessionManager = SqlSessionManager.newInstance(new SqlSessionFactoryBuilder().build(inputStream)); } @Before public void before() { sessionManager.startManagedSession(); } @After public void after() { sessionManager.close(); } @Test public void test() { UserMapper userMapper = sessionManager.getMapper(UserMapper.class); User user = new User(); user.setId(3); user.setName("にゃんこ先生"); user.setSex("M"); user.setCreated(new java.util.Date()); userMapper.insert(user); sessionManager.rollback(); assertThat(userMapper.countByExample(new UserExample()), is(2)); } SqlSessionFactoryからSqlSessionManagerを生成 通常、システム起動時に一度だけ生成すればいい。
  80. 80. MyBatis Sessionを管理したい MyBatisの活用事例 private static SqlSessionManager sessionManager; @BeforeClass public static void init() throws IOException { InputStream inputStream = Resources.getResourceAsStream("sample/context/MapperConfig.xml"); sessionManager = SqlSessionManager.newInstance(new SqlSessionFactoryBuilder().build(inputStream)); } @Before public void before() { sessionManager.startManagedSession(); } @After public void after() { sessionManager.close(); } @Test public void test() { UserMapper userMapper = sessionManager.getMapper(UserMapper.class); User user = new User(); user.setId(3); user.setName("にゃんこ先生"); user.setSex("M"); user.setCreated(new java.util.Date()); userMapper.insert(user); sessionManager.rollback(); assertThat(userMapper.countByExample(new UserExample()), is(2)); } startManagedSessionメソッドの呼び出しで 内部的にSqlSessionインスタンスが生成され、 スレッドローカル変数で管理される。
  81. 81. MyBatis Sessionを管理したい MyBatisの活用事例 private static SqlSessionManager sessionManager; @BeforeClass public static void init() throws IOException { InputStream inputStream = Resources.getResourceAsStream("sample/context/MapperConfig.xml"); sessionManager = SqlSessionManager.newInstance(new SqlSessionFactoryBuilder().build(inputStream)); } @Before public void before() { sessionManager.startManagedSession(); } @After public void after() { sessionManager.close(); } @Test public void test() { UserMapper userMapper = sessionManager.getMapper(UserMapper.class); User user = new User(); user.setId(3); user.setName("にゃんこ先生"); user.setSex("M"); user.setCreated(new java.util.Date()); userMapper.insert(user); sessionManager.rollback(); assertThat(userMapper.countByExample(new UserExample()), is(2)); } SqlSessionManagerはSqlSessionインタフェースを 実装しているので、SqlSessionと同様のAPIを 提供。
  82. 82. MyBatis 文字化けに対処したい ・有名な「~」の文字化け ・MS932とSJISのUnicodeのマッピングの違いによって生じる。 MyBatisの活用事例
  83. 83. MyBatis 文字化けに対処したい ・有名な「~」の文字化け ・MS932とSJISのUnicodeのマッピングの違いによって生じる。 MyBatisの活用事例 ・typeHandlerでUnicodeの文字変換を行うことで解決!
  84. 84. MyBatis 文字化けに対処したい MyBatisの活用事例 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd" > <configuration > : <typeHandlers> <typeHandler javaType="String" jdbcType="VARCHAR" handler="hogedriven.StringTypeHandler"/> <typeHandler javaType="String" jdbcType="CHAR" handler="hogedriven.StringTypeHandler"/> </typeHandlers> : </configuration>
  85. 85. MyBatis 文字化けに対処したい MyBatisの活用事例 public final class StringTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, convertTo(parameter)); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return convertTo(rs.getString(columnName)); } : private static final String convertTo(String str) { StringBuffer result = new StringBuffer(); char c; for (int i = 0; i < str.length(); i++) { c = str.charAt(i); switch (c) { // WAVE DASH(~) case 0x301c: c = 0xff5e; break; default: break; } result.append(c); } return result.toString(); } }
  86. 86. MyBatis 文字化けに対処したい MyBatisの活用事例 public final class StringTypeHandler extends BaseTypeHandler<String> { @Override public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException { ps.setString(i, convertTo(parameter)); } @Override public String getNullableResult(ResultSet rs, String columnName) throws SQLException { return convertTo(rs.getString(columnName)); } : private static final String convertTo(String str) { StringBuffer result = new StringBuffer(); char c; for (int i = 0; i < str.length(); i++) { c = str.charAt(i); switch (c) { // WAVE DASH(~) case 0x301c: c = 0xff5e; break; default: break; } result.append(c); } return result.toString(); } } DBからのread/writeのタイミングで、それぞれの 文字エンコーダに応じてUnicodeの文字コードを 変更してやればいい。
  87. 87. MyBatis 違うスキーマから自動生成したい ・自動生成ソースを作成するデータベースの参照スキーマを  実行環境とは別のものにしたい。 MyBatisの活用事例 DB MyBatis Generater Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース 自動生成リソース DB 自動生成用スキーマ 実行用スキーマ
  88. 88. MyBatis 違うスキーマから自動生成したい ・自動生成ソースを作成するデータベースの参照スキーマを  実行環境とは別のものにしたい。 MyBatisの活用事例 ・自動生成設定のtableタグにschema属性を指定する。 ・それだけだと、生成されたSQLが指定されたschemaを指定  したクエリとなるので、   <property name="ignoreQualifiersAtRuntime" value="true"/>  を指定する。
  89. 89. MyBatis 違うスキーマから自動生成したい MyBatisの活用事例 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <generatorConfiguration> <context id="sample2" targetRuntime="MyBatis3"> : <table schema="orm" tableName="USER" > <property name="ignoreQualifiersAtRuntime" value="true"/> </table> <table schema="orm" tableName="ITEM" > <property name="ignoreQualifiersAtRuntime" value="true"/> </table> : </context> </generatorConfiguration>
  90. 90. MyBatis MyBatisの活用事例 楽したい ・自動生成されたソースの検索APIが手続き型のAPI  (コマンドクエリーAPI)で使いにくい ・自動生成されたソースはDAOのため、Entityに  ビジネスロジックを書きたくないし、そもそも自動生成ソース  を修正したくない。 ・テーブルのメタデータだけでなく、SQLからも自動生成したい。 ・てか、モデル層がないとコントローラ層にビジネスロジック  ががが
  91. 91. MyBatis MyBatisの活用事例 楽したい ・GeneratorのPluginでσ(゚∀゚)オレオレPlugin を実装! ・GeneratorはPluginを用いて自動生成ソースを追加/拡張できる! ・自動生成されたソースの検索APIが手続き型のAPI  (コマンドクエリーAPI)で使いにくい ・自動生成されたソースはDAOのため、Entityに  ビジネスロジックを書きたくないし、そもそも自動生成ソース  を修正したくない。 ・テーブルのメタデータだけでなく、SQLからも自動生成したい。 ・てか、モデル層がないとコントローラ層にビジネスロジック  ががが
  92. 92. MyBatis MyBatisの活用事例 楽したい DB MyBatis Generater + σ(゚∀゚)オレオレPlugin Mapper XML Entityオブジェクト Criteriaオブジェクト Mapperインターフェース Modelオブジェクト Queryオブジェクト 自動生成リソース SQL MapConfig XML NEW NEW NEW
  93. 93. MyBatis MyBatisの活用事例 自動生成クラス Pluginで生成した クラス モデルクラス 自動生成ソースは修正しない! 楽したい
  94. 94. MyBatis MyBatisの活用事例 楽したい UserBelongItemsMapper.xml User2itemq1.java User2itemq1Example.java User2itemq1Mapper.java User2itemq1MoBase.java User2itemq1Query.java User2ItemQ1.sql MapperConfig.xml select user.*, item.id as item_id, item.name as item_name from USER user join USER_BELONG_ITEMS blng on user.id = blng.user_id join ITEM item on blng.item_id = item.id
  95. 95. MyBatis MyBatisの活用事例 楽したい UserBelongItemsMapper.xml User2itemq1.java User2itemq1Example.java User2itemq1Mapper.java User2itemq1MoBase.java User2itemq1Query.java User2ItemQ1.sql MapperConfig.xml select user.*, item.id as item_id, item.name as item_name from USER user join USER_BELONG_ITEMS blng on user.id = blng.user_id join ITEM item on blng.item_id = item.id テーブルの結合条件を指定したSQLを指定 Viewを生成するイメージ このSQLをPluginから実行し、ResultSetのメタ情報より 各種リソースを自動生成する。
  96. 96. MyBatis MyBatisの活用事例 楽したい UserBelongItemsMapper.xml User2itemq1.java User2itemq1Example.java User2itemq1Mapper.java User2itemq1MoBase.java User2itemq1Query.java User2ItemQ1.sql MapperConfig.xml : <select id="selectByExample" resultMap="BaseResultMap" parameterType="hogedriven.sample.dao.orm.entity.User2itemq1Example" > select <if test="distinct" > distinct </if> <include refid="Base_Column_List" /> from (select user.*, item.id as item_id, item.name as item_name from USER user join USER_BELONG_ITEMS blng on user.id = blng.user_id join ITEM item on blng.item_id = item.id) User2ItemQ1 <if test="_parameter != null" > <include refid="Example_Where_Clause" /> </if> <if test="orderByClause != null" > order by ${orderByClause} </if> </select> :
  97. 97. MyBatis MyBatisの活用事例 楽したい UserBelongItemsMapper.xml User2itemq1.java User2itemq1Example.java User2itemq1Mapper.java User2itemq1MoBase.java User2itemq1Query.java User2ItemQ1.sql MapperConfig.xml : <select id="selectByExample" resultMap="BaseResultMap" parameterType="hogedriven.sample.dao.orm.entity.User2itemq1Example" > select <if test="distinct" > distinct </if> <include refid="Base_Column_List" /> from (select user.*, item.id as item_id, item.name as item_name from USER user join USER_BELONG_ITEMS blng on user.id = blng.user_id join ITEM item on blng.item_id = item.id) User2ItemQ1 <if test="_parameter != null" > <include refid="Example_Where_Clause" /> </if> <if test="orderByClause != null" > order by ${orderByClause} </if> </select> : 副問い合わせによるSQLが生成された
  98. 98. MyBatis MyBatisの活用事例 楽したい <generatorConfiguration> <context id="sample2" targetRuntime="MyBatis3"> : <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin" /> <plugin type="org.mybatis.generator.plugins.SerializablePlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.SelectByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.UpdateByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.DeleteByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.CountByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.selectforupdate.SelectForUpdatePlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.custommapper.CustomMapperPlugin"> <property name="targetProject" value="sql/orm" /> </plugin> <plugin type="hogedriven.mybatis.generator.plugins.model.ModelPlugin"> <property name="targetModelPackage" value="hogedriven.sample.app.model.orm" /> <property name="targetModelBasePackage" value="hogedriven.sample.dao.orm.model" /> <property name="targetQueryPackage" value="hogedriven.sample.dao.orm.query" /> <property name="targetModelProject" value="src_wrk/model" /> <property name="targetModelBaseProject" value="src_gen" /> <property name="targetQueryProject" value="src_gen" /> </plugin> : </context> </generatorConfiguration>
  99. 99. MyBatis MyBatisの活用事例 楽したい <generatorConfiguration> <context id="sample2" targetRuntime="MyBatis3"> : <plugin type="org.mybatis.generator.plugins.CaseInsensitiveLikePlugin" /> <plugin type="org.mybatis.generator.plugins.SerializablePlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.SelectByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.UpdateByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.DeleteByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.queryby.CountByPlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.selectforupdate.SelectForUpdatePlugin" /> <plugin type="hogedriven.mybatis.generator.plugins.custommapper.CustomMapperPlugin"> <property name="targetProject" value="sql/orm" /> </plugin> <plugin type="hogedriven.mybatis.generator.plugins.model.ModelPlugin"> <property name="targetModelPackage" value="hogedriven.sample.app.model.orm" /> <property name="targetModelBasePackage" value="hogedriven.sample.dao.orm.model" /> <property name="targetQueryPackage" value="hogedriven.sample.dao.orm.query" /> <property name="targetModelProject" value="src_wrk/model" /> <property name="targetModelBaseProject" value="src_gen" /> <property name="targetQueryProject" value="src_gen" /> </plugin> : </context> </generatorConfiguration> それぞれの用途に応じて作成したPlugin達
  100. 100. MyBatis MyBatisの活用事例 楽したい public class SampleTest { @BeforeClass public static void init() throws Exception { SqlContextManager.init("test"); } @Before public void before() { SqlContextManager.getContext("orm").beginTransaction(); } @After public void after() { SqlContextManager.getContext("orm").endTransaction(); } @Test public void test() { UserMo userMo = UserMo.where().idEqualTo(1).fetchFirst(UserMo.class); assertThat(userMo, is(notNullValue())); assertThat(userMo.getName(), is("小酒")); userMo.setName("こざけ"); userMo.saveSelective(); userMo.remove(); SqlContextManager.getContext("orm").rollback(); } :
  101. 101. MyBatis MyBatisの活用事例 楽したい public class SampleTest { @BeforeClass public static void init() throws Exception { SqlContextManager.init("test"); } @Before public void before() { SqlContextManager.getContext("orm").beginTransaction(); } @After public void after() { SqlContextManager.getContext("orm").endTransaction(); } @Test public void test() { UserMo userMo = UserMo.where().idEqualTo(1).fetchFirst(UserMo.class); assertThat(userMo, is(notNullValue())); assertThat(userMo.getName(), is("小酒")); userMo.setName("こざけ"); userMo.saveSelective(); userMo.remove(); SqlContextManager.getContext("orm").rollback(); } : Pluginを用いて生成したモデルによる検索 流れるようなメソッドチェーンでSimpleに かける!
  102. 102. MyBatis MyBatisの活用事例 Demo エル 知ってるか? Demoは大抵成功しない。
  103. 103. MyBatis MyBatis #とは MyBatis入門 MyBatisの活用事例 まとめ AgendaAgenda
  104. 104. MyBatis 楽じゃなかった Plugin作り過ぎたorz 。今は反省している・・
  105. 105. MyBatis 質問があれば

×