MyBatis-XML映射文件


MyBatis的真正强大在于它的映射语句,这也是它的魔力所在。
sql映射文件包含的顶级元素有:

  • cache 对给定命名空间的缓存配置
  • cache-ref 对其他命名空间缓存配置的引用
  • resultMap 用来描述如何从数据库结果集中来加载对象
  • sql 可被其他语句引用的可重用代码块
  • insert 映射插入语句
  • update 映射更新语句
  • delete 映射删除语句
  • select 映射查询语句

select

使用xml

查询语句是MyBatis中最常用的元素之一:

<select id="selectPerson" parameterType="int" resultType="hashmap">
	SELECT * FROM PERSON WHERE ID = #{id}
</select>

此时这条查询语句被称作selectPerson,接收一个int(或integer)类型的参数,并返回一个HashMap类型的对象,其中的键是列名,值便是结果行中的对应值。
select元素中的属性

属性描述
id命名空间中唯一的标识符,可以被用来引用这条语句
parameterType传入这条语句的参数的完全限定名和别名。可选,MyBatis可以通过类型处理器(TypeHandler)判断出具体传入语句的参数,默认值为未设置(unset)
resultType返回的期望类型的类的完全限定名或别名。注意如果返回的是集合,应该设置为集合包含的类型,而不是集合本身。不可与resultMap同时使用
resultMap外部resultMap的命名引用。结果集的映射是MyBatis对强大的特性,不可与resultType同时使用
flushCache设置为true后,只要语句被调用就会导致本地缓存和二级缓存被清空,默认false
useCache设置为true后,将会呆滞本条语句的结果被二级缓存缓存起来,默认对select元素为true
timeout这个设置是在抛出异常前,驱动程序等待数据库返回请求结果的秒数。默认未设置(unset)依赖驱动
fetchSize这是一个给驱动的提示,尝试让驱动程序每次批量返回结果行数和这个设置值相等。默认未设置(unset)依赖驱动
statementTypeSTATEMENT,PREPARED,CALLABLE中的一个。这会让MyBatis分别使用Statement,PreparedStatement或CallableStatement,默认值为PREPARED
resultSetTypeFORWARD_ONLY,SCROLL_SENSITIVE,SCROLL_INSENSITIVE或DEFAULT中的一个,默认未DEFAULT(等价于unset)依赖驱动
databaseId配置数据库厂商标识,MyBatis会加载所有的不带databaseId或配置当前databaseId的语句;如果带或者不带的语句都有,则不带的会被忽略
resultOrdered这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。
resultSets这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。

使用注解

首先我们需要在配置文件中开启注解;之后我们可以在dao接口中使用注解

@Select("select * from user where id = #{id}")
User findById(@Param("id") String id);

@Select 表示查询映射
@Param 表示要使用的参数

insert,update和delete

使用xml

数据变更语句insert,update和delete的实现非常接近

