一.mybatis-config.xml文件
<?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> <!--读取外部资源,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的是 properties 属性中指定的属性。--> <properties resource="org/mybatis/example/config.properties"> <property name="username" value="dev_user"/> <property name="password" value="F2Fa3!33TYyg"/> </properties> <!--settings设置--> <settings> <!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存--> <setting name="cacheEnabled" value="true"/> <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。--> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="autoMappingBehavior" value="PARTIAL"/> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> <setting name="defaultFetchSize" value="100"/> <setting name="safeRowBoundsEnabled" value="false"/> <!--是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn--> <setting name="mapUnderscoreToCamelCase" value="false"/> <setting name="localCacheScope" value="SESSION"/> <setting name="jdbcTypeForNull" value="OTHER"/> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> </settings> <!--类型别名--> <typeAliases> <!--type:实体类的全路径。alias:别名,通常首字母大写--> <!--<typeAlias type="com.zpc.mybatis.pojo.User" alias="User"/>--> <!--扫描包--> <package name="com.zpc.mybatis.pojo"/> </typeAliases> <!--插件(plugins)--> <plugins> <plugin interceptor="org.mybatis.example.ExamplePlugin"> <property name="someProperty" value="100"/> </plugin> </plugins> <!-- 环境,可以配置多个,default:指定采用哪个环境 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"> <property name="..." value="..."/> </transactionManager> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!-- 使用相对于类路径的资源引用 --> <mappers> <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> <mapper resource="org/mybatis/builder/BlogMapper.xml"/> <mapper resource="org/mybatis/builder/PostMapper.xml"/> </mappers> </configuration>
二.Mapper XML文件详解
1.CRUD标签
select
select中的几个属性说明:
id属性:当前名称空间下的statement的唯一标识。必须。要求id和mapper接口中的方法的名字一致。
resultType:将结果集映射为java的对象类型。必须(和 resultMap 二选一)
parameterType:传入参数类型。可以省略
<select id="selectPerson" //当前名称空间下的statement的唯一标识 parameterType="int" //将会传入这条语句的参数的类全限定名或别名(可以省略) parameterMap="deprecated" //该参数已废弃 resultType="hashmap" //期望从这条语句中返回结果的类全限定名或别名 resultMap="personResultMap" //对外部 resultMap 的命名引用 flushCache="false" //将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空 useCache="true" //将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来 timeout="10" //这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数 fetchSize="256" //这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值 statementType="PREPARED" //可选 STATEMENT,PREPARED 或 CALLABLE resultSetType="FORWARD_ONLY">
<select id="selectPerson" parameterType="int" resultType="User"> SELECT * FROM PERSON WHERE ID = #{id} </select>
insert, update 和 delete
insert 的几个属性说明:
id:唯一标识,随便写,在同一个命名空间下保持唯一,使用动态代理之后要求和方法名保持一致
parameterType:参数的类型,使用动态代理之后和方法的参数类型一致
useGeneratedKeys:开启主键回写
keyColumn:指定数据库的主键
keyProperty:主键对应的pojo属性名
标签内部:具体的sql语句。
<insert id="insertAuthor" parameterType="domain.blog.Author" //将会传入这条语句的参数的类全限定名或别名 flushCache="true" //将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空 statementType="PREPARED" //可选 STATEMENT,PREPARED 或 CALLABLE keyProperty="" //(仅适用于 insert 和 update)指定能够唯一识别对象的属性 keyColumn="" //(仅适用于 insert 和 update)设置生成键值在表中的列名 useGeneratedKeys="" //(仅适用于 insert 和 update)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的自动递增字段) timeout="20">
<insert id="insertAuthor"> insert into Author (id,username,password,email,bio) values (#{id},#{username},#{password},#{email},#{bio}) </insert>
update的几个属性说明:
id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。
<update id="updateAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">
<update id="updateAuthor"> update Author set username = #{username}, password = #{password}, email = #{email}, bio = #{bio} where id = #{id} </update>
delete 的几个属性说明:
id属性:当前名称空间下的statement的唯一标识(必须属性);
parameterType:传入的参数类型,可以省略。
标签内部:具体的sql语句。
<delete id="deleteAuthor" parameterType="domain.blog.Author" flushCache="true" statementType="PREPARED" timeout="20">
<delete id="deleteAuthor"> delete from Author where id = #{id} </delete>
2.#{}和${}
通常在方法的参数列表上加上一个注释@Param(“xxxx”) 显式指定参数的名字,然后通过${“xxxx”}或#{“xxxx”}
sql语句动态生成的时候,使用${};
sql语句中某个参数进行占位的时候#{}
/** * #号 * @param username1 * @return */ User queryUserListByName1(@Param("username1") String username1); /** * $号 * @param username2 * @return */ User queryUserListByName2(@Param("username2") String username2); <select id="queryUserListByName1" resultType="com.zpc.mybatis.pojo.User"> select * from tb_user WHERE user_name=#{username1} </select> <select id="queryUserListByName2" resultType="com.zpc.mybatis.pojo.User"> select * from tb_user WHERE user_name='${username2}'//手动加了引号 </select>
3.resultMap
使用:
4.sql片段
例如在UserMapper.xml中定义如下片段:
<sql id="commonSql"> id, user_name, password, name, age, sex, birthday, created, updated </sql>
则可以在UserMapper.xml中使用它:
<select id="queryUserById" resultMap="userResultMap"> select <include refid="commonSql"></include> from tb_user where id = #{id} </select> <select id="queryUsersLikeUserName" resultType="User"> select <include refid="commonSql"></include> from tb_user where user_name like "%"#{userName}"%" </select>
5.动态sql
if
使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分。比如:
<select id="findActiveBlogWithTitleLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <if test="title != null"> AND title like #{title} </if> </select>
choose、when、otherwise
它有点像 Java 中的 switch 语句
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE state = ‘ACTIVE’ <choose> <when test="title != null"> AND title like #{title} </when> <when test="author != null and author.name != null"> AND author_name like #{author.name} </when> <otherwise> AND featured = 1 </otherwise> </choose> </select>
trim、where、set
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG <where> <if test="state != null"> state = #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </where> </select>
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
如果 where 元素与你期望的不太一样,你也可以通过自定义 trim 元素来定制 where 元素的功能。比如,和 where 元素等价的自定义 trim 元素为:
<trim prefix="WHERE" prefixOverrides="AND |OR "> ... </trim>
用于动态更新语句的类似解决方案叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列。比如:
<update id="updateAuthorIfNecessary"> update Author <set> <if test="username != null">username=#{username},</if> <if test="password != null">password=#{password},</if> <if test="email != null">email=#{email},</if> <if test="bio != null">bio=#{bio}</if> </set> where id=#{id} </update>
这个例子中,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
来看看与 set 元素等价的自定义 trim 元素吧:
<trim prefix="SET" suffixOverrides=","> ... </trim>
foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 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>
6.高级查询
一对一查询(人和订单)
public class Order { private Integer id; private Long userId; private String orderNumber; private Date created; private Date updated; private User user; }
<resultMap id="OrderUserResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true"> <id column="id" property="id"/> <!--association:完成子对象的映射--> <!--property:子对象在父对象中的属性名--> <!--javaType:子对象的java类型--> <!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配--> <association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true"> <id column="user_id" property="id"/> </association> </resultMap> <select id="queryOrderWithUserByOrderNumber" resultMap="OrderUserResultMap"> select * from tb_order o left join tb_user u on o.user_id=u.id where o.order_number = #{number} </select>
一对多查询(订单和订单详情)
public class Order { private Integer id; private Long userId; private String orderNumber; private Date created; private Date updated; private User user; private List<OrderDetail> detailList; }
<resultMap id="OrderUserDetailResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true"> <id column="id" property="id"/> <!--collection:定义子对象集合映射--> <!--association:完成子对象的映射--> <!--property:子对象在父对象中的属性名--> <!--javaType:子对象的java类型--> <!--autoMapping:完成子对象的自动映射,若开启驼峰,则按驼峰匹配--> <association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true"> <id column="user_id" property="id"/> </association> <collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true"> <id column="id" property="id"/> </collection> </resultMap> <select id="queryOrderWithUserAndDetailByOrderNumber" resultMap="OrderUserDetailResultMap"> select * from tb_order o left join tb_user u on o.user_id=u.id left join tb_orderdetail od on o.id=od.order_id where o.order_number = #{number} </select>
多对多查询(订单和商品)
<resultMap id="OrderUserDetailItemResultMap" type="com.zpc.mybatis.pojo.Order" autoMapping="true"> <id column="id" property="id"/> <association property="user" javaType="com.zpc.mybatis.pojo.User" autoMapping="true"> <id column="user_id" property="id"/> </association> <collection property="detailList" javaType="List" ofType="com.zpc.mybatis.pojo.OrderDetail" autoMapping="true"> <id column="detail_id" property="id"/> <association property="item" javaType="com.zpc.mybatis.pojo.Item" autoMapping="true"> <id column="item_id" property="id"/> </association> </collection> </resultMap> <select id="queryOrderWithUserAndDetailItemByOrderNumber" resultMap="OrderUserDetailItemResultMap"> select * ,od.id as detail_id from tb_order o left join tb_user u on o.user_id=u.id left join tb_orderdetail od on o.id=od.order_id left join tb_item i on od.item_id=i.id where o.order_number = #{number} </select>