システムアーキテクト~my batis編~
Post on 18-Dec-2014
5.706 Views
Preview:
DESCRIPTION
TRANSCRIPT
本日のお話
MyBatis
数億を超える社内きっての大規模プロジェクト
可用性 99.99% 絶対に止まらないシステム
データ件数 2億件 ビックデータへの対応
連携装置 3万台 負荷に対応できるシステム
このプロジェクトにMyBatisで挑みました!
(`・ω・)
本日は
・MyBatisの紹介・プロジェクトに適用した MyBatisの技術事例
についてお話をしようと思います!
つまりですね
これは、高可用・大規模プロジェクトに挑んだ知られざるシステムアーキテクトの話である
主題歌「地上の星」中島 みゆき
一般的な中堅SIer
社内きっての大規模プロジェクト
可用性 99.99%
許される年間停止時間 53分未満
現行システムに性能遅延
連携装置
3万台
デー
タ件数
2億件以上!
移行時も
システム停止は
許されない!
インフルエンザの猛威!
次々倒れるチームメンバ(平均年齢35才)
新チーム結成
シスアーキの意地!
負荷テストでシステムダウン!
迫られるO/R Mapperの選択
MyBatisで行く!
押し寄せる寝不足
ドラクエX
挑め!99.99%!~大規模プロジェクトに見る MyBatisの技術事例~
presents by
すいませんお待たせしましたm(__)m
オープニングは前回の使いまわしです。# もう一度使ってみたかった
ちなみに
可用性 99.99%!データ件数 2億件!連携装置 3万台!
をどのように実現したのか
可用性 99.99%!データ件数 2億件!連携装置 3万台!
をどのように実現したのか
などの話はしません
話すのはMyBatisの内容ね
難しい話はできません
ごめんね
MyBatis
自己紹介自己紹介 <名前>
こざけさんじゅうはっさい
<メッセージ>
はい、ビールが好きです!
Twitter@s_kozake
<最近のお気に入り>
ニャンコ先生
MyBatis
MyBatis #とは
MyBatis入門
MyBatisの活用事例
まとめ
AgendaAgenda
MyBatis
MyBatis #とは
MyBatis入門
MyBatisの活用事例
まとめ
AgendaAgenda
MyBatis
MyBatis #とは・XMLまたはアノテーションを用いてストアドプロシージャ やSQL文をオブジェクトと紐付ける永続性フレームワーク
・Apache License 2.0によるオープンソースソフトウェアとして提供
・以前はiBATISとして知られていた
wikiより転載http://ja.wikipedia.org/wiki/MyBatis
MyBatis
MyBatis #とは
・他のO/Rマッピングフレームワークとは異なりデータベースと オブジェクトをマッピングするのではなく、SQL文とオブジェクト のマッピングを行う
・レガシーな環境や非正規化されたデータベース、またはSQL文 の実行を完全に制御したい場合に、よい選択肢となる
・一番の特徴は、XMLに記述したSQL文を普通のオブジェクト と組み合わせられることである
wikiより転載http://ja.wikipedia.org/wiki/MyBatis
特徴
MyBatis
MyBatis #とは
・他のO/Rマッピングフレームワークとは異なりデータベースと オブジェクトをマッピングするのではなく、SQL文とオブジェクト のマッピングを行う
・レガシーな環境や非正規化されたデータベース、またはSQL文 の実行を完全に制御したい場合に、よい選択肢となる
・一番の特徴は、XMLに記述したSQL文を普通のオブジェクト と組み合わせられることである
wikiより転載http://ja.wikipedia.org/wiki/MyBatis
特徴
プロジェクトにMyBatisを採用した理由は
この特徴が大きいです。
MyBatis
MyBatis #とは
MyBatis入門
MyBatisの活用事例
まとめ
AgendaAgenda
MyBatis
MyBatis入門
・「例示は理解の試金石」 by 数学ガール
・MyBatisのSimpleなサンプル実装をMyBatisの概念図と 紐付けて示します。
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*
MyBatis
MyBatis入門
MyBatis
MyBatis入門 MyBatisの設定ファイルDB接続定義やMapper SQL Statementなどの定義
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>
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への接続設定
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の情報
MyBatis
MyBatis入門 SQLとオブジェクトとのマッピング定義
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>
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指定
MyBatis
MyBatis入門
Javaオブジェクト
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}
MyBatis
MyBatis入門
ユーザーコード
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(); } }}
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を生成通常システム起動時に行えばよい
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の主要オブジェクト
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した結果を受け取れる。
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);}
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を用いて実現している。
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);}
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を定義することも可能。
MyBatis
・MyBatisにはデータベースのスキーマ情報を元にソースを自動生成 してくれるGeneratorがある。・自動生成されるソースは次のとおり。
・Entityオブジェクト ・Mapper XML ・Mapperインタフェース ・Criteriaオブジェクト
https://github.com/mybatis/generator
自動生成
MyBatis入門
MyBatis
DB
MyBatis GeneraterMapper XML
EntityオブジェクトCriteriaオブジェクトMapperインターフェース
自動生成設定(XMLファイル)
自動生成リソース
MyBatis入門
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入門
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への接続定義
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や生成フォルダ、生成リソースの種類などを定義
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入門
生成するテーブルやビューを指定
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
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入門
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入門
主キーによる検索メソッドが
自動生成されている。
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入門
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
のクエリーが発行されている。
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入門
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なしの二種類の検索方法が自動生成で用意される。
※性能的な理由によるものと思われる。
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入門
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メソッドでトランザクションを制御できる。
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入門
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を用いた条件による更新が可能
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を用いた条件による削除が可能
MyBatis
MyBatis入門More infomation
・公式サイトの日本語情報が充実
・http://mybatis.github.io/mybatis-3/ja/
MyBatis
MyBatis #とは
MyBatis入門
MyBatisの活用事例
まとめ
AgendaAgenda
MyBatis
・MyBatisは多機能なO/Rマッパーなので、プロジェクトに応じて 様々な使い方ができます。
MyBatisの活用事例
・ここでは、実際のプロジェクトでMyBatisを活用した際のいくつか の技術事例を紹介します。
MyBatis
Sessionを管理したい
・SqlSessionのAPIでMapperオブジェクトの取得や commit/rollbackを制御する。・処理間(メソッド間)でSqlSessionの引き回しはしたくない。
MyBatisの活用事例
MyBatis
Sessionを管理したい
・SqlSessionのAPIでMapperオブジェクトの取得や commit/rollbackを制御する。・処理間(メソッド間)でSqlSessionの引き回しはしたくない。
MyBatisの活用事例
・SqlSessionManagerを使うことでスレッド単位でSqlSession を管理できる。
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)); }
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を生成通常、システム起動時に一度だけ生成すればいい。
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インスタンスが生成され、スレッドローカル変数で管理される。
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を提供。
MyBatis
文字化けに対処したい
・有名な「~」の文字化け
・MS932とSJISのUnicodeのマッピングの違いによって生じる。
MyBatisの活用事例
MyBatis
文字化けに対処したい
・有名な「~」の文字化け
・MS932とSJISのUnicodeのマッピングの違いによって生じる。
MyBatisの活用事例
・typeHandlerでUnicodeの文字変換を行うことで解決!
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>
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(); }}
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の文字コードを変更してやればいい。
MyBatis
違うスキーマから自動生成したい
・自動生成ソースを作成するデータベースの参照スキーマを
実行環境とは別のものにしたい。
MyBatisの活用事例
DB
MyBatis GeneraterMapper XML
EntityオブジェクトCriteriaオブジェクトMapperインターフェース
自動生成リソース
DB
自動生成用スキーマ
実行用スキーマ
MyBatis
違うスキーマから自動生成したい
・自動生成ソースを作成するデータベースの参照スキーマを
実行環境とは別のものにしたい。
MyBatisの活用事例
・自動生成設定のtableタグにschema属性を指定する。・それだけだと、生成されたSQLが指定されたschemaを指定 したクエリとなるので、
<property name="ignoreQualifiersAtRuntime" value="true"/> を指定する。
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>
MyBatis
MyBatisの活用事例楽したい
・自動生成されたソースの検索APIが手続き型のAPI (コマンドクエリーAPI)で使いにくい・自動生成されたソースはDAOのため、Entityに ビジネスロジックを書きたくないし、そもそも自動生成ソース
を修正したくない。
・テーブルのメタデータだけでなく、SQLからも自動生成したい。・てか、モデル層がないとコントローラ層にビジネスロジック
ががが
MyBatis
MyBatisの活用事例楽したい
・GeneratorのPluginでσ(゚∀゚)オレオレPlugin を実装!・GeneratorはPluginを用いて自動生成ソースを追加/拡張できる!
・自動生成されたソースの検索APIが手続き型のAPI (コマンドクエリーAPI)で使いにくい・自動生成されたソースはDAOのため、Entityに ビジネスロジックを書きたくないし、そもそも自動生成ソース
を修正したくない。
・テーブルのメタデータだけでなく、SQLからも自動生成したい。・てか、モデル層がないとコントローラ層にビジネスロジック
ががが
MyBatis
MyBatisの活用事例楽したい
DB
MyBatis Generater +σ(゚∀゚)オレオレPlugin Mapper XML
EntityオブジェクトCriteriaオブジェクトMapperインターフェースModelオブジェクトQueryオブジェクト
自動生成リソース
SQL MapConfig XML
NEW
NEWNEW
MyBatis
MyBatisの活用事例自動生成クラス
Pluginで生成したクラス
モデルクラス
自動生成ソースは修正しない!
楽したい
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
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のメタ情報より各種リソースを自動生成する。
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> :
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が生成された
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>
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達
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(); } :
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にかける!
MyBatis
MyBatisの活用事例
Demo
エル知ってるか? Demoは大抵成功しない。
MyBatis
MyBatis #とは
MyBatis入門
MyBatisの活用事例
まとめ
AgendaAgenda
MyBatis
楽じゃなかったPlugin作り過ぎたorz 。今は反省している・・
MyBatis
質問があれば
top related