概述
映射器配置文件
映射配置文件主要完成的是对数据库的操作,我们直接将sql语句写在映射配置文件中,比如下面的例子:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis3.mappers.StudentMapper">
<select id="findStudentById" parameterType="int" resultType="Student">
select stud_id as studId, name, email, dob
from Students where stud_id=#{studId}
</select>
</mapper>
上面的文件就是一个映射配置文件:
namespace
是命名空间- id是该标签的唯一标识符,在同一个命名空间中该id唯一
parameterType
是输入参数的类型resultType
是输出参数的类型
在java代码中我们想要调用该查询语句可以使用下面的代码:
public Student findStudentById(Integer studId){
//通过封装类来获取sqlSession
SqlSession sqlSession = MyBatisUtil.getSqlSession();
try{
Student student = sqlSession.selectOne("com.mybatis3.mappers.StudentMapper.
findStudentById", studId);
return student;
}finally{
sqlSession.close();
}
}
然后再通过sqlSession
的各种api
(这里使用的是selectOne
())去调用我们的sql
映射。对于这种方式只有当我们执行的时候才会知道是否出错,所以还可以使用另外一种更好的方式。
mapper映射器接口
另一种方式是当配置映射文件后,可以创建一个完全对应的映射器接口,所谓的完全对应主要有以下几个方面:
- 接口所在的包和配置文件所在的包一致
- 接口名与配置文件名一致
上面两条结合起来比如StudentMapper.xml
所在的包名是com.mybatis.mappers
那么对应的接口名就是com.mybatis.mappers.StudentMapper.java
- 接口中的方法名就是配置文件中id值
- 方法参数类型为
parameterType
对应值 - 方法返回值类型为
returnType
对应值 - 命名空间
namespace
与接口的完全限定名一致
对应上述的StudentMapper.xml
文件,可以创建一个映射器接口StudentMapper.java
package com.mybatis.mapper;
public interface StudentMapper{
Student findStudentById(Integer id);
}
使用接口映射器
public Student findStudentById(Integer stuId){
SqlSession sqlSession = MybatisUtil.getSqlSession();
try{
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);
return studentMapper.findStudentById(stuId);
}finally{
sqlSession.close();
}
}
映射语句
Mybatis
提供了多种元素来配置不同类型的语句,比如select
,insert
,update
,delete
,不过需要注意的是这些元素只是为了增强可读性,并不是说select
语句必须写在select
元素里面。但是为了良好的可读性还是要将对应类型的sql
语句写在对应的标签里面比较好。
insert语句
insert配置
<insert id="insertStudent" parameterType="Student">
INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL, PHONE)
VALUES(#{studId},#{name},#{email},#{phone})
</insert>
id
是在当前命名空间中唯一的值parameterType
是输入参数类型
insert调用
int count = sqlSession.insert("com.mybatis3.mappers.StudentMapper.insertStudent", student);
该方法返回的值是影响的行数。
insert语句自动生成主键配置
mysql
在mysql
中可以为自动生成(auto-generated
)主键的咧stud_id
插入值,可以使用useGenerateKeys
和keyProperty
属性让数据库生成auto_increment
列的值,并将生成的值设置到其中一个输入对象属性内。
<insert id="insertStudent" parameterType="Student" useGeneratedKeys="true"
keyProperty="studId">
INSERT INTO STUDENTS(NAME, EMAIL, PHONE)
VALUES(#{name},#{email},#{phone})
</insert>
配置了主键自动生成后STUD_ID
列的值将会被Mysql
数据库自动生成,并且生成的值会被设置到student
对象的studId
属性上。
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
mapper.insertStudent(student);
int studId = student.getStudId();
oracle
order=“before”
oracle
是不支持auto_increment
列,而是使用序列(sequence
)来生成主键值,假如我们有一个stud_id_seq
的序列来生成stud_id
主键值,那么可以使用如下代码来生成主键:
<insert id="insertStudent" parameterType="Student">
<selectKey keyProperty="studId" resultType="int" order="BEFORE">
SELECT STUD_ID_SEQ.NEXTVAL FROM DUAL
</selectKey>
INSERT INTO STUDENTS(STUD_ID,NAME,EMAIL, PHONE)
VALUES(#{studId},#{name},#{email},#{phone})
</insert>
使用子元素类生成主键值,并将值保存到Student对象的studId属性上,上面的order=“before”表示mybatis
将取得序列的下一个值作为主键值,并且在执行insert sql
语句之前将值设置到studId
属性上。
order=“after”
上面使用的是order=“before”,order的值还可以为after,获取序列的下一个值时使用触发器(trigger)来设置主键值,并且在执行insert sql语句之前将值设置到主键列上,此时的配置文件为:
<insert id="insertStudent" parameterType="Student">
INSERT INTO STUDENTS(NAME,EMAIL, PHONE)
VALUES(#{name},#{email},#{phone})
<selectKey keyProperty="studId" resultType="int" order="AFTER">
SELECT STUD_ID_SEQ.CURRVAL FROM DUAL
</selectKey>
</insert>
update
与delete
语句是类似的,所以不再写,重点是select
语句。
select语句
一个简单的查询的映射
<select id="findStudentById" parameterType="int" resultType="Student">
SELECT STUD_ID, NAME, EMAIL, PHONE FROM STUDENTS WHERE STUD_ID=#{studId}
</select>
命名空间方式调用
int studId =1;
Student student = sqlSession.selectOne("com.mybatis3.mappers.
StudentMapper.findStudentById", studId);
映射接口调用
package com.mybatis3.mappers;
public interface StudentMapper{
Student findStudentById(Integer studId);
}
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.findStudentById(studId);
查询映射需要注意的问题(属性与字段对应规则)
在上面的例子查询结果中student对象的studId属性是不会有值的,这是因为mybatis自动对javaBean中的列中和列名匹配的属性进行填充,表中是stud_id,javaBean中是studId,二者是不对应的,如果对应可以将查询结果取别名:
<select id="findStudentById" parameterType="int" resultType="Student">
SELECT STUD_ID AS studId, NAME,EMAIL, PHONE FROM STUDENTS WHERE STUD_ID=#{studId}
</select>
select返回多条结果
返回多条结果时配置文件与返回一条是一样的,resultType返回的依然是对象而不是一个集合。
<select id="findAllStudents" resultType="Student">
SELECT STUD_ID AS studId, NAME,EMAIL, PHONE FROM STUDENTS
</select>
通过命名空间调用
List<Student> students =
sqlSession.selectList("com.mybatis3.mappers.StudentMapper.findAllStudents");
通过接口映射器调用
定义接口
package com.mybatis3.mappers;
public interface StudentMapper{
List<Student> findAllStudents();
}
调用
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.findAllStudents();
结果集映射ResultMaps
ResultMaps
是用来将查询结果集映射到javaBean
的属性中。使用步骤:
- 定义一个车
ResultMap
结果集 - 在
select
标签中引用resultMap
一个简单的案例:
<resultMap id="StudentResult" type="com.mybatis3.domain.Student">
<id property="studId" column="stud_id" />
<result property="name" column="name" />
<result property="email" column="email" />
<result property="phone" column="phone" />
</resultMap>
<select id="findAllStudents" resultMap="StudentResult">
SELECT * FROM STUDENTS
</select>
<select id="findStudentById" parameterType="int" resultMap="StudentResult">
SELECT * FROM STUDENTS WHERE STUD_ID=#{studId}
</select>
注意事项:
resultMap
的id在同一个命名空间内部应该是唯一的type
属性是完全限定类名或者是返回类型的别名resultType
与resultMap
两者之间只能使用一个,不能同时使用
将结果集映射到HashMap中
如果将resultType
类型设置为map(java.util.HashMap)
,结果集的列名将会作为Map的key值,列值作为Map的value值。
返回单个结果
配置文件:
<select id="findStudentById" parameterType="int" resultType="map">
SELECT * FROM STUDENTS WHERE STUD_ID=#{studId}
</select>
部分测试代码:
HashMap<String,Object> studentMap = sqlSession.selectOne("com.
mybatis3.mappers.StudentMapper.findStudentById", studId);
System.out.println("stud_id :"+studentMap.get("stud_id"));
System.out.println("name :"+studentMap.get("name"));
System.out.println("email :"+studentMap.get("email"));
System.out.println("phone :"+studentMap.get("phone"));
返回多个结果
配置文件:
<select id="findAllStudents" resultType="map">
SELECT STUD_ID, NAME, EMAIL, PHONE FROM STUDENTS
</select>
部分测试代码:
List<HashMap<String, Object>> studentMapList =
sqlSession.selectList("com.mybatis3.mappers.StudentMapper.findAllS
tudents");
for(HashMap<String, Object> studentMap : studentMapList){
System.out.println("studId :" + studentMap.get("stud_id"));
System.out.println("name :" + studentMap.get("name"));
System.out.println("email :" + studentMap.get("email"));
System.out.println("phone :" + studentMap.get("phone"));
}
拓展ResultMap
这里的拓展类似于java中的继承。
配置文件案例:
<!--这里type直接写student是因为有了别名-->
<resultMap type="Student" id="StudentResult">
<id property="studId" column="stud_id" />
<result property="name" column="name" />
<result property="email" column="email" />
<result property="phone" column="phone" />
</resultMap>
<resultMap type="Student" id="StudentWithAddressResult" extends="StudentResult">
<result property="address.addrId" column="addr_id" />
<result property="address.street" column="street" />
<result property="address.city" column="city" />
<result property="address.state" column="state" />
<result property="address.zip" column="zip" />
<result property="address.country" column="country" />
</resultMap>
id为StudentWithAddressResult
的ResultMap
继承了id
为StudentResult
的ResultMap
这样如果只想映射Student
的话那么可以只使用id
为StudentResult
的ResultMap
就可以,但是如果想要映射Student
与Address
数据,那么就可以使用id为StudentWithAddressResult
的ResultMap
。
一对一映射
基本一对一映射案例
比如现在有两个表Student
与Address
关系如下:
Student表:
stud_id | name | phone | addr_id | |
---|---|---|---|---|
1 | 张三 | hrgqg@qq.com | 12413 | 1 |
2 | 李四 | a1232@qq.com | 3545 | 2 |
Address表:
addr_id | streef | city | state | zip | country |
---|---|---|---|---|---|
1 | jafgoi | HK | 7839 | 1398 | usa |
2 | hairog | HK | 8193 | 89131 | usa |
这两个表是有关联的,Student
表与Address
表之间的关联是Student
表中的addr_id
是外键。
此时的javaBean
代码如下:
AddressBean
:
public class Address{
private Integer addrId;
private String street;
private String city;
private String state;
private String zip;
private String country;
// setters & getters
}
StudentBean
:
public class Student{
private Integer studId;
private String name;
private String email;
private PhoneNumber phone;
private Address address;
//setters & getters
}
配置文件:
<resultMap type="Student" id="StudentWithAddressResult">
<id property="studId" column="stud_id" />
<result property="name" column="name" />
<result property="email" column="email" />
<result property="phone" column="phone" />
<result property="address.addrId" column="addr_id" />
<result property="address.street" column="street" />
<result property="address.city" column="city" />
<result property="address.state" column="state" />
<result property="address.zip" column="zip" />
<result property="address.country" column="country" />
</resultMap>
<select id="selectStudentWithAddress" parameterType="int"
resultMap="StudentWithAddressResult">
SELECT STUD_ID, NAME, EMAIL, A.ADDR_ID, STREET, CITY, STATE,
ZIP, COUNTRY FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON
S.ADDR_ID=A.ADDR_ID WHERE STUD_ID=#{studId}
</select>
由于在Student
对象中包含Address
对象,所以在配置文件中可以使用圆点记法为内嵌对象赋值。
上面这种方式如果想要查询Address
就相当于也要查询Student
,这样会有重复映射,此时可以使用嵌套结果ResultMap
和嵌套select
查询语句。
嵌套ResultMap来实现一对一映射
has-one关联
依然是上面的案例,此时的配置文件如下:
<resultMap type="Address" id="AddressResult">
<id property="addrId" column="addr_id" />
<result property="street" column="street" />
<result property="city" column="city" />
<result property="state" column="state" />
<result property="zip" column="zip" />
<result property="country" column="country" />
</resultMap>
<resultMap type="Student" id="StudentWithAddressResult">
<id property="studId" column="stud_id" />
<result property="name" column="name" />
<result property="email" column="email" />
<association property="address" resultMap="AddressResult" />
</resultMap>
<select id="findStudentWithAddress" parameterType="int"
resultMap="StudentWithAddressResult">
SELECT STUD_ID, NAME, EMAIL, A.ADDR_ID, STREET, CITY, STATE,
ZIP, COUNTRY FROM STUDENTS S LEFT OUTER JOIN ADDRESSES A ON
S.ADDR_ID=A.ADDR_ID WHERE STUD_ID=#{studId}
</select>
元素被用来导入“has-one”类型的关联,在上面的例子中使用元素引用了在同一个xml
文件中定义的(resultMap
的值是另外一个ResultMap
的id
)
内联关联
内联关联配置文件如下:
<resultMap type="Student" id="StudentWithAddressResult">
<id property="studId" column="stud_id" />
<result property="name" column="name" />
<result property="email" column="email" />
<association property="address" javaType="Address">
<id property="addrId" column="addr_id" />
<result property="street" column="street" />
<result property="city" column="city" />
<result property="state" column="state" />
<result property="zip" column="zip" />
<result property="country" column="country" />
</association>
</resultMap>
使用嵌套Select来实现一对一映射
配置文件:
<resultMap type="Address" id="AddressResult">
<id property="addrId" column="addr_id" />
<result property="street" column="street" />
<result property="city" column="city" />
<result property="state" column="state" />
<result property="zip" column="zip" />
<result property="country" column="country" />
</resultMap>
<select id="findAddressById" parameterType="int"
resultMap="AddressResult">
SELECT * FROM ADDRESSES WHERE ADDR_ID=#{id}
</select>
<resultMap type="Student" id="StudentWithAddressResult">
<id property="studId" column="stud_id" />
<result property="name" column="name" />
<result property="email" column="email" />
<association property="address" column="addr_id" select="findAddressById" />
</resultMap>
<select id="findStudentWithAddress" parameterType="int"
resultMap="StudentWithAddressResult">
SELECT * FROM STUDENTS WHERE STUD_ID=#{Id}
</select>
在此方式中,元素的 select
属性被设置成了 id
为 findAddressById
的语句。这里,两个分开的SQL
语句将会在数据库中执行,第一个调用 findStudentById
加载 student
信息,而第二个调用 findAddressById
来加载 address
信息。Addr_id
列的值将会被作为输入参数传递给 selectAddressById
语句。
调用语句:
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
Student student = mapper.findStudentWithAddress(studId);
System.out.println(student);
System.out.println(student.getAddress());
一对多映射
案例表数据
tutors
:
tutor_id | tutor_name | phone | addr_id | |
---|---|---|---|---|
1 | 张三 | ad@qq.com | 3213 | 1 |
2 | 李四 | asg@qq.com | 1525 | 2 |
course:
course_id | name | description | start_date | end_date | tutor_id |
---|---|---|---|---|---|
1 | javaSE | java Se | 2019-01-01 | 2019-01-01 | 1 |
2 | javaEE | java Ee | 2019-01-01 | 2019-01-01 | 2 |
3 | Mybatis | Mybatis | 2019-01-01 | 2019-01-01 | 2 |
上面教授与课程表是一对多(外键在多的一方)的关联,可以看到李四对应两门课程。
tutorBean
public class Tutor{
private Integer tutorId;
private String name;
private String email;
private Address address;
private List<Course> courses;
// setters & getters
}
CourseBean
public class Course{
private Integer courseId;
private String name;
private String description;
private Date startDate;
private Date endDate;
private Integer tutorId;
//setters & getters
}
使用内嵌结果ResultMap实现一对多
<resultMap type="Course" id="CourseResult">
<id column="course_id" property="courseId" />
<result column="name" property="name" />
<result column="description" property="description" />
<result column="start_date" property="startDate" />
<result column="end_date" property="endDate" />
</resultMap>
<resultMap type="Tutor" id="TutorResult">
<id column="tutor_id" property="tutorId" />
<result column="tutor_name" property="name" />
<result column="email" property="email" />
<collection property="courses" resultMap="CourseResult" />
</resultMap>
<select id="findTutorById" parameterType="int" resultMap="TutorResult">
SELECT T.TUTOR_ID as tutorId , T.tutor_NAME AS NAME, EMAIL,
C.COURSE_ID as courseId, C.NAME, DESCRIPTION, START_DATE as
StartDate, END_DATE as endDate
FROM TUTORS T LEFT OUTER JOIN ADDRESSES A ON T.ADDR_ID=A.ADDR_ID
LEFT OUTER JOIN COURSES C ON T.TUTOR_ID=C.TUTOR_ID
WHERE T.TUTOR_ID=#{tutorId}
</select>
使用嵌套Select语句实现一对多映射
<resultMap type="Course" id="CourseResult">
<id column="course_id" property="courseId" />
<result column="name" property="name" />
<result column="description" property="description" />
<result column="start_date" property="startDate" />
<result column="end_date" property="endDate" />
</resultMap>
<resultMap type="Tutor" id="TutorResult">
<id column="tutor_id" property="tutorId" />
<result column="tutor_name" property="name" />
<result column="email" property="email" />
<association property="address" resultMap="AddressResult" />
<collection property="courses" column="tutor_id" select="findCoursesByTutor" />
</resultMap>
<select id="findTutorById" parameterType="int" resultMap="TutorResult">
SELECT T.TUTOR_ID tutorId, T.TUTOR_NAME AS NAME, EMAIL
FROM TUTORS T WHERE T.TUTOR_ID=#{tutorId}
</select>
<select id="findCoursesByTutor" parameterType="int"
resultMap="CourseResult">
SELECT * FROM COURSES WHERE TUTOR_ID=#{tutorId}
</select>
注:嵌套 Select 语句查询会导致 N+1 选择问题。首先,主查询将会执行(1 次),对于主
查询返回的每一行,另外一个查询将会被执行(主查询 N 行,则此查询 N 次)。对于
大型数据库而言,这会导致很差的性能问题。
最后
以上就是魔幻小鸽子为你收集整理的mybatis的sql映射文件映射器配置文件mapper映射器接口映射语句结果集映射ResultMaps一对一映射一对多映射的全部内容,希望文章能够帮你解决mybatis的sql映射文件映射器配置文件mapper映射器接口映射语句结果集映射ResultMaps一对一映射一对多映射所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复