前言:
前面我们学习了对mybatis的环境配置以及一些涉及到的知识点和操作;现在我们将用mybatis配合JDBC来完成简单的人事管理系统hrms(hr)。
搭建前的相关知识:
一、映射与参数
我们在充分了解了CRUD,即增删改查的操作后,需要进一步将其落实到我们的.xml文件当中。所以我们必须在xml文件工作之前,理解所写的每一个sql语句应该在执行前后做一个什么样的事情。
<select id="getEmployeeById" resultType="com.hr.entity.Employee">
SELECT *
FROM employee
WHERE emp_id = #{empId}
</select>
这说明了一个非常简单的命名参数映射,参数类型(parameterType)会被自动设置为int
,这个参数可以随意命名。原始类型或简单数据类型(比如Integer
和 String
)因为没有其它属性,会用它们的值来作为参数。
※在参数方面:
如果参数只有一个且没有注解的情况下,可以随意命名。
对象参数:需要与实体类属性名一致。
多个参数:可以使用#{arg0}、#{arg1}或者#{param1}、#{param2}
注意:可以通过@Param
注解指定多个参数名称,此时只能param作为参数传递。
HashMap:我们知道hashmap是键值对——key and value。
如果在查询时有多个条件,那么我们可以把多个条件放在一个map中来作为参数传递进来。
<select id="queryByMap" resultType="employee">
select emp_name, phone, address, salary from employee where emp_name = #{empName} or phone= #{phone}
</select>
#{}中的内容是测试时传进来的map的key值 。
※结果映射:
resultType和resultMap的区别
对象不同与描述不同:
resultType:直接表示SQL查询返回结果的Java类型,MyBatis会自动将查询结果集中的列名与Java对象的属性名进行匹配(默认情况下,列名到属性名的映射是大小写不敏感的,并且会考虑驼峰命名法)。只有当列名和属性名完全一致(或通过别名匹配)时,映射才能成功。
resultMap:提供了更复杂的映射关系定义,当查询结果的列名和Java对象的属性名不一致时,可以通过resultMap来建立它们之间的映射关系。此外,resultMap还支持更高级的映射功能,如一对一、一对多等复杂关系的映射。
类型适用不同:
resultType:适用于简单的单表查询,且查询结果的列名和Java对象的属性名能够直接匹配的情况。
resultMap:适用于复杂的查询场景,包括列名和属性名不一致、需要进行一对一或一对多映射的关联查询等。
存在方式:
在MyBatis的mapper文件中,可以使用resultType或resultMap来指定查询的返回类型。但二者不能同时存在,必须选择一个使用。
二、Service层
DAO层:负责访问数据库进行数据的操作,取得结果集之后将结果集中的数据取出封装后返回给service层。
DAO只完成基本的增删改查,虽然可以1-n,n-n,1-1关联,模糊、动态、子查询都可以。但是无论多么复杂的查询,dao只是封装增删改查。
service层:主要负责一些业务处理,比如多个操作需要放在一个事务中进行管理,事务回滚,一些复杂的逻辑业务处理就放到service层。
Service层的业务实现,具体要调用到已定义的DAO层的接口。封装Service层的业务逻辑有利于通用的业务逻辑的独立性和重复利用性。
理清了Dao层和Mapper层的逻辑后(二者在一定程度上是等价的),我们开始搭建服务层及其实现类。
以增添功能为例:
mapper层实现类:
@Override
public int add(SqlSession session,Employee employee) {
EmployeeMapper mapper = session.getMapper(EmployeeMapper.class);
int add=mapper.add(session,employee);
//session.commit();
return add;
}
service层实现类:
@Override
public int add() {
try (SqlSession session = MybatisUtils.getSession()){
System.out.println("请输入编号");
int id = sc.nextInt();
System.out.println("请输入员工姓名");
String name = sc.next();
System.out.println("请输入性别");
String sex = sc.next();
System.out.println("请输入年龄");
int age = sc.nextInt();
System.out.println("请输入生日");
String birthday = sc.next();
System.out.println("请输入邮箱");
String email = sc.next();
System.out.println("请输入地址");
String address = sc.next();
System.out.println("请输入电话");
String phone = sc.next();
Employee employee = new Employee(id, name, sex, age, birthday, email, address, phone);
int i=employeeMapper.add(session,employee);
session.commit();
return i;
}
}
我们将事务的判别交给服务层,一般推荐这么做。同时上述代码完成了封装,这样可以大量简化App主函数体里的代码量;提高代码的可读性和可维护性。当然,也可以写在主函数体里,如果这么做需要在该方法中加入参数。
请注意,底层的mapper接口需要用注解的方式传递给xml文件:
public interface EmployeeMapper {
int add(SqlSession session,@Param("employee") Employee employee);
}
整体完成对应的增删改查功能后就可以开始写业务了,同样的,写在对应的服务层:
@Override
public boolean register(String username, String password) {
try (SqlSession session = MybatisUtils.getSession()) {
HrMapper mapper = session.getMapper(HrMapper.class);
// 假设 queryByUsername 返回一个布尔值,表示用户名是否存在
boolean userExists = mapper.queryByUsername(username);
if (!userExists) {
Hr hr = new Hr();
hr.setUsername(username);
hr.setPassword(password);
int result = mapper.add(hr);
if (result > 0) {
session.commit();
System.out.println("注册成功!");
return true; // 返回注册成功
} else {
System.out.println("注册失败,可能是数据库问题!");
return false; // 返回注册失败
}
} else {
System.out.println("用户名已存在!");
return false; // 返回用户名已存在
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("注册过程中发生异常!");
return false; // 返回异常导致的失败
}
}
这样,注册功能就完成了。
三、动态sql
我们回到xml文件中以丰富我们的数据库操作(进阶):
1、if条件判断
if标签的test属性判断成立,就会将标签对之间的sql语句拼接到主sql语句上
2、choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
<!-- select * from employee where status=1-->
<!-- <choose>-->
<!-- <when test="dept_id!=0">-->
<!-- and dept_id=#{deptId}-->
<!-- </when>-->
<!-- <when test="emp_name!=null">-->
<!-- and emp_name=#{empName}-->
<!-- </when>-->
<!-- <otherwise>-->
<!-- and phone='666666'-->
<!-- </otherwise>-->
<!-- </choose>-->
3、where标签
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
# where能自动去掉if里的and
<!--<where>-->
<!-- <if test="dept_id!=0" >-->
<!-- and dept_id=#{deptId}-->
<!-- </if>-->
<!-- <if test="emp_name!=null">-->
<!-- and emp_name=#{empName}-->
<!-- </if> -->
<!--</where>-->
4、set标签
用于动态更新语句的类似解决方案叫做 set。set元素可以用于动态包含需要更新的列,忽略其它不更新的列。
5、trim
给sql语句添加前后缀,将前后关键字去掉,通过trim可以生成where和set的效果
6、foreach
动态 SQL 的另一个常见使用场景是对集合进行遍历
# 批量增加
<!-- insert into dept(dept_id, dept_name, remark) values-->
<!-- <foreach collection="list" item="dept" separator="," >-->
<!-- (#{dept.id},#{dept.deptName},#{dept.remark})-->
<!-- </foreach>-->
# 批量删除
<!-- delete from dept where dept_id in -->
<!-- <foreach collection="list" item="id" separator="," open="(" close=")"-->
<!-- #{id}-->
<!-- </foreach>-->
7、SQL标签-提取重用的SQL代码片段
这个元素可以用来定义可重用的 SQL 代码片段,以便在其它语句中使用。参数可以静态地(在加载的时候)确定下来,并且可以在不同的 include 元素中定义不同的参数值。
<sql id="BASE_COLUMN_LIST">
# 一般第一个会报错,无视即可
emp_id,emp_name, sex, age, birthday, email, address, hr_phone
</sql>
8、bind标签
拼接sql内容
四、实现与测试
测试正确运行。