1. 单元测试

在单元测试中,每个测试方法都需要执行相同的前置代码和后置代码,则可以自定义2个方法,分别在这2个方法中执行前置代码和后置代码,并为这2个方法添加@Before@After注解,然后,在每个测试方法中,就不必再编写这些代码,最终,在执行测试方法之前,会自动调用添加了@Before注解的方法,在执行测试方法之后,会自动调用添加了@After注解的方法:

private AbstractApplicationContext ac;
private UserMapper userMapper; @Before
public void doBefore() {
// 加载Spring配置文件,获取Spring容器
ac = new ClassPathXmlApplicationContext(
"spring.xml"); // 从Spring容器中获取对象
// bean-id与接口名一致,首字母为小写
userMapper
= ac.getBean("userMapper", UserMapper.class);
} @After
public void doAfter() {
// 释放资源
ac.close();
} @Test
public void deleteUserById() {
// 测试功能
Integer id = 3;
Integer rows = userMapper.deleteUserById(id);
System.out.println("rows=" + rows);
}

2. 在MyBatis中查询数据

使用MyBatis执行查询操作时,抽象方法的设计中,返回值应该根据查询需求来决定,例如查询用户列表时,可以使用List<User>作为返回值类型,查询某个用户时,可以使用User作为返回值类型,查询的是计数等操作时,可以使用Integer作为返回值类型。

其实,无论执行什么样的查询,MyBatis的查询结果都是List集合,只不过,如果抽象方法声明的不是集合,而是具体的某个类型,例如User时,MyBatis会尝试从集合中获取第1个元素作为返回值!

查询是可能失败,即没有匹配的数据,在这种情况下,如果返回值是List集合,则返回的是空集合(集合对象是存在的,但是集合中没有任何元素),如果返回值是某个类型,则返回null。

在配置的XML映射中,每个查询对应的都是<select>节点,该节点必须配置resultTyperesultMap属性,用于表示查询结果的类型(即使返回值类型是Integer也必须配置)!

如果返回结果是User对象,则resultType的值是User类的全名,如果返回结果是List,其resultType也是User类的全名,而不是List的全名!

关于resultMap后续再介绍。

目标:查询所有用户的数据

在接口中添加抽象方法:

List<User> findAll();

配置以上方法的映射:

<select id="findAll"
resultType="cn.tedu.mybatis.entity.User">
SELECT
id, username, password, age, phone, email
FROM t_user
</select>

目标:查询指定id的用户的数据

在接口中添加抽象方法:

User findUserById(Integer id);

配置以上方法的映射:

<select id="findUserById"
resultType="cn.tedu.mybatis.entity.User">
SELECT
id, username, password, age, phone, email
FROM t_user
WHERE id=#{id}
</select>

练习:根据用户名查询用户数据。

目标:获取当前用户表中用户的数量

在接口中添加抽象方法:

Integer getCount();

配置以上方法的映射:

<select id="getCount"
resultType="java.lang.Integer">
SELECT COUNT(id) FROM t_user
</select>

2. 涉及多参数的数据访问操作

在许多操作中,也许1个参数并不能满足需求,可能需要2个或更多个参数,例如修改某个用户的密码,设计的抽象方法可能是:

Integer changePassword(Integer id, String password);

然后,配置的映射应该是:

<update id="changePassword">
UPDATE t_user
SET password=#{password}
WHERE id=#{id}
</update>

在MyBatis中,其实只支持1个参数,并且,Java源文件编译为class字节码文件后,也会丢失参数名称,所以,需要为每一个参数添加@Param注解:

Integer changePassword(
@Param("id") Integer arg0,
@Param("password") String arg1);

则MyBatis会把这些参数全部封装在一个Map中,注解中的名称就是每个参数的Key,后续,在配置映射时,在#{}中填入的也就是注解的名称,即各参数在Map中的Key:

在设计MyBatis中的抽象方法时,如果参数超过1个,则每个参数之前都必须添加@Param注解,在映射的SQL语句中,#{}中填入也是注解中使用的名称!

