目录
MyBatis中文官方文档:XML 映射器_MyBatis中文网
MyBatis中文官方文档:XML 映射器_MyBatis中文网
1.为什么要用XML映射器?
MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。
(因为我们学过JDBC就知道通过JDBC对数据库进行操作时,那部分增删改查的代码都是固定的套路,而且代码比较长,每次都去写的话就会很不方便,所以就可以用XML映射来简化我们的代码。)简言之,就是简化代码的作用。
2.顶级元素
-
select
-
insert
-
update
-
delete
-
resultMap 映射的结果集
前期项目搭建:
创建数据库:student和teacher表
idea连接数据库
创建项目:
1.新建一个maven项目
2.导入依赖(mybatis \ mysql\ junit\ 日志)
3.创建核心配置文件(mybatis.xml)
4.写工具类(MyBatisUtils) (为什么一定要try...catch呢)SqlSession不是安全的线程
5.数据库对应的pojo类
6.编写StudentMapper映射文件
7.StdentMapper.xml文件(注意:每个Mapper文件都要在mybatis-config.xml中注册!)
注意:导入包的时候一定要看清楚!!!导错了项目运行会报错!在idea显示代码提示的时候也要看清楚参数再确定
2.1select查询
2.1.1 普通查询
1.查询所有记录
-
编写接口方法:Mapper接口
-
编写SQL语句 (参数;返回结果)
-
执行方法,测试
StudentMapper接口:
List<Student> selectAllStudents();
StudentMapper.xml映射文件
<mapper namespace="com.tang.dao.StudentMapper">
<select id="selectAllStudents" resultType="com.tang.pojo.Student">
select * from mybatis.student
</select>
</mapper>
问题:数据库表的字段名称 和 实体类的属性名称 不一样, 则不能自动封装数据
-
起别名:对不一样的列名起别名,让列名的别名和实体类的属性名一样
-
sql片段:起别名
<sql id="student_column">
sid,sname,teacher_id as teacherId
</sql>
<select id="selectAllStudents" resultType="Student">
select
<include refid="student_column"/>
from student
</select>
缺点:不灵活
-
resultMap映射: 将与属性名不同的列名映射过来
<!-- id:唯一标识 type:返回类型,支持别名-->
<resultMap id="studentResultMap" type="Student">
<!-- id:主键字段的映射 result:普通字段的映射-->
<result column="teacher_id" property="teacherId" />
<!-- column:表的列名 property:实体类的属性名-->
</resultMap>
<select id="selectAllStudents" resultMap="studentResultMap">
select *
from mybatis.student
</select>
总:1.定义resultMap标签
2.在<select>标签中用resultMap属性替换resultType属性
2.根据id查询记录
<mapper namespace="com.tang.dao.StudentMapper">
<select id="selectById" resultMap="studentResultMap">
select * from student where sid=#{sid}
</select>
</mapper>
参数占位符: 1.#{} : 会将其替换为?,为了防止SQL注入 2.${} : 拼sql,会存在SQL注入问题 3.使用时机:
* 参数传递的时候: #{}
*表名或者列名不固定的情况下:${}
参数类型:parameterType="int"(可省略) 特殊字符处理:
-
转义字符 (转义字符比较少的时候)
select * from student where sid < #{sid}
-
CDATA区
<select id="selectById" resultMap="studentResultMap" >
select *
from student
where sid
<![CDATA[
<
]]>
#{sid}
</select>
2.1.2 多条件查询
//1.散装参数 如果有多个参数,需要使用@Param("SQL参数占位符名称")
List<Student> selectByCondition(@Param("sid") int id,@Param("sname")String name,@Param("teacher_id")int tid);
//2.对象参数 对象的属性名称要和参数占位符一致
List<Student> selectByCondition(Teacher teacher);
//3.Map集合参数
List<Student> selectByCondition(Map map);
test:查询名字里有“玉”并且老师id=2的所有学生信息
<select id="selectByCondition" resultMap="studentResultMap">
select * from student where sname like #{sName} and teacher_id = #{teacherId}
</select>
3.Map集合参数
Map map =new HashMap();
map.put("sName","%玉%");
map.put("teacherId",2);
键名对应参数占位名
总结:SQL语句设置多个参数有几种方式?
1)散装参数:需要使用@Param("SQL中的参数占位符名称")
2)实体类封装参数
只需要保证SQL语句中的参数名和实体类属性名对应上,即可设置成功
3)map集合
只需要保证SQL语句中的参数名和map集合的键的名称对应上,即可设置成功
模糊查询
-
java代码执行的时候传递通配符% %
mapper.getLikeList("%李%");
-
在sql语句中拼接% %
select * from mybatis.student where snmae like "%"#{sName}"%"
第二种更好,安全性更高
2.2 insert添加
<insert id="addStudent" paramType="com.tang.pojo.Student">
insert into mybatis.student(sid,sname,teacher_id)
values(#{sId},#{sName},#{teacher_id});
</insert>
最后要事务提交,可以手动提交,也可以自动提交。
openSession():默认开启事务,进行增删改操作后需要使用sqlSession.commit()手动提交事务 openSession(true):自动提交事务(关闭事务)
问题:查不了主键id ? 需要主键返回insert(Brand brand) into goods后想要得到brand.id
<insert id="addStudent" parameterType="Student" useGeneratedKeys="true" keyProperty="sId">
insert into student values(#{sId},#{sName},#{teacherId})
</insert>
2.3 update修改
1.全部字段修改
<update id="updateStudent" resultType="map">
update student set tid=#{tId} where sid=#{sId}
</update>
2.修改动态字段
不知道用户修改的是哪些字段--> if标签判断
<set>处理逗号问题
<update id="updateStudent" parameterType="Map">
update student
<set>
<if test="sName != null and sName != '' ">
sname = #{sName},
</if>
<if test="teacherId != null ">
teacher_id = #{teacherId}
</if>
</set>
where sid=#{sId}
</update>
2.4delete删除
1.删除一个
<delete id="deleteStudent" paramType="int">
delete from student where sid=#{sId}
</delete>
2.批量删除
void deleteByIds(@Param("ids")int[] ids);
<!-- mybatis会将数组参数封装为一个Map集合
* 默认: array=数组 在collection里面写array
* 使用@Param注解来改变map默认key的名称 array换成了ids
-->
<delete id="deleteByIds" >
delete from student
where sid in(
<foreach collection="ids" item="sId" open="(" close=")" separator=",">
#{sId}
</foreach>
)
</delete>
separator:分隔符
open:开始符号 ; close:结束符号
2.5 resultMap
2.5.1 什么是resultMap
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets
数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作。实际上,在为一些比如连接的复杂语句编写映射代码的时候,一份 resultMap
能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
上面示例中使用的map只是简单地将所有的列映射到 HashMap
的键上,这由 resultType
属性指定,它们没有显式指定 resultMap
。
2.5.2 定义resultMap:
<resultMap id="studentResultMap" type="Student">
<id property="sId" column="sid" />
<result property="sNmae" column="sname"/>
<result property="tId" column="tid"/>
</resultMap>
-
id用于标识一个结果集映射
起类型别名:
<typeAlias type="com.tang.pojo.Student" alias="Student"/>
在mybatis-config.xml核心配置文件中取别名
2.5.3 resultMap的属性:
1.id & result
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
这些元素是结果映射的基础。id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。
这两者之间的唯一不同是,id 元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。
两个元素都有一些属性:
属性 | 描述 |
---|---|
property | 映射到列结果的字段或属性。如果 JavaBean 有这个名字的属性(property),会先使用该属性。否则 MyBatis 将会寻找给定名称的字段(field)。 无论是哪一种情形,你都可以使用常见的点式分隔形式进行复杂属性导航。 比如,你可以这样映射一些简单的东西:“username”,或者映射到一些复杂的东西上:“address.street.number”。 |
column | 数据库中的列名,或者是列的别名。一般情况下,这和传递给 resultSet.getString(columnName) 方法的参数一样。 |
javaType | 一个 Java 类的全限定名,或一个类型别名(关于内置的类型别名,可以参考上面的表格)。 如果你映射到一个 JavaBean,MyBatis 通常可以推断类型。然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证行为与期望的相一致。 |
property对应pojo里面的变量名 , column对应数据库的字段名
注:只能写简单的,复杂的属性需要单独写
2.关联
association: 一对一关联(has one) collection:一对多关联(has many)
<association property="author" column="blog_author_id" javaType="Author">
<id property="id" column="author_id"/>
<result property="username" column="author_username"/>
</association>
关联(association)元素处理“有一个”类型的关系。 比如,在我们的示例中,一个博客有一个用户。关联结果映射和其它类型的映射工作方式差不多。 你需要指定目标属性名以及属性的JavaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。
关联的不同之处是,你需要告诉 MyBatis 如何加载关联。MyBatis 有两种不同的方式加载关联:
-
嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
-
嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。
和普通的结果映射相比,它只在 select 和 resultMap 属性上有所不同。
1.嵌套 Select 查询
(查询学生及其对应的老师信息;一个学生只对应一个老师)
<resultMap id="studentResultMap" type="Student">
<id property="sId" column="sid" />
<result property="sName" column="sname"/>
<association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
</resultMap>
<mapper namespace="com.tang.dao.StudentMapper">
<select id="getStudents" resultMap="studentResultMap">
select * from mybatis.student
</select>
<select id="getTeacher" resultType="com.tang.pojo.Teacher">
select * from mybatis.teacher where tid=#{tid}
</select>
</mapper>
(association里面的property是pojo.Student里定义的Teacher变量名;column对应数据库里student表中的外键tid;)
(这里的getTeacher不需要在Mapper接口中声明)
2.关联的嵌套结果映射
当需要实现多表查询的时候,通常需要使用association标签来进行结果集的嵌套。
<resultMap id="resultMap2" type="Student">
<result property="sId" column="sid"/>
<result property="sName" column="sname"/>
<association property="teacher" column="tid" javaType="Teacher" resultMap="teacherResultMap"/>
</resultMap>
<resultMap id="teacherResultMap" type="Teacher">
<id property="tId" column="tid"/>
<result property="tName" column="tname"/>
</resultMap>
<select id="getStudents" resultMap="resultMap2">
select s.*,t.* from student s, teacher t where t.tid=s.tid
</select>
集合
<collection property="posts" ofType="domain.blog.Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
集合元素和关联元素几乎是一样的,它们相似的程度之高,以致于没有必要再介绍集合元素的相似部分。 所以让我们来关注它们的不同之处吧。接下来你会注意到有一个新的 “ofType” 属性。这个属性非常重要,它用来将 JavaBean(或字段)属性的类型和集合存储的类型区分开来。在一般情况下,MyBatis 可以推断 javaType 属性,因此并不需要填写。m
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
读作: “posts 是一个存储 Post 的 ArrayList 集合”
一个博客(Blog)只有一个作者(Author)。但一个博客有很多文章(Post)。 在博客类中,这可以用下面的写法来表示:
private List<Post> posts;
要像上面这样,映射嵌套结果集合到一个 List 中,可以使用集合元素。 和关联元素一样,我们可以使用嵌套 Select 查询,或基于连接的嵌套结果映射集合。
集合的嵌套select查询
(一个老师对应多个学生)
<resultMap id="teacherResultMap1" type="Teacher">
<id property="tId" column="tid"/>
<result property="tName" column="tname"/>
<collection property="students" column="tid" ofType="Student" select="getStudents"/>
</resultMap>
<select id="getTeachers" resultMap="teacherResultMap1">
select * from teacher
</select>
<select id="getStudents" resultType="Student">
select * from student where tid=#{tid}
</select>
(collection里面的property是pojo.Teacher类里面定义的Student的List集合;column是数据库teacher表里的tid;
ofType是用来将字段属性的类型和集合存储的类型区分开来,即将Student类和List<Student>区别开)
集合的嵌套结果映射
<resultMap id="teacherResultMap2" type="Teacher">
<id property="tId" column="tid"/>
<result property="tName" column="tname"/>
<collection property="students" column="tid" ofType="Student">
<id property="sId" column="sid"/>
<result property="sName" column="sname"/>
<result property="teacher_id" column="tid"/>
</collection>
</resultMap>
<select id="getTeachersAndStudents" resultMap="teacherResultMap2">
select s.*,t.* from teacher t,student s where s.tid=t.tid
</select>