106
本日のお話

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

Embed Size (px)

DESCRIPTION

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

Citation preview

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

本日のお話

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

MyBatis

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

数億を超える社内きっての大規模プロジェクト

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

可用性 99.99% 絶対に止まらないシステム

データ件数 2億件 ビックデータへの対応

連携装置 3万台 負荷に対応できるシステム

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

このプロジェクトにMyBatisで挑みました!

(`・ω・)

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

本日は

・MyBatisの紹介・プロジェクトに適用した MyBatisの技術事例

についてお話をしようと思います!

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

つまりですね

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

これは、高可用・大規模プロジェクトに挑んだ知られざるシステムアーキテクトの話である

Page 9: システムアーキテクト~My batis編~
Page 10: システムアーキテクト~My batis編~

主題歌「地上の星」中島 みゆき

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

一般的な中堅SIer

社内きっての大規模プロジェクト

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

可用性 99.99%

許される年間停止時間 53分未満

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

現行システムに性能遅延

連携装置

3万台

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

デー

タ件数

  2億件以上!

移行時も

システム停止は

許されない!

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

インフルエンザの猛威!

次々倒れるチームメンバ(平均年齢35才)

新チーム結成

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

シスアーキの意地!

負荷テストでシステムダウン!

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

迫られるO/R Mapperの選択

MyBatisで行く!

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

押し寄せる寝不足

ドラクエX

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

挑め!99.99%!~大規模プロジェクトに見る MyBatisの技術事例~

presents by

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

すいませんお待たせしましたm(__)m

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

オープニングは前回の使いまわしです。# もう一度使ってみたかった

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

ちなみに

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

可用性 99.99%!データ件数 2億件!連携装置 3万台!

をどのように実現したのか

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

可用性 99.99%!データ件数 2億件!連携装置 3万台!

をどのように実現したのか

などの話はしません

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

話すのはMyBatisの内容ね

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

難しい話はできません

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

ごめんね

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

MyBatis

自己紹介自己紹介 <名前>

こざけさんじゅうはっさい

<メッセージ>

はい、ビールが好きです!

Twitter@s_kozake

<最近のお気に入り>

ニャンコ先生

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

MyBatis

MyBatis #とは

MyBatis入門

MyBatisの活用事例

まとめ

AgendaAgenda

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

MyBatis

MyBatis #とは

MyBatis入門

MyBatisの活用事例

まとめ

AgendaAgenda

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

MyBatis

MyBatis #とは・XMLまたはアノテーションを用いてストアドプロシージャ やSQL文をオブジェクトと紐付ける永続性フレームワーク

・Apache License 2.0によるオープンソースソフトウェアとして提供

・以前はiBATISとして知られていた

wikiより転載http://ja.wikipedia.org/wiki/MyBatis

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

MyBatis

MyBatis #とは

・他のO/Rマッピングフレームワークとは異なりデータベースと オブジェクトをマッピングするのではなく、SQL文とオブジェクト のマッピングを行う

・レガシーな環境や非正規化されたデータベース、またはSQL文 の実行を完全に制御したい場合に、よい選択肢となる

・一番の特徴は、XMLに記述したSQL文を普通のオブジェクト と組み合わせられることである

wikiより転載http://ja.wikipedia.org/wiki/MyBatis

特徴

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

MyBatis

MyBatis #とは

・他のO/Rマッピングフレームワークとは異なりデータベースと オブジェクトをマッピングするのではなく、SQL文とオブジェクト のマッピングを行う

・レガシーな環境や非正規化されたデータベース、またはSQL文 の実行を完全に制御したい場合に、よい選択肢となる

・一番の特徴は、XMLに記述したSQL文を普通のオブジェクト と組み合わせられることである

wikiより転載http://ja.wikipedia.org/wiki/MyBatis

特徴

プロジェクトにMyBatisを採用した理由は

この特徴が大きいです。

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

MyBatis

MyBatis #とは

MyBatis入門

MyBatisの活用事例

まとめ

AgendaAgenda

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

MyBatis

MyBatis入門

・「例示は理解の試金石」 by 数学ガール

・MyBatisのSimpleなサンプル実装をMyBatisの概念図と 紐付けて示します。

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

MyBatis

MyBatis #とは用意したDB

ID INT (PK)

NAME VARCHAR(100)SEX CHAR(1)COMMENT CLOBCREATED TIMESTAMP

ユーザ(USER)

ID INT (PK)

NAME VARCHAR(100)

アイテム(ITEM)

USER_ID INT (PK)ITEM_ID INT (PK)

ユーザ所有アイテム

(USER_BELONG_ITEMS)1*

1*

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

MyBatis

MyBatis入門

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

MyBatis

MyBatis入門 MyBatisの設定ファイルDB接続定義やMapper SQL Statementなどの定義

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

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:\MyFiles\orm\dao\h2\db;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>

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

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:\MyFiles\orm\dao\h2\db;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への接続設定

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

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:\MyFiles\orm\dao\h2\db;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の情報

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

MyBatis

MyBatis入門 SQLとオブジェクトとのマッピング定義

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

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>

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

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指定

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

MyBatis

MyBatis入門

Javaオブジェクト

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

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}

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

MyBatis

MyBatis入門

ユーザーコード

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

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(); } }}

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

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を生成通常システム起動時に行えばよい

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

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の主要オブジェクト

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

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した結果を受け取れる。

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

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);}

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

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を用いて実現している。

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

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);}

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

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を定義することも可能。

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

MyBatis

・MyBatisにはデータベースのスキーマ情報を元にソースを自動生成 してくれるGeneratorがある。・自動生成されるソースは次のとおり。

 ・Entityオブジェクト ・Mapper XML ・Mapperインタフェース ・Criteriaオブジェクト

https://github.com/mybatis/generator

自動生成

MyBatis入門

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

MyBatis

DB

MyBatis GeneraterMapper XML

EntityオブジェクトCriteriaオブジェクトMapperインターフェース

自動生成設定(XMLファイル)

自動生成リソース

MyBatis入門

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

MyBatis

DB

MyBatis GeneraterMapper XML

EntityオブジェクトCriteriaオブジェクトMapperインターフェース

自動生成設定(XMLファイル)

自動生成リソース

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfigurationPUBLIC "-//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:\MyFiles\orm\dao\h2\db;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入門

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

MyBatis

DB

MyBatis GeneraterMapper XML

EntityオブジェクトCriteriaオブジェクトMapperインターフェース

自動生成設定(XMLファイル)

自動生成リソース

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfigurationPUBLIC "-//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:\MyFiles\orm\dao\h2\db;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への接続定義

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

MyBatis

DB

MyBatis GeneraterMapper XML

EntityオブジェクトCriteriaオブジェクトMapperインターフェース

自動生成設定(XMLファイル)

自動生成リソース

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfigurationPUBLIC "-//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:\MyFiles\orm\dao\h2\db;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や生成フォルダ、生成リソースの種類などを定義

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

MyBatis

DB

MyBatis GeneraterMapper XML

EntityオブジェクトCriteriaオブジェクトMapperインターフェース

自動生成設定(XMLファイル)

自動生成リソース

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfigurationPUBLIC "-//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:\MyFiles\orm\dao\h2\db;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入門

生成するテーブルやビューを指定

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

MyBatis

DB

MyBatis GeneraterMapper 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

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

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入門

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

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入門

主キーによる検索メソッドが

自動生成されている。

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

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入門

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

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 ITEMwhere name like '天空%' or name = 'こんぼう'ordery by ID desc

のクエリーが発行されている。

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

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入門

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

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なしの二種類の検索方法が自動生成で用意される。

※性能的な理由によるものと思われる。

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

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入門

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

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メソッドでトランザクションを制御できる。

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

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入門

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

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を用いた条件による更新が可能

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

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を用いた条件による削除が可能

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

MyBatis

MyBatis入門More infomation

・公式サイトの日本語情報が充実

・http://mybatis.github.io/mybatis-3/ja/

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

MyBatis

MyBatis #とは

MyBatis入門

MyBatisの活用事例

まとめ

AgendaAgenda

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

MyBatis

・MyBatisは多機能なO/Rマッパーなので、プロジェクトに応じて 様々な使い方ができます。

MyBatisの活用事例

・ここでは、実際のプロジェクトでMyBatisを活用した際のいくつか の技術事例を紹介します。

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

MyBatis

Sessionを管理したい

・SqlSessionのAPIでMapperオブジェクトの取得や commit/rollbackを制御する。・処理間(メソッド間)でSqlSessionの引き回しはしたくない。

MyBatisの活用事例

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

MyBatis

Sessionを管理したい

・SqlSessionのAPIでMapperオブジェクトの取得や commit/rollbackを制御する。・処理間(メソッド間)でSqlSessionの引き回しはしたくない。

MyBatisの活用事例

・SqlSessionManagerを使うことでスレッド単位でSqlSession を管理できる。

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

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)); }

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

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を生成通常、システム起動時に一度だけ生成すればいい。

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

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インスタンスが生成され、スレッドローカル変数で管理される。

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

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を提供。

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

MyBatis

文字化けに対処したい

・有名な「~」の文字化け

・MS932とSJISのUnicodeのマッピングの違いによって生じる。

MyBatisの活用事例

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

MyBatis

文字化けに対処したい

・有名な「~」の文字化け

・MS932とSJISのUnicodeのマッピングの違いによって生じる。

MyBatisの活用事例

・typeHandlerでUnicodeの文字変換を行うことで解決!

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

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>

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

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(); }}

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

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の文字コードを変更してやればいい。

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

MyBatis

違うスキーマから自動生成したい

・自動生成ソースを作成するデータベースの参照スキーマを

 実行環境とは別のものにしたい。

MyBatisの活用事例

DB

MyBatis GeneraterMapper XML

EntityオブジェクトCriteriaオブジェクトMapperインターフェース

自動生成リソース

DB

自動生成用スキーマ

実行用スキーマ

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

MyBatis

違うスキーマから自動生成したい

・自動生成ソースを作成するデータベースの参照スキーマを

 実行環境とは別のものにしたい。

MyBatisの活用事例

・自動生成設定のtableタグにschema属性を指定する。・それだけだと、生成されたSQLが指定されたschemaを指定 したクエリとなるので、

  <property name="ignoreQualifiersAtRuntime" value="true"/> を指定する。

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

MyBatis

違うスキーマから自動生成したい

MyBatisの活用事例

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfigurationPUBLIC "-//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>

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

MyBatis

MyBatisの活用事例楽したい

・自動生成されたソースの検索APIが手続き型のAPI (コマンドクエリーAPI)で使いにくい・自動生成されたソースはDAOのため、Entityに ビジネスロジックを書きたくないし、そもそも自動生成ソース

 を修正したくない。

・テーブルのメタデータだけでなく、SQLからも自動生成したい。・てか、モデル層がないとコントローラ層にビジネスロジック

 ががが

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

MyBatis

MyBatisの活用事例楽したい

・GeneratorのPluginでσ(゚∀゚)オレオレPlugin を実装!・GeneratorはPluginを用いて自動生成ソースを追加/拡張できる!

・自動生成されたソースの検索APIが手続き型のAPI (コマンドクエリーAPI)で使いにくい・自動生成されたソースはDAOのため、Entityに ビジネスロジックを書きたくないし、そもそも自動生成ソース

 を修正したくない。

・テーブルのメタデータだけでなく、SQLからも自動生成したい。・てか、モデル層がないとコントローラ層にビジネスロジック

 ががが

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

MyBatis

MyBatisの活用事例楽したい

DB

MyBatis Generater +σ(゚∀゚)オレオレPlugin Mapper XML

EntityオブジェクトCriteriaオブジェクトMapperインターフェースModelオブジェクトQueryオブジェクト

自動生成リソース

SQL MapConfig XML

NEW

NEWNEW

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

MyBatis

MyBatisの活用事例自動生成クラス

Pluginで生成したクラス

モデルクラス

自動生成ソースは修正しない!

楽したい

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

MyBatis

MyBatisの活用事例楽したい

UserBelongItemsMapper.xml

User2itemq1.javaUser2itemq1Example.javaUser2itemq1Mapper.javaUser2itemq1MoBase.javaUser2itemq1Query.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

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

MyBatis

MyBatisの活用事例楽したい

UserBelongItemsMapper.xml

User2itemq1.javaUser2itemq1Example.javaUser2itemq1Mapper.javaUser2itemq1MoBase.javaUser2itemq1Query.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のメタ情報より各種リソースを自動生成する。

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

MyBatis

MyBatisの活用事例楽したい

UserBelongItemsMapper.xml

User2itemq1.javaUser2itemq1Example.javaUser2itemq1Mapper.javaUser2itemq1MoBase.javaUser2itemq1Query.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> :

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

MyBatis

MyBatisの活用事例楽したい

UserBelongItemsMapper.xml

User2itemq1.javaUser2itemq1Example.javaUser2itemq1Mapper.javaUser2itemq1MoBase.javaUser2itemq1Query.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が生成された

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

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>

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

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達

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

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(); } :

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

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にかける!

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

MyBatis

MyBatisの活用事例

Demo

エル知ってるか? Demoは大抵成功しない。

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

MyBatis

MyBatis #とは

MyBatis入門

MyBatisの活用事例

まとめ

AgendaAgenda

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

MyBatis

楽じゃなかったPlugin作り過ぎたorz 。今は反省している・・

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

MyBatis

質問があれば