3. 插入数据时获取数据自增长的id

在配置映射时,为<insert>节点添加2个属性:useGeneratedKeys="true"表示需要获取自动生成的键,通常就是数据表中的主键字段,即id字段,然后配置keyProperty="id",表示获取到的键的值(即自增长的id值)将要封装到哪个属性中(即实体类中的属性名):

经过以上配置后,当成功插入数据时,就会获取到该数据的自增长的id值,并且,会将值封装到参数对象中,即:调用Integer insert(User user)方法时,假设使用user1作为调用时的参数,当方法执行结果后,参数user1中就已经包含了id值!

@Test
public void insert() {
// 测试功能
User user = new User();
user.setUsername("java");
user.setPassword("1234"); System.out.println("执行前:" + user);
Integer rows = userMapper.insert(user);
System.out.println("rows=" + rows);
System.out.println("执行后:" + user);
}

执行结果例如:

4. 关联表查询操作

问题描述

存在班级学生数据,要求显示某个班级信息时,同时显示出该班级的所有学生。

准备工作

创建班级(1)表:

CREATE TABLE t_class (
id INT AUTO_INCREMENT,
name VARCHAR(20),
PRIMARY KEY(id)
) DEFAULT CHARSET=UTF8;

创建学生(N)表:

CREATE TABLE t_student (
id INT AUTO_INCREMENT,
name VARCHAR(20),
class_id INT,
PRIMARY KEY(id)
) DEFAULT CHARSET=UTF8;

当数据表之间存在1对多关系时,在“多”的表中需要存储“1”的表的唯一标识,即存储“1”的表的id。

为了保证后续的数据查询,还应该添加一部分的测试数据:

INSERT INTO t_class (name) VALUES
("JSD1806"), ("JSD1807"), ("JSD1808"); INSERT INTO t_student (name, class_id) VALUES
("Jack", 1), ("Rose", 1),
("LiLei", 2), ("HanMM", 2),
("Lucy", 3), ("LiLi", 3),
("Bob", 1), ("LiMing", 1),
("Kitty", 2), ("Tom", 1);

基于以上数据表,如果要获取班级信息的同时,还获取该班级的所有学生的列表,则执行的SQL查询应该是:

SELECT
c.id AS class_id,
c.name AS class_name,
s.id AS student_id,
s.name AS student_name
FROM t_class AS c
INNER JOIN t_student AS s
ON c.id=s.class_id
WHERE c.name="JSD1806";

基于每张数据表都应该有1个与之对应的实体类的原则,则在项目中应该有:

public class Clazz {
private Integer id;
private String name;
} public class Student {
private Integer id;
private String name;
private Integer classId;
}

即使有了以上2个类,却都无法满足查询结果的需求,即尝试在接口中声明抽象方法时:

??? getClassInfo(String className);

无法确定返回值类型!

针对这种情况,通常会在项目中创建VO类,即Value Object类!例如:

public class ClazzVO {
private Integer classId;
private Integer className;
private List<Student> students;
}

通常,实体类与数据表是对应的,而VO类是与实际使用需求对应的!

当设计好了VO类,则查询的抽象方法可以是:

ClazzVO getClassInfo(String className);

可以发现,即使使用了VO类,查询的字段与ClazzVO类中的属性名称等都无法直接对应,则,在映射文件中,需要使用到<resultMap>

最后的执行结果为:

ClazzVO [
classId=1,
className=JSD1806,
students=[
Student [id=1, name=Jack, classId=null],
Student [id=2, name=Rose, classId=null],
Student [id=7, name=LiMing, classId=null],
Student [id=8, name=Bob, classId=null],
Student [id=10, name=Tom, classId=null]
]
]

小结

如果某次查询涉及多张表,存在关联查询,通常是没有匹配的实体类可以直接使用的,在这种情况下,就需要自定义VO类。

VO类与实体类的代码表现基本相似,只是定位不同,实体类是与数据表对应的,而VO类是为了满足编码需求,更方便的获取查询结果而存在的!

