赵走x博客
网站访问量:151441
首页
书籍
软件
工具
古诗词
搜索
登录
32、使用MyBatis注解实现数据库操作
31、MyBaties使用XML配置文件实现数据库操作
30、Spring Boot构建MyBatis应用程序
29、MyBatis简介
28、实战:实现JdbcTemplate多数据源
27、使用JdbcTemplate操作数据库
26、JdbcTemplate入门
25、实战:实现Web API版本控制
24、使用Swagger生成Web API文档
23、Thymeleaf页面布局
22、Thymeleaf内置对象、内嵌变量
21、Thymeleaf内联
20、Thymeleaf语法
19、Thymeleaf表达式
18、Thymeleaf入门
17、全局异常处理
16、实战:实现优雅的数据返回
15、跳转指定页面
14、Spring Boot静态资源
13、Spring Boot数据转换配置
12、跨域访问
11、Web配置
10、过滤器
9、拦截器
8、数据验证
7、参数传递
6、URL映射
5、@ResponseBody
4、@RequestMapping
3、@Controller和@RestController
2、Web项目结构
1、spring-boot-starter-web介绍
31、MyBaties使用XML配置文件实现数据库操作
资源编号:552024
热度:140
31、MyBaties使用XML配置文件实现数据库操作
MyBatis真正强大的地方在于它的SQL映射,这是它的魔力所在。 对于任何MyBatis的使用者来说,其SQL映射文件是必须要掌握的。 本节开始介绍MyBatis的SQL映射文件的语法和使用方法。 # 一、SQL映射文件 SQL映射文件就是我们通常说的mapper.xml配置文件,主要实现SQL语句的配置和映射,同时实现Java的POJO对象与数据库中的表和字段进行映射关联的功能。 ### 1. mapper.xml的结构 前面我们创建的StudentMapper.xml中定义了mapper接口对应的SQL和返回类型。下面就来详细介绍mapper.xml文件的结构。首先看一个完整的mapper.xml示例: ``` <
SELECT * FROM student
> ``` 如上述示例所示,一般mapper.xml主要分为4部分: - 1)mapper.xml的语法声明,声明MyBatis语法。 - 2)通过namespace指明mapper.xml文件对应的Mapper接口。 - 3)通过XML标签定义接口方法对应的SQL语句,id属性对应Mapper接口中的方法,resultMap属性为返回值类型。 - 4)
标签定义返回的结果类型与数据库表结构的对应关系,上面映射的是Student实体类对象。 ### 2. mapper.xml的标签 mapper.xml映射文件提供了一些非常实用的标签,其中比较常用的有resultMap、sql、insert、update、delete、select等标签。熟练掌握标签的使用,这样使用MyBatis才能如鱼得水。MyBatis标签和功能说明如表8-2所示。表8-2 MyBatis标签和功能说明  # 二、定义SQL语句 MyBatis提供了insert、update、delete和delete四个标签来定义SQL语句。接下来就从SQL语句开始介绍每个标签的用法。 ### 1. select select是MyBatis常用的元素之一,MyBatis在查询和结果映射中做了相当多的改进。 一个简单查询的select元素是非常简单的,比如: ```
SELECT name,age FROM student WHERE id = #{id}
``` 在上面的示例中,通过id查询学生的姓名和年龄。 定义方法名为selectOne,接收一个Long类型的参数,并返回一个HashMap类型的对象。 HashMap的键是列名,值是结果集中的对应值。#{id}为传入的参数符号。 select标签允许配置很多属性来配置每条语句的行为细节,比如参数类型、返回值类型等,包含的属性如表8-3所示。  select标签虽然有很多属性,但是常用的是id、parameterType、resultType、resultMap这4个属性。 需要注意的是,resultMap是MyBatis的强大特性之一,如果对其理解透彻,许多复杂的映射问题都能迎刃而解。 ### 2. insert insert标签主要用于定义插入数据的SQL语句,例如: ```
INSERT INTO student (id,name,sex,age) VALUES (#{id},#{name}, #{sex}, #{age})
``` 在上面的示例中,插入语句的配置规则更加复杂,同时提供了额外的属性和子元素用来处理主键的生成方式。 如果数据库包含自动生成主键的字段,那么可以设置useGeneratedKeys="true",然后把keyProperty设置为目标属性。比如,上面的Student表已经在id列上使用了自动生成主键,那么语句可以修改为: ```
INSERT INTO student (name,sex,age) VALUES (#{name}, #{sex}, #{age})
``` 在上面的示例中,设置useGeneratedKeys="true",然后设置keyProperty="id"对应的主键字段。insert标签包含的属性如表8-4所示。  常用的属性有id、parameterType、useGeneratedKeys、keyProperty等,部分属性和select标签是一致的。 ### 3. update update标签和insert标签类似,主要用来映射更新语句,示例代码如下: ```
UPDATE student SET name = #{name}, sex = #{sex}, age = #{age} WHERE id = #{id}
``` 如果需要根据传入的参数来动态判断是否进行修改,可以使用if标签动态生成SQL语句,示例代码如下: ```
UPDATE student SET
name = #{name},
sex = #{sex},
age = #{age} WHERE id = #{id}
``` 在上面的示例中,通过if标签判断传入的name参数是否为空,实现根据参数动态生成SQL语句。update标签包含的属性和insert标签基本一致,这里不再重复解释。 ### 4. delete delete标签用来映射删除语句。 ```
DELETE FROM student WHERE id =#{id}
``` delete标签包含的属性如表8-5所示。 表8-5 delete标签的属性说明  delete标签除了少了useGeneratedKeys、keyProperty和keyColumn三个属性之外,其余的和insert、update标签一样。 # 三、结果映射 结果映射是MyBatis重要的功能之一。 对于简单的SQL查询,使用resultType属性自动将结果转换成Java数据类型。 不过,如果是复杂的语句,则使用resultMap映射将查询结果转换为数据实体关系。 ### 1. resultType 前面介绍select标签的时候提到,select标签的返回结果可以使用resultMap和resultType两个属性指定映射结构。下面就来演示resultType的用法。 ```
select * from student where id = #{id}
``` 通过设置resultType属性,MyBatis会自动把查询结果集转换为Student实体对象。当然,如果只查询部分字段,则可以返回HashMap,比如: ```
select name,age from student where id = #{id}
``` 上述语句,Mybatis会自动将所有的列映射成HashMap对象。 ### 2. resultMap 在日常开发过程中,在大部分情况下resultType就能满足。但是使用resultType需要数据库字段和属性字段名称一致,否则就得使用别名,这样就使得SQL语句变得复杂。 所以MyBatis提供了resultMap标签定义SQL查询结果字段与实体属性的映射关系。 下面演示resultMap的使用。首先,定义resultMap: ```
``` 在上面的示例中,我们使用resultMap标签定义了BaseResultMap映射关系,将数据库中的字段映射为Student实体对象。 然后,在SQL语句中使用自定义的BaseResultMap映射关系,设置select标签的resultMap="BaseResultMap",示例代码如下: ```
SELECT * FROM student WHERE id = #{id}
``` 在上面的示例中,将之前的resultType改为resultMap="BaseResultMap"。 #### 3. resultMap的结构 resultMap标签的结构比较复杂,包含很多子属性和子标签。 resultMap标签包含id和type属性: - id定义该resultMap的唯一标识。 - type为返回值的类名。 同样,resultMap还可以包含多个子标签,包括: - 1)id标签用于设置主键字段与领域模型属性的映射关系,此处主键为id,对应数据库字段中的主键ID。 - 2)result标签用于设置普通字段与领域模型的属性映射关系。 - 3)association标签用于配置一对一结果映射,可以关联resultMap中的定义,或者对其他结果映射的引用。 - 4)collection标签用于配置一对多结果映射,可以关联resultMap中的定义,或者对其他结果映射的引用。 下面是完整的resultMap元素的结构: ```
``` # 四、关联关系 前面介绍了resultMap结果映射,MyBatis通过resultMap标签自动将查询结果集转换成数据实体类。 但是多表关联出来的复杂结果该怎么映射呢? 这就需要通过collection标签和association标签配置关联关系。 ### 1. association(一对一) association通常用来映射一对一的关系,比如一个学生(Student)对应一个班级(Classes),一个学生只能属于一个班级。 下面以学生和班级为例来演示association标签配置一对一关联关系。 步骤01 在数据库中创建班级表Classes,代码如下: ``` CREATE TABLE 'Classes' ( 'id' bigint(20) NOT NULL AUTO_INCREMENT, 'name' varchar(255) DEFAULT NULL, 'createtime' date DEFAULT NULL, 'memo' varchar(255) DEFAULT NULL, PRIMARY KEY ('id') ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; ``` 步骤02 使用MyBatis Generator插件自动生成Mapper接口、POJO实体类和Mapper映射文件,如图8-6所示。  图8-6 MyBatis Generate生成Classes表的Mapper接口、实体类和映射文件 生成成功之后,修改之前的Student类,增加学生对应的课程关系字段,示例代码如下: ``` public class Student { private Long id; private String name; private int sex; private int age; private Classes classes; //省略get、set方法 } ``` 在上面的示例中,在Student实体类中增加classes属性。 步骤03 修改StudentMapper接口,增加查询学生班级信息的方法,示例代码如下: ``` public interface StudentMapper { List
selectAll(); Student selectOne(Long id); void insert(Student student); void update(Student student); void delete(Long id); Student selectStudentAndClass(Long id); } ``` 在上面的示例中,在StudentMapper接口中增加了selectStudentAndClass方法,查询学生及课程信息。 步骤04 修改StudentMapper.xml映射文件,配置实体映射关系,示例代码如下: ```
``` 在上面的示例中,通过association标签配置了Classes的映射关系。在association标签中的property属性的作用是将结果集与Student中的classes字段映射,javaType属性指定映射到表的数据类型(Classes类型)。 步骤05 定义resultMap之后,接下来定义查询语句,示例代码如下: ```
select s.id,s.name,s.sex,s.age,s.class_id,c.name as class_name,c.memo from student s left join classes c on s.class_id=c.id where s.id = #{id}
``` 这个SQL的查询结果集会被自动转换成resultMap中定义的完整的Student对象。 步骤06 增加单元测试方法,验证是否生效,示例代码如下: ``` @Test public void testSelectStudentAndClass() { Student student = studentMapper.selectStudentAndClass(1L); System.out.println("name:"+student.getName()+",age:"+student.getAge()+",class name:"+student.getClasses().getName()+",class memo:"+student.getClasses().getMemo()); } ``` 单击Run Test或在方法上右击,选择Run'testSelectStudentAndClass',查看单元测试结果,结果如图8-7所示。  结果表明单元测试方法运行成功,并输出了相应的查询结果。这说明实现了学生和课程的多表信息关联查询。 ### 2. collection(一对多) collection用来映射一对多的关系,将关联查询信息映射到一个列表集合中。比如,一个班级(Classes)对应多名学生(Student)。 下面就来演示collection标签配置一对多关联关系。 步骤01 修改ClassesMapper接口,查询班级和班级下的所有学生信息,示例代码如下: [插图] 在上面的示例中,在ClassesMapper接口中增加selectClassAndStudent()方法,通过班级id查询班级以及班级下的所有学生信息。 步骤02 定义返回数据resultMap: ```
``` 在上面的示例中,定义了ClassAndStudentMap返回数据映射,通过collection标签配置Classes类中的students属性字段的映射关系。 步骤03 创建SQL语句: ```
select c.id,c.name,c.memo,s.name as student_name,s.age,s.sex from classes c left join student s on s.class_id=c.id where c.id = #{id}
> ``` 在上面的示例中,使用前面定义的ClassAndStudentMap映射结果集返回查询到的数据。 步骤04 增加单元测试方法,验证是否生效,示例代码如下: ``` @Autowired private ClassesMapper classesMapper; @Test public void testSelectClassAndStudent() { Classes classes = classesMapper.selectClassAndStudent(1L); System.out.println("班级信息:name:" + classes.getName() + ",memo:" +classes.getMemo()); System.out.println("学生信息列表,总人数:"+classes.getStudents().size()); for (Student stu : classes.getStudents()){ System.out.println("name:"+stu.getName()+",age:"+stu.getAge()); } } ``` 单击Run Test或在方法上右击,选择Run'testSelectClassAndStudent',查看单元测试结果,结果如图8-8所示。  结果表明单元测试方法运行成功,并输出了相应的查询结果。 这说明实现了班级和班级下的学生列表的多表信息关联查询。 通过上面的示例查询班级信息和该班级下的所有学生信息,使用collection将查询到的学生列表数据映射到列表集合中,这样做的目的也是方便对查询结果集进行遍历查询。 而使用resultType无法将查询结果映射到列表集合中。 # 五、SQL代码片段 当多个SQL语句中存在相同的部分,可以将其定义为公共的SQL代码片段。 MyBatis提供了sql和include标签来定义和引用SQL代码片段。 这样调用方便、SQL整洁。比如: ```
id,name,age,sex
``` 通过sql标签定义可以重新使用的SQL代码片段Base_Column_List,然后在SQL语句中引用Base_Column_List,示例代码如下: ```
SELECT
FROM student
``` 在上面的示例中,使用include标签引用定义的Base_Column_List代码片段。当然,sql标签也支持传入参数。我们对上面的示例进行修改: ```
${alias_s}.id,${alias_s}.name,${alias_s}.age,${alias_s}.sex
``` 在上面的示例中,通过${}定义查询表的别名作为传入参数。当引用此代码片段时,可以传入表的别名,比如: ```
SELECT
, FROM student stu WHERE stu.id=#{id}
``` 在上面的示例中,使用include标签引用定义的SQL代码片段,并且通过property定义传入的参数。 # 六、动态SQL拼接 MyBatis提供了if、foreach、choose等标签动态拼接SQL语句,使用起来特别简单灵活。 下面一一介绍这些标签的使用。 ### 1. if标签 if标签通常用于WHERE语句中,通过判断参数值来决定是否使用某个查询条件,它也经常用于UPDATE语句中,用于判断是否更新某一个字段,还可以在INSERT语句中使用,用来判断是否插入某个字段的值,比如: ```
select * from student
where name like CONCAT(CONCAT('%', #{name}),'%')
``` 在上面的示例中,使用if标签先进行判断,如果传入的参数值为null或等于空字符串,就不进行此条件的判断。 ### 2. foreach标签 foreach标签主要用于构建in条件,它可以在sql标签中对集合进行迭代。通常可以将其用到批量删除、添加等操作中。使用方法如下: ```
delete from student where id in
#{id}
/delete> ``` 在上面的示例中,通过foreach标签将传入的id数组拼接成in(1,2,3),实现批量删除的功能。foreach标签包含如下几个属性: - collection:有3个值,分别是list、array和map,分别对应Java中的类型为:List集合、Array和Map三种数据类型。示例中传的参数为数组,所以值为array。 - item:表示在迭代过程中每一个元素的别名。 - index:表示在迭代过程中每次迭代到的位置(下标)。 - open:前缀。 - close:后缀。 - separator:分隔符,表示迭代时每个元素之间以什么分隔。 ### 3. choose标签 MyBatis提供了choose标签,用于按顺序判断when中的条件是否成立,如果有一个成立,则choose结束。 如果choose中的所有when条件都不满足,则执行otherwise中的SQL语句。 类似于Java中的switch语句,choose为switch,when为case,otherwise为default。 Choose适用于从多个选项中选择一个条件的场景,比如: ```
select * from student
name like CONCAT(CONCAT('%', #{name}),'%')
AND sex = #{sex}
AND age = #{age}
``` 在上面的示例中,把所有可以限制的条件都写上,匹配其中一个符合条件的拼接成where条件。 # 七、格式化输出 MyBatis提供了where、set、trim等标签处理查询条件和update语句,使得在mapper.xml中拼接SQL语句变得非常简单高效,从而避免出错。 ### 1. where标签 MyBatis支持使用where标签动态拼接查询条件,如果where标签判断包含的标签中含有返回值,就在SQL语句中插入一个where。 此外,如果标签返回的内容以AND或OR开头,则会自动去除,这样比我们手动拼接where条件简单许多。示例如下: ```
select * from student
name like CONCAT(CONCAT('%', #{name}),'%')
AND sex= #{sex}
``` 在上面的示例中,如果参数name为null或'',则不会生成这个条件,同时还会自动把后面多余的AND关键字去掉。这样就避免了手动判断的麻烦。 ### 2. set标签 与where标签类似,使用set标签可以为update语句动态配置set关键字,同时自动去除追加到条件末尾的任何逗号。使用方法如下: ``` <
update student
name = #{name},
sex= #{sex},
age = #{age},
class_id = #{classes.class_id}
WHERE id = #{id};
> ``` 在上面的示例中,使用了set和if标签,如果某个传入参数不为null,则生成该字段,无须额外处理末尾的逗号,整个update语句更加清晰简洁。 ### 3. trim标签 trim标签的作用是在包含的内容前加上某些前缀,也可以在其后加上某些后缀,对应的属性是prefix和suffix; 可以把内容首部的某些内容覆盖掉,即忽略,也可以把内容尾部的某些内容覆盖掉,对应的属性是prefixOverrides和suffixOverrides。 trim标签比Java中的trim方法功能还要强大。正因为trim有这样的功能,所以我们可以非常简单地利用trim来代替where元素的功能,比如: ```
select * from student
name like CONCAT(CONCAT('%', #{name}),'%')
AND sex = #{sex}
``` 从上面的示例可以看到,trim标签和where标签的功能类似,会自动去掉多余的AND或OR关键字。 trim标签与where标签或set标签不同的地方是,trim除了支持在首尾去除多余的字符外,还可以追加字符,比如: ```
insert into student
id,
name,
age,
sex,
#{id,jdbcType=INTEGER},
#{name,jdbcType=VARCHAR},
#{age,jdbcType=INTEGER},
#{sex,jdbcType=INTEGER},
``` 在上面的示例中,使用trim标签生成insert语句,通过prefix和suffix属性在首尾加上“(”和“)”,同时通过suffixOverrides属性去掉拼接字段时多余的“,”。这样省去了很多判断,使得insert语句非常简单清晰。