<insert id="insertAuthor" 
parameterType="domain.blog.Author" 
flushCache="true" 
statementType="PREPARED" 
keyProperty="" 
keyColumn="" 
useGeneratedKeys="" 
timeout="20">
insert into Author (id,username,password,email,bio)
  values (#{id},#{username},#{password},#{email},#{bio})
</insert>

<update id="updateAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
update Author set
    username = #{username},
    password = #{password},
    email = #{email},
    bio = #{bio}
  where id = #{id}
</update>

<delete id="deleteAuthor"
parameterType="domain.blog.Author"
flushCache="true"
statementType="PREPARED"
timeout="20">
delete from Author where id = #{id}
</delete>
属性描述
id命名空间中的唯一标识符,可被用来代表这条语句。
parameterType将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:true(对于 insert、update 和 delete 语句)。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。
statementTypeSTATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
useGeneratedKeys(仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。
keyProperty(仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认值:未设置(unset)。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。
keyColumn(仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。

使用注解

@Insert("insert into user (name, password) values (#{name}, #{password})")
pubilc int insertUser(@Param("name") String name, @Param("password") String password);

@Update("update user set password=#{password} where name=#{name}")
pubilc int updateUser(@Param("name") String name, @Param("password") String password)

@Delete("delete from user where name=#{name}")
pubilc int deleteUser(@Param("name") String name)

参数

<select id="selectUsers" resultType="User">
  select id, username, password
  from users
  where id = #{id}
</select>

上述示例展示了一个非常简单的命名参数映射。参数类型被设置为int,使用#{xx}相当于使用了一个?占位符。

<insert id="insertUser" parameterType="User">
	insert into users (id, username, password)
	values (#{id}, #{username}, #{password})
</insert>

如果使用User类型的参数对象传递到语句中,User类中定义的id、username、password等属性都将会被查找到,然后将它们的值传入预处理语句的参数中。
对向语句中传递参数来说,这样既简单又有效。

默认情况下,使用#{}格式的语法可以在MyBatis创建PreparedStatement时使用参数占位符并安全的设置参数(就像使用?一样)。这样更安全,迅速,通常也是首选做法,不过有时可能需要直接在sql语句中插入一个不转义的字符串。比如,像ORDER BY,我们可以这样做:

ORDER BY ${columnName}

此时MyBatis不会修改或转义字符串。当sql语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。比如:想要通过一个条件获取参数时

@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value)

此时${column}会被直接替换,而#{value}会被使用?预处理。这样就可以不同的条件及条件值进行查询数据。
使用这种方式接收用户的输入,并将其用于语句中的参数是不安全的,会导致潜在的sql注入攻击,因此要么不允许用户输入这些字段,要么自行转义并检验

结果映射

简单结果映射

resultMap元素是MyBatis中最重要最强大的元素。ResultMap的设计思想是,对于简单的语句根本不需要配置显式的结果映射,而对于复杂一点的语句只需要描述它们的关系即可。
一般情况下使用resultType=“map”,将所有的列映射到HashMap的键上,是可以满足开发需求的。但是有时我们可能会使用到javaBean或POJO作为模型。

<!-- mybatis-config.xml 中 -->
<typeAlias type="com.someapp.model.User" alias="User"/>

<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultType="User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

此时我们可以将resultType指定为我们提前写好的pojo类,这种情况下MyBatis会在幕后自动创建一个ResultMap,再基于属性名来映射列到JavaBean的属性上。如果列名和属性名没有精确匹配,可以在SELECT语句中对列使用别名来匹配标签;或者使用外部的resultMap来解决列名不匹配的问题

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

<select id="selectUsers" resultMap="userResultMap">
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>

高级结果映射

在我们实际开发过程中,我们可能会遇到一些复杂的查询和结果映射,MyBatis创建时的一个思想就是:数据库不可能永远是你所想或所需要的那个样子。
此时我们就需要用的一对一关联,一对多关联,甚至于多对多的映射。

一对一

1-首先需要在pojo类中创建一个属性,将关联查询的信息映射到这个属性中

public class Orders{
	private Integer id;
	private Integer userId;
	private Integer number;
	private User user;
}

2-在xml中编写reslutMap

<resultMap type="orders" id="ordersUserResultMap">
	<id column="id" property="id"/>
	<result column="user_id" property="userId"/>
	<result column="number" property="number"/>
	<association property="user" javaType="user">
		<id column="user_id" property="id"/>
		<result column="username" property="username"/>
	</association>
</resultMap>

在进行关联时MyBatis有两种不同的方式加载关联:
嵌套Select查询:通过执行另外一个sql映射语句来加载期望的复杂类型。

<resultMap id="blogResult" type="Blog">
  <association property="author" column="author_id" javaType="Author" select="selectAuthor"/>
</resultMap>

<select id="selectBlog" resultMap="blogResult">
  SELECT * FROM BLOG WHERE ID = #{id}
</select>

<select id="selectAuthor" resultType="Author">
  SELECT * FROM AUTHOR WHERE ID = #{id}
</select>

嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集

<resultMap id="blogResult" type="Blog">
  <id property="id" column="blog_id" />
  <result property="title" column="blog_title"/>
  <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
</resultMap>

<resultMap id="authorResult" type="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
  <result property="password" column="author_password"/>
  <result property="email" column="author_email"/>
  <result property="bio" column="author_bio"/>
</resultMap>

不推荐使用Select嵌套关联,相对来说这种方法虽然简单,但是性能表现不佳。

一对多

一对多的使用其实与一对一非常相似,区别在于它关联的是一个集合元素

private List<Post> posts
<collection property="posts" javaType="ArrayList" ofType="domain.blog.Post">
  <id property="id" column="post_id"/>
  <result property="subject" column="post_subject"/>
  <result property="body" column="post_body"/>
</collection>

一般情况下,MyBatis可以推断javaType属性,因此可以省略该属性;如此我们可以看出除了新增的ofType属性之外,它和一对一时完全相同的;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值