VO类的属性的设计原则完全取决于所需要执行的查询的结果。

产生了关联查询后,可以直接用VO类作为resultType,但是,如果查询结果中存在数据之间的1对多等关系,则需要配置<resultMap>

5. 动态SQL

在MyBatis中配置映射时,允许使用例如<if>此类的标签,使得每次执行的SQL语句可以产生动态调整,则称之为动态SQL。

目标:实现根据id修改用户信息,可修改的字段有:密码、年龄、手机号码、电子邮件,如果执行的参数中,某项数据为null,则不修改原有值,例如修改时,参数中没有年龄值,则不修改原有的年龄,其它字段也是相同的处理方式。

首先,在接口中声明抽象方法:

Integer changeInfo(
@Param("id") Integer id,
@Param("password") String password,
@Param("age") Integer age,
@Param("phone") String phone,
@Param("email") String email);

然后,配置以上方法的映射:

UPDATE t_user
SET
password=#{password},
age=#{age},
phone=#{phone},
email=#{email}
WHERE id=#{id}

以上配置的执行效果会是:如果没有提供某个值,将会把对应的字段的值设置为null,而并非不修改原有值。

此类问题可以通过动态SQL的<if>标签来解决:

UPDATE t_user
SET
password=#{password}, <if test="age != null">
age=#{age},
</if> phone=#{phone}, <if test="email != null">
email=#{email}
</if>
WHERE id=#{id}

执行以上代码时,如果提供了有效的age值(非null),则SQL语句为:

UPDATE t_user SET password=?, age=?, phone=?, email=? WHERE id=?

但是,如果没有提供age值,则SQL语句为:

UPDATE t_user SET password=?, phone=?, email=? WHERE id=?

注意:在编写动态SQL时,参数直接写名字即可,例如test="age != null"中的age就是参数的名称,不需要使用#{}这类的语法!

目标:一次删除多条数据,这些数据的id是作为参数体现的,但是,是没有规律的。

在接口中声明抽象方法:

Integer deleteUserByIds(List<Integer> ids);

以上方法的设计,参数可以是List<Integer>,也可以是Integer[]

然后,配置映射:

<!-- collection:使用哪个集合,取值使用list或array -->
<!-- item:每次遍历到的元素的名称 -->
<!-- separator:IN内部的各个值之间使用的分隔符 -->
<!-- open:遍历后的结果的起始字符 -->
<!-- close:遍历后的结果的结束字符 -->
<delete id="deleteUserByIds">
DELETE FROM t_user
WHERE id IN
<foreach collection="list"
item="id" separator=","
open="(" close=")">
#{id}
</foreach>
</delete>

注意:在中的collection属性,当抽象方法只有1个参数时,取值为list或array,根据参数类型决定,当抽象方法的参数超过1个时,该属性的值为参数的名称(参数的注解中使用的名称)!

关于动态SQL,主要掌握<if><foreach>的使用!

【附】关于配置MyBatis映射没有代码提示的解决方案**

先连接达内公司内网,下载:http://schema.tedu.cn/proxy/dtd/ibatis-3-mapper.dtd

下载的文件存储到任意位置均可。

在Eclipse中打开设置,左侧选择XML > XML Catelog,并在右侧点击Add按钮:

然后,在左侧选择第1项,右侧选择到刚才下载的文件,然后在Key这一栏输入-//ibatis.apache.org//DTD Mapper 3.0//EN(在映射文件顶部Public字样右侧的字符串):

												

