リファレンス:https://www.cnblogs.com/wuzhenzhao/p/11101555.html
XMLマッピングファイル
この記事は、学習の概要についてmybatis中国の公式Webサイトを参照しています。http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html
MyBatisの本当の力は、その魔法であるマッピングステートメントにあります。その卓越したパワーにより、マッパーのXMLファイルは比較的単純です。同じ機能を持つJDBCコードと比較すると、コードのほぼ95%が保存されていることがすぐにわかります。MyBatisは、SQLに重点を置いて構築されており、トラブルをできるだけ減らすことができます。
SQLマッピングファイルには、最上位の要素がいくつかしかありません(定義する順序でリストされています)。
- 指定された名前空間のcache -cache構成。
- cache-ref- 他の名前空間のキャッシュ構成への参照。
- resultMap- データベースの結果セットからオブジェクトをロードする方法を説明するために使用される最も複雑で強力な要素です。
- SQL -文は、再利用可能なブロックは、他の文によって参照されることができます。
- insert –マップ挿入ステートメント
- update -map updateステートメント
- delete –マップの削除ステートメント
- select -mapクエリステートメント
選択する
クエリステートメントは、MyBatisで最も一般的に使用される要素の1つです。光エネルギーは、データベースにデータを保存するのにそれほど価値がありません。データを再度取得できる場合にのみ役立ちます。ほとんどのアプリケーションは、変更よりも頻繁です。挿入、更新、または削除操作ごとに、通常、間隔を置いて複数のクエリ操作があります。これはMyBatisの基本原則の1つであり、クエリと結果のマッピングに重点が置かれている理由でもあります。単純なクエリのselect要素は非常に単純です。たとえば、次のとおりです。
<resultMap id = "BaseResultMap" type = "blog"> <id column = "bid" property = "bid" jdbcType = "INTEGER" /> <result column = "name" property = "name" jdbcType = "VARCHAR" / > <result column = "author_id" property = "authorId" jdbcType = "INTEGER" /> </ resultMap> <!-********************** ************************************************** ****************-> <!-简单查询-> <select id = "selectBlogById" resultMap = "BaseResultMap" statementType = "PREPARED" useCache = "false" > ブログから選択*入札=#{bid} </ select>
#{bid}これは、MyBatisに準備済みステートメント(PreparedStatement)パラメーターを作成するように指示します。JDBCでは、そのようなパラメーターはSQLで「?」によって識別され、新しい準備済みステートメントに渡されます。このように:
// MyBatisコードではなく、JDBCコードを近似...
String selectBlogById = "SELECT * FROM BLOG WHERE BID =?";
PreparedStatement ps = conn.prepareStatement(selectBlogById);
ps.setInt(1、bid);
もちろん、JDBCを使用するということは、結果を抽出してオブジェクトインスタンスにマップするために、より多くのコードが必要であることを意味します。これにより、MyBatisが時間を節約できます。select要素を使用すると、多くの属性を構成して、各ステートメントの詳細を構成できます。
<select id = "selectPerson" parameterType = "int" parameterMap = "deprecated" resultType = " hashmap" resultMap = "personResultMap" flushCache = "false" useCache = "true" timeout = "10" fetchSize = "256" statementType = " PREPARED " resultSetType =" FORWARD_ONLY ">
関連する属性の説明:
の属性 | 説明文 |
---|---|
id | 名前空間内の一意の識別子を使用して、このステートメントを参照できます。 |
parameterType | このステートメントに渡されるパラメータークラスの完全修飾名またはエイリアス。MyBatisはTypeHandlerを通じて特定の着信ステートメントのパラメーターを推測できるため、この属性はオプションです。デフォルト値は設定されていません。 |
resultType | このステートメントから返される目的のタイプのクラスの完全修飾名またはエイリアス。コレクションが返される場合は、コレクション自体ではなく、コレクションに含まれるタイプに設定する必要があることに注意してください。resultTypeまたはresultMapを使用できますが、両方を使用することはできません。 |
resultMap | 外部resultMapへの名前付き参照。結果セットのマッピングは、MyBatisの最も強力な機能です。それを完全に理解すると、多くの複雑なマッピング状況を解決できます。resultMapまたはresultTypeを使用できますが、両方を使用することはできません。 |
flushCache | trueに設定すると、ステートメントが呼び出される限り、ローカルキャッシュと2次キャッシュがクリアされます。デフォルト値はfalseです。 |
useCache | これをtrueに設定すると、このステートメントの結果が2次キャッシュにキャッシュされます。select要素のデフォルト値はtrueです。 |
タイムアウト | この設定は、例外をスローする前に、データベースがリクエスト結果を返すのをドライバーが待機する秒数です。デフォルト値は設定されていません(ドライブに依存)。 |
fetchSize | これはドライバのプロンプトです。ドライバからバッチで返される結果行の数がこの設定値と等しくなるようにしてください。デフォルト値は設定されていません(ドライブに依存)。 |
statementType | STATEMENT、PREPARE、またはCALLABLEのいずれか。これにより、MyBatisはそれぞれStatement、PreparedStatement、またはCallableStatementを使用します。デフォルト値はPREPAREDです。 |
resultSetType | FORWARD_ONLY、SCROLL_SENSITIVE、SCROLL_INSENSITIVE、またはDEFAULT(unsetと同じ)のいずれかであり、デフォルト値はunset(ドライブ依存)です。 |
databaseId | データベースベンダーID(databaseIdProvider)が構成されている場合、MyBatisは、databaseIdがない、または現在のdatabaseIdに一致しないすべてのステートメントをロードします。 |
resultOrdered | この設定は、ネストされた結果選択ステートメントにのみ適用できます。trueの場合、ネストされた結果セットまたはグループ化が含まれていると見なされるため、メインの結果行が返されても、前の結果セットへの参照は発生しません。状況。これにより、ネストされた結果セットをフェッチするときにメモリが不足することはありません。デフォルト値:false。 |
resultSets | この設定は、複数の結果セットにのみ適用されます。ステートメントの実行後に返される結果セットがリストされ、各結果セットに名前が付けられます。名前はコンマで区切られます。 |
挿入、更新、削除:
データ変更ステートメントの挿入、更新、削除の実装は非常に近いものです。
<insert id = "insertAuthor" parameterType = "domain.blog.Author" flushCache = "true" statementType = "PREPARED" keyProperty = "" keyColumn = "" useGeneratedKeys = "" timeout = "20"> <update id = "updateAuthor " parameterType =" domain.blog.Author " flushCache =" true " statementType =" PREPARED " timeout =" 20 "> <delete id =" deleteAuthor " parameterType =" domain.blog.Author " flushCache =" true " statementType ="準備されました」 timeout = "20">
関連する属性の説明:
の属性 | 説明文 |
---|---|
id | 名前空間の一意の識別子を使用して、このステートメントを表すことができます。 |
parameterType | ステートメントに渡されるパラメーターの完全修飾クラス名またはエイリアス。MyBatisはタイププロセッサを介して特定の着信ステートメントのパラメータを推測できるため、この属性はオプションです。デフォルト値は設定されていません。 |
flushCache | trueに設定すると、ステートメントが呼び出される限り、ローカルキャッシュと2次キャッシュがクリアされます。デフォルト値はtrue(挿入、更新、削除ステートメントの場合)です。 |
タイムアウト | この設定は、例外をスローする前に、データベースがリクエスト結果を返すのをドライバーが待機する秒数です。デフォルト値は設定されていません(ドライブに依存)。 |
statementType | ステートメント、準備済みまたは呼び出し可能。これにより、MyBatisはそれぞれStatement、PreparedStatement、またはCallableStatementを使用します。デフォルト値はPREPAREDです。 |
useGeneratedKeys | (挿入と更新にのみ役立ちます)これにより、MyBatisはJDBCのgetGeneratedKeysメソッドを使用して、データベース内で生成された主キー(例:MySQLやSQL Serverなどのリレーショナルデータベース管理システムの自動インクリメントフィールド)を取得します。デフォルト値はfalseです。 |
keyProperty | (挿入と更新にのみ役立ちます)属性にマークを付けるだけで、MyBatisはgetGeneratedKeysの戻り値または挿入ステートメントのselectKeyサブ要素、デフォルト値:unset(unset)を通じてキー値を設定します。複数の生成された列を取得する場合は、属性名のコンマ区切りのリストにすることもできます。 |
keyColumn | (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
下面就是 insert,update 和 delete 语句的示例:
<insert id="insertAuthor"> insert into Author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio}) </insert> <update id="updateAuthor"> update Author set username = #{username}, password = #{password}, email = #{email}, bio = #{bio} where id = #{id} </update> <delete id="deleteAuthor"> delete from Author where id = #{id} </delete>
如前所述,插入语句的配置规则更加丰富,在插入语句里面有一些额外的属性和子元素用来处理主键的生成,而且有多种生成方式。首先,如果你的数据库支持自动生成主键的字段(比如 MySQL 和 SQL Server),那么你可以设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置到目标属性上就 OK 了。如果你的数据库还支持多行插入, 你也可以传入一个 Blog数组或集合,并返回自动生成的主键。
<!--批量插入--> <insert id="insertBlogs" useGeneratedKeys="true" keyProperty="bid"> insert into blog (name, author_id) values <foreach item="item" collection="list" separator=","> (#{item.name}, #{item.authorId}) </foreach>
</insert>
sql
这个元素可以被用来定义可重用的 SQL 代码段,这些 SQL 代码可以被包含在其他语句中。它可以(在加载的时候)被静态地设置参数。 在不同的包含语句中可以设置不同的值到参数占位符上。mybatis中sql
标签与include
标签进行配合,灵活的查询需要的数据。
<sql id="ref">
bid,name,authorId
</sql>
<select id="selectbyId" resultMap="BaseResultMap">
select
<include refid="ref"/>
from
blog where bid = #{bid}
</select>
sql标签
中id属性对应include标签
中的refid属性。通过include标签将sql片段
和原sql片段进行拼接成一个完成的sql语句进行执行。include标签中还可以用property标签
,用以指定自定义属性。
<select id="selectbyId" resultMap="BaseResultMap"> select <include refid="ref"> <property name="abc" value="bid"/> </include> from blog where bid = #{bid} </select>
此时,可以在sql标签
中取出对应设置的自定义属性中的值,例如接上代码例子:
<sql id="ref"> ${abc},name,authorId </sql> <select id="selectbyId" resultMap="BaseResultMap"> select <include refid="ref"> <property name="abc" value="bid"/> </include> from blog where bid = #{bid} </select>
在sql
标签中通过${}
取出对应include标签中
设置的属性值。
关联(association)元素处理“有一个”类型的关系。 比如,在我们的示例中,一个博客有一个用户。关联结果映射和其它类型的映射工作方式差不多。 你需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:
- 嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
- 嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。
关联的嵌套 Select 查询
<!-- 另一种联合查询(一对一)的实现,但是这种方式有“N+1”的问题 --> <resultMap id="BlogWithAuthorQueryMap" type="com.wuzz.demo.associate.BlogAndAuthor"> <id column="bid" property="bid" jdbcType="INTEGER"/> <result column="name" property="name" jdbcType="VARCHAR"/> <association property="author" javaType="com.wuzz.demo.entity.Author" column="author_id" select="selectAuthor"/> </resultMap> <!-- 嵌套查询 --> <select id="selectAuthor" parameterType="int" resultType="com.wuzz.demo.entity.Author"> select author_id authorId, author_name authorName from author where author_id = #{authorId} </select> <!-- 根据文章查询作者,一对一,嵌套查询,存在N+1问题,可通过开启延迟加载解决 --> <select id="selectBlogWithAuthorQuery" resultMap="BlogWithAuthorQueryMap" > select b.bid, b.name, b.author_id, a.author_id , a.author_name from blog b left join author a on b.author_id=a.author_id where b.bid = #{bid, jdbcType=INTEGER} </select>
就是这么简单。我们有两个 select 查询语句:一个用来加载博客(Blog),另外一个用来加载作者(Author),而且博客的结果映射描述了应该使用 selectAuthor 语句加载它的 author 属性。其它所有的属性将会被自动加载,只要它们的列名和属性名相匹配。这种方式虽然很简单,但在大型数据集或大型数据表上表现不佳。这个问题被称为“N+1 查询问题”。 概括地讲,N+1 查询问题是这样子的:
- 你执行了一个单独的 SQL 语句来获取结果的一个列表(就是“+1”)。
- 对列表返回的每条记录,你执行一个 select 查询语句来为每条记录加载详细信息(就是“N”)。
这个问题会导致成百上千的 SQL 语句被执行。有时候,我们不希望产生这样的后果。MyBatis 能够对这样的查询进行延迟加载,因此可以将大量语句同时运行的开销分散开来。mybatis.configuration.lazy-loading-enabled=true 可以开启延时加载 mybatis.configuration.aggressive-lazy-loading=true 可以指定哪些方法调用查询, 然而,如果你加载记录列表之后立刻就遍历列表以获取嵌套的数据,就会触发所有的延迟加载查询,性能可能会变得很糟糕。所以还有另外一种方法。
关联的嵌套结果映射
<!-- 根据文章查询作者,一对一查询的结果,嵌套查询 --> <resultMap id="BlogWithAuthorResultMap" type="com.wuzz.demo.associate.BlogAndAuthor"> <id column="bid" property="bid" jdbcType="INTEGER"/> <result column="name" property="name" jdbcType="VARCHAR"/> <!-- 联合查询,将author的属性映射到ResultMap --> <association property="author" javaType="com.wuzz.demo.entity.Author"> <id column="author_id" property="authorId"/> <result column="author_name" property="authorName"/> </association> </resultMap> <!-- 根据文章查询作者,一对一,嵌套结果,无N+1问题 --> <select id="selectBlogWithAuthorResult" resultMap="BlogWithAuthorResultMap" > select b.bid, b.name, b.author_id, a.author_id , a.author_name from blog b,author a where b.author_id=a.author_id and b.bid = #{bid, jdbcType=INTEGER} </select>
查询文章带评论的结果(一对多)映射:
<!-- 查询文章带评论的结果(一对多) --> <resultMap id="BlogWithCommentMap" type="com.wuzz.demo.associate.BlogAndComment" extends="BaseResultMap" > <collection property="comment" ofType="com.wuzz.demo.entity.Comment"> <id column="comment_id" property="commentId" /> <result column="content" property="content" /> <result column="bid" property="bid" /> </collection> </resultMap> <!-- 根据文章查询评论,一对多 --> <select id="selectBlogWithCommentById" resultMap="BlogWithCommentMap" > select b.bid, b.name, b.author_id , c.comment_id , c.content,c.bid from blog b, comment c where b.bid = c.bid and b.bid = #{bid} </select>
按作者查询文章评论的结果(多对多):
<!-- 按作者查询文章评论的结果(多对多) --> <resultMap id="AuthorWithBlogMap" type="com.wuzz.demo.associate.AuthorAndBlog" > <id column="author_id" property="authorId" jdbcType="INTEGER"/> <result column="author_name" property="authorName" jdbcType="VARCHAR"/> <collection property="blog" ofType="com.wuzz.demo.associate.BlogAndComment"> <id column="bid" property="bid" /> <result column="name" property="name" /> <result column="author_id" property="authorId" /> <collection property="comment" ofType="com.wuzz.demo.entity.Comment"> <id column="comment_id" property="commentId" /> <result column="content" property="content" /> <result column="bid" property="bid" /> </collection> </collection> </resultMap> <!-- 根据作者文章评论,多对多 --> <select id="selectAuthorWithBlog" resultMap="AuthorWithBlogMap" > select b.bid, b.name, a.author_id , a.author_name , c.comment_id , c.content,c.bid from blog b, author a, comment c where b.author_id = a.author_id and b.bid = c.bid </select>
动态 SQL
MyBatis 的强大特性之一便是它的动态 SQL。如果你有使用 JDBC 或其它类似框架的经验,你就能体会到根据不同条件拼接 SQL 语句的痛苦。例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL 这一特性可以彻底摆脱这种痛苦。虽然在以前使用动态 SQL 并非一件易事,但正是 MyBatis 提供了可以被用在任意 SQL 映射语句中的强大的动态 SQL 语言得以改进这种情形。动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
其中 choose再实际开发中应用的较少,我们这里就其他3个标签进行测试
<!--动态sql--> <select id="selectBlogById2" resultMap="BaseResultMap" statementType="PREPARED" useCache="false" parameterType="blog"> select * from blog <trim prefix="WHERE" prefixOverrides="AND |OR "> <if test="bid != null and bid !='' "> bid = #{bid} </if> <if test="name != null and name !='' "> AND name = #{name} </if> <if test="authorId != null and authorId != ''"> AND author_id = #{author_id} </if> </trim> </select>
foreach:動的SQLのもう1つの一般的な操作要件は、通常、IN条件ステートメントを作成するときに、コレクションをトラバースすることです。たとえば、次のとおりです。
<select id = "selectPostIn" resultType = "domain.blog.Post"> SELECT * FROM POST P WHERE ID in <foreach item = "item" index = "index" collection = "list" open = "(" separator = " 、 "close =") "> #{item} </ foreach> </ select>