一、Mapper XML映射文件
MyBatis 的真正强大之处在于它的映射语句,这也是它的魔力所在。由于它的功能异常强大,映射器XML文件就显得相对简单。
SQL映射文件常用的元素如下:
- select 映射查询语句
- insert 映射插入语句
- update 映射更新语句
- delete 映射删除语句
- sql 可被其他语句引用的可重用语句块
- cache 给定命名空间的缓存配置
- cache-ref 其他命名空间缓存配置的引用
- resultMap 最复杂也是最强大的元素,用来描述如何从数据库结果集中加载对象
二、select 查询语句
在 SQL 映射文件中 元素用于映射 SQL 的 select 语句,其示例代码如下:
<select id="selectUserById" parameterType="Integer" resultType="com.zhang.pojo.User">
select * from user where id = #{id}
</select>
在上述代码中,这个语句被称作 selectUserById,其 id 值是唯一标识符,它接受一个 Integer 类型 的参数,返回一个 User 类型 的对象,结果集自动映射到 User 属性。
注意: 参数符号 #{id},这是告诉 MyBatis 创建一个预处理语句参数。通过JDBC,这样的一个参数在 SQL 中会由一个 “?” 来标识,并被传递到一个新的预处理语句中。以上配置文件执行时会生成如下JDBC代码。
String selectUserById = "select * from user where id = ?";
PreparedStatement ps = conn.prepareStatement(selectUserById);
ps.setInt(1,id);
还有一种 ${id},这种是字符串替换,在动态 SQL 解析阶段将会进行变量替换。
使用#{}可以有效的防止SQL注入,提高系统安全性。
< select> 元素除了有上述示例代码中的几个属性以外,还有一些常用的属性,如下表 所示。
属性名称 | 描述 |
---|---|
id | 它和 Mapper 的命名空间组合起来使用,是唯一标识符,可以被用来引用这条语句 |
parameterType | 表示传入 SQL 语句的参数类型的全限定名或别名。它是一个可选属性,MyBatis 能推断出具体传入语句的参数 |
resultType | SQL 语句执行后返回的类型(全限定名或者别名)。如果是集合类型,返回的是集合元素的类型,返回时可以使用 resultType 或 resultMap 之一 |
resultMap | 外部 resultMap 的命名引用。返回时可以使用 resultType 或 resultMap 之一 |
flushCache | 用于设置在调用 SQL 语句后是否要求 MyBatis 清空之前查询的本地缓存和二级缓存,默认值为 false,如果设置为 true,则任何时候只要 SQL 语句被调用都将清空本地缓存和二级缓存 |
useCache | 启动二级缓存的开关,默认值为 true,表示将査询结果存入二级缓存中 |
timeout | 用于设置超时参数,单位是秒(s),超时将抛出异常 |
fetchSize | 获取记录的总条数设定 |
statementType | 告诉 MyBatis 使用哪个 JDBC 的 Statement 工作,取值为 STATEMENT(Statement)、 PREPARED(PreparedStatement)、CALLABLE(CallableStatement) |
resultSetType | 这是针对 JDBC 的 ResultSet 接口而言,其值可设置为 FORWARD_ONLY(只允许向前访问)、SCROLL_SENSITIVE(双向滚动,但不及时更新)、SCROLLJNSENSITIVE(双向滚动,及时更新) |
三、insert、update 和 delete
insert、update 和 delete 元素用来映射 DML 语句,是MyBatis 中常用的元素之一。
insert、update 和 delete 元素配置和 select 非常接近,但是也有它们的特有属性:
- useGeneratedKeys: (仅对 insert 和 update 有用) 这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来获取有数据库内部生成的主键(比如,像 MySQL 和 SQL Server 这样的关系数据库系统的自动递增字段),默认值为 false。
- keyProperty:(仅对 insert 和 update 有用) 唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认为 unset。如果是联合主键,可以将多个值用逗号分隔开。
- keyColumn:(仅对 insert 和 update 有用) 该属性用于设置第几列是主键,当主键列不是表中的第 1 列时需要设置。如果是联合主键,可以将多个值用逗号隔开。
1)主键(自动递增)回填
MySQL、SQL Server 等数据库的表格可以采用自动递增的字段作为主键,有时可能需要使用这个刚刚产生的主键,用于关联其他业务。
首先为 com.zhang.mapper 包中的 SQL 映射文件 UserMapper.xml 中 id 为 insertUser 的 < insert> 元素添加 keyProperty 和 useGeneratedKeys 属性,具体代码如下:
<!--添加一个用户,成功后将主键值返回填给id(user的属性)-->
<insert id="insertUser" parameterType="com.zhang.pojo.User" keyProperty="id" useGeneratedKeys="true">
insert into user(id,name,sex,age) values(default,#{name},#{sex},#{age})
</insert>
然后再 com.zhang.work 包的 MainApp 类进行调用,具体代码如下:
User user = new User();
user.setName("小明");
user.setSex("男");
user.setAge(20);
int add = userService.addUser(user);
System.out.println("添加了" + add + "条记录");
System.out.println("添加记录的主键是" + user.getId());
2)自定义主键
如果在实际工程中使用的数据库不支持主键自动递增(例如 Oracle),或者取消了主键自动递增的规则,可以使用 MyBatis 的 < selectKey> 元素来自定义生成主键。具体配置示例代码如下:
<!-- 添加一个用户,#{uname}为 com.mybatis.po.MyUser 的属性值 -->
<insert id="insertUser" parameterType="com.po.MyUser">
<!-- 先使用selectKey元素定义主键,然后再定义SQL语句 -->
<selectKey keyProperty="uid" resultType="Integer" order="BEFORE">
select if(max(uid) is null,1,max(uid)+1) as newUid from user)
</selectKey>
insert into user (uid,uname,usex) values(#{uid},#{uname},#{usex})
</insert>
在执行上述示例代码时,< selectKey> 元素首先被执行,该元素通过自定义的语句设置数据表的主键,然后执行插入语句。
< selectKey> 元素的 keyProperty 属性指定了新生主键值返回给 PO 类(com.po.MyUser)的哪个属性。
- order 属性可以设置为 BEFORE 或 AFTER。BEFORE 表示先执行 元素然后执行插入语句。AFTER 表示先执行插入语句再执行 元素。
insert、update 和 delete 语句的示例:
<!--添加一个用户-->
<insert id="insertUser" parameterType="com.zhang.pojo.User" >
insert into user(id,name,sex,age) values(default,#{name},#{sex},#{age})
</insert>
<!--修改一个用户-->
<update id="updateUser" parameterType="com.zhang.pojo.User">
updare user set name = #{name},sex = #{sex},age = age + 1 where id = #{id}
</update>
<!--删除一个用户-->
<delete id="deleteUser" parameterType="Integer">
delete from user where id = #{id}
</delete>
四、sql 元素
< sql> 元素的作用在于可以定义 SQL 语句的一部分(代码片段),以方便后面的 SQL 语句引用它,例如反复使用的列名。
MyBatis中sql标签与include标签进行配合,灵活的查询需要的数据。
<sql id="ref">
id,name,sex,age
</sql>
<select id="selectUserById" resultType="com.zhang.pojo.User">
select
<include refid="ref"/>
from
user where id = #{id}
</select>
sql 标签中 id属性 对应 include标签 中的 refid属性 。通过include标签将sql片段和原sql片段进行拼接成一个完成的sql语句进行执行。
include标签 中还可以用 property标签,用以指定自定义属性。
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
<select id="selectUser" resultType="map">
select
<include refid="userColumns"><property name="alias" value="u1"/></include>,
<include refid="userColumns"><property name="alias" value="u2"/></include>
from user u1
cross join user u2
</select>
在sql标签中通过${}取出对应include标签中设置的属性值。
五、参数(Parameters)
-
简单参数映射
原生的类型或者简单数据类型(比如整形和字符串),因为没有相关属性,它会完全用参数值来代替。例如:
<select id="selectUserById" parametersType="Intager" resultType="com.zhang.pojo.User"> select * from user where id = #{id} </select>
-
对象参数映射
如果传入一个复杂对象(比如 User),行为就有点不同了。例如:
<insert id="insertUser" parametersType="com.zhang.pojo.User"> insert into user values(default,#{name},#{sex},#{age}) </insert>
如果User类型的参数对象被传递到了语句中,如 #{name} 语句则会查找参数对象User 的 name 属性,#{sex},#{age}也是一样,然后将它们的值传入预处理语句的参数中。
-
多个参数映射
-
利用 #{参数顺序} 接收参数
mapper 层的函数方法
public List<Student> selStudentBySex(String sex,Intager pageNumber);
对应的 xml 文件
<select id="selStudentBySex" resultType="com.zhang.pojo.Student"> select * from student where sex=#{0} limit #{1},5 </select>
其中,#{0}代表接收的是mapper层中的第一个参数,#{1}代表接收的是mapper层中的第二个参数,更多参数依次往后加即可。
-
利用 Map 传递多个参数
mapper 层的函数方法public List<Student> selStudentBySex(Map paramMap);
service 实现类的函数方法
Map<String,Object> map = new HashMap<String, Object>(); map.put("sex","男"); map.put("pageNumber",0); List<Student> studentList = studentService.findStudentBySex(map);
对应的 xml 文件
<select id="selStudentBySex" resultType="com.zhang.pojo.Student"> select * from student where sex=#{sex} limit #{pageNumber},5 </select>
这种方法不太直观,无法从接口看到传递的参数类型。
-
利用注解@param() 传递多个参数(推荐使用)
mapper 层的函数方法
public List<Student> selStudentBySex(@Param("sex")String sex,@Param("pageNumber")Integer pageNumber);
对应的 xml 文件
<select id="selStudentBySex" resultType="com.zhang.pojo.Student"> select * from student where sex=#{sex} limit #{pageNumber},5 </select>
如果多个参数中又一个复杂对象参数该怎么办?
mapper 层的函数方法
public List<Student> selStudentBySex(@Param("student")Student student,@Param("pageNumber")Integer pageNumber);
对应的 xml 文件
<select id="selStudentBySex" resultType="com.zhang.pojo.Student"> select * from student where sex=#{student.sex} limit #{pageNumber},5 </select>
在 xml 文件中 使用 @Param 注解里的对象的属性即可,#{student.sex}
-
参考文章:
- 《Spring + MyBatis 企业应用开发》
- 《C语言中文网》