在MyBatis中查询数据、涉及多参数的数据访问操作、插入数据时获取数据自增长的id、关联表查询操作、动态SQL、关于配置MyBatis映射没有代码提示的解决方案的更多相关文章

  1. mybatis一对一关联表查询

    先创建一个表 CREATE TABLE teacher( t_id INT PRIMARY KEY AUTO_INCREMENT, t_name ) ); CREATE TABLE class( c_ ...

  2. Mybatis源码分析--关联表查询及延迟加载原理(二)

    在上一篇博客Mybatis源码分析--关联表查询及延迟加载(一)中我们简单介绍了Mybatis的延迟加载的编程,接下来我们通过分析源码来分析一下Mybatis延迟加载的实现原理. 其实简单来说Myba ...

  3. .NetCore中EFCore的使用整理(二)-关联表查询

    EF常用处理关联加载的方式有3中:延迟加载(Lazy Loading).贪婪加载 (Eager Loading)以及显示加载. 一.EF Core  1.1 1.当前的版本,还不支持延迟加载(Lazy ...

  4. Mybatis动态SQL简单了解 Mybatis简介(四)

    动态SQL概况 MyBatis 的强大特性之一便是它的动态 SQL 在Java开发中经常遇到条件判断,比如: if(x>0){ //执行一些逻辑........ }   Mybatis应用中,S ...

  5. SpringBoot Data JPA 关联表查询的方法

    SpringBoot Data JPA实现 一对多.多对一关联表查询 开发环境 IDEA 2017.1 Java1.8 SpringBoot 2.0 MySQL 5.X 功能需求 通过关联关系查询商店 ...

  6. 【Eclipse】 Alt+/ 代码提示问题解决方案

    一般情况下alt+/有代码提示作用,还有代码提示的快捷代码也不是alt+/,因此要恢复代码提示用alt+/.需要做两件事. 在 Window - Preferences - General - Key ...

  7. MyBatis实现关联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

  8. MyBatis学习总结(五)——实现关联表查询(转载)

    本文转载自:http://www.cnblogs.com/jpf-java/p/6013516.html 一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数 ...

  9. MyBatis入门学习教程-实现关联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

随机推荐

  1. 智能卡操作系统COS概述

    随着IC卡从简单的同步卡发展到异步卡,从简单的EPROM卡发展到内带微处理器的智能卡(又称CPU卡),对IC卡的各种要求越来越高.而卡本身所需要的各种管理工作也越来越复杂,因此就迫切地需要有一种工具来 ...

  2. day 70 crm(7):stark组件调用,以及权限分配

    前情提要: 复习:  1: orm !!!!! 2: session 3: django 4:  前端在复习 5:  复习中间件 学习的stark 的组件调用,以及权限的应用 一:权限的概念,  1: ...

  3. vertical-tical

    通常我们需要垂直对齐并排的元素. CSS提供了一些可实现的方法:有时我用浮动float来解决,有时用position: absolute来解决,有时甚至是“肮脏”地手动添加的margin或paddin ...

  4. Oracle 常见字符操作

    一.拼接 1.使用 || 来实现 SELECT '你'||'好!' title FROM dual; 2.使用concat (不支持多个字符串的拼接,但是可以嵌套调用) SELECT concat(' ...

  5. LeetCode题解-23 合并K个排序链表 Hard

    合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ 1->4->5, 1->3->4, 2->6 ] 输出: 1->1-&g ...

  6. Linux驱动:LCD驱动测试

    (1) 进入内核源码目录中,make menuconfig -> Device Drivers -> Graphics support -> [M]Support for frame ...

  7. Android 开发工具类 14_ JsonTools

    天气 JSON 数据解析 package com.example.weather_json.tools; import java.util.ArrayList; import java.util.Li ...

  8. VMware里Ubuntukylin-14.04-desktop的VMware Tools安装图文详解

    不多说,直接上干货! 总的来说,根据分为三个步骤. 步骤一: 点击 :虚拟机—–>安装VM tools 然后发现桌面会跳出如下问题: 客户机操作系统已将 CD-ROM 门锁定,并且可能正在使用 ...

  9. Oracle中的层次查询详解

    1 语法格式 select [level], column, expr... from table [where condition] start with condition connect by ...

  10. Mac在终端用命令装载dmg文件

    今天碰到个问题,下载了一个dmg文件,然后双击/右键安装,一点反应都没有.一开始以为是电脑的缘故,重启,依旧没有反应,然后想到用终端装载试试. 打开终端,输入命令: hdiutil attach we ...