<resultMap id="empAndDeptResultMap" type="Emp"> <id column="emp_id" property="empId"></id> <result column="emp_name" property="empName"></result> <result column="age" property="age"></result> <result column="gender" property="gender"></result> <result column="dept_id" property="dept.deptId"></result> <result column="dept_name" property="dept.deptName"></result> </resultMap>中为什么Emp类中没有无参构造MyBatis却能正确创建Emp对象
时间: 2023-10-09 13:07:40 浏览: 103
在MyBatis中,如果一个类中没有显式定义无参构造函数,Java会自动提供一个无参构造函数。当MyBatis创建Emp对象时,它会首先调用Emp的无参构造函数来创建一个对象,然后通过调用setter方法来设置对象的属性。因此,尽管Emp类中没有显式定义无参构造函数,MyBatis仍然可以正确创建Emp对象。
但是,如果Emp类中定义了有参构造函数,而没有显式定义无参构造函数,那么在创建Emp对象时就会出现问题。因为MyBatis无法通过调用无参构造函数来创建Emp对象,因此会抛出异常。所以,最好为每个类都显式地定义一个无参构造函数,以确保MyBatis能够正确地创建对象。
相关问题
目录 员工管理: 删除员工: Controller层: Service层: Mapper接口: 接受参数的两种方式: 修改员工: 查询回显: Controller层: Service层: Mapper接口: 修改数据: Controller层: Service层: Mapper接口: 程序优化: 员工信息统计: 职位统计开发 Controller层: Service层: Mapper接口: 性别统计: 员工管理: 删除员工: 明确三层架构职责: Controller层: 1.接受参数(ID值) 2.调用Service层 3.响应结果 Service层: 1.调用Mapper接口方法,批量删除员工基本信息 2.调用Mapper接口方法,批量删除员工的工作经历信息 Mapper接口: 执行SQL语句 接受参数的两种方式: 方式一:在Controller方法中通过数组来接收 @DeleteMapping public Result delete(Integer[] ids){ log.info("根据id删除员工:{}",ids); return Result.success(); } 方法二:在Controller方法中通过集合来接收 public Result delete(@RequestParam List<Integer> ids){ log.info("根据id批量删除员工:{}",ids); return Result。success(); } Service层: @Transactional(rollbackFor = {Exception.class}) public void deleteByIds(List<Integer> ids){ //1.根据ID删除员工基本信息 empMapper.deleteByIds(ids); //2.根据ID删除员工的工作经历 empExprMapper.deleteByEmpIds(ids); } Mapper层xml: //根据ID批量删除员工信息 <delete id="deleteByIds"> delete from emp where id in <foreach collection="ids" item="id" separator="," open="(" close=")"> #{id} </foreach> </delete> //根据员工ID批量删除员工工作经历信息 <delete id="deleteByEmpIds"> delete from emp_expr where emp_id in <foreach collection="empIds" item="empId" separator="," open="(" close=")" #{empId} </foreach> </delete> 修改员工: 查询回显: 明确三层架构职责: Controller层: 1.接受参数(ID值) 2.调用Service层 3.响应结果 Service层: 1.调用Mapper接口方法,查询员工详细信息 Mapper接口: 执行SQL语句 方法实现: Controller层: //根据ID查询员工信息 @GetMapping("/{id}") public Result getInfo(@PathVariable Integer id){ log.info("根据ID查询员工信息:{}",id); Emp emp = empService.getInfo(id); return Result.success(emp); } Service层: @Override public Emp getInfo(Integer id){ return empMapper.getById(id); } Mapper层: //根据ID查询员工基本信息及员工的工作经历信息 <select id="empResultMap" resultType="包名"> select e.*,ee.id ee_id,ee.emp_id ee_empid,ee.begin ee_end,ee.end ee_end,ee.companyee_company, ee.job ee_job from emp e left join emp_expr ee on e.id = ee.emp_id where e.id = #{id} </select> //定义ResultMap手动封装属性 <resultM
<think>好的,我需要帮助用户理解员工管理系统中删除、修改和查询回显功能的三层架构实现细节。首先,我要回忆一下三层架构通常指的是控制层(Controller)、服务层(Service)和数据访问层(Mapper)。用户提到的删除、修改和查询回显都需要在这三层中实现不同的逻辑。
根据用户提供的引用内容,引用[4]提到了EmpService接口中的方法,包括delete、page、insert、getById和update,这些对应了删除、分页查询、新增、根据ID查询和修改操作。引用[2]中的EmployeeMapper继承了通用Mapper,可能使用了MyBatis的通用方法,比如根据主键查询或更新。引用[3]提到了DTO到实体类的转换在Service层完成,这可能涉及到数据封装和转换。引用[1]和[4]都提到了Controller层处理请求,调用Service层的方法,特别是查询回显通过ID查询员工信息。
接下来,我需要分别梳理每个功能在三层中的具体实现细节:
1. **删除功能**:
- Controller层接收删除请求,可能是一个批量删除,参数是ID列表。需要调用Service层的删除方法。
- Service层处理业务逻辑,比如权限检查或日志记录,然后调用Mapper的删除方法。
- Mapper层使用MyBatis的通用方法或自定义SQL,根据ID删除记录。这里可能需要使用动态SQL处理批量删除。
2. **修改功能**:
- Controller层接收包含更新数据的请求体,将数据传递给Service层。
- Service层可能需要先查询现有数据,合并更改,然后进行更新。这里涉及到DTO到实体类的转换,如引用[3]所述。
- Mapper层使用updateByPrimaryKey方法或其他更新方法,确保数据正确持久化。
3. **查询回显**:
- Controller层处理GET请求,通过路径变量获取员工ID,调用Service层获取员工数据。
- Service层调用Mapper的selectByPrimaryKey方法查询数据库,返回实体对象。
- Mapper层利用通用Mapper的方法,无需编写SQL即可实现按主键查询。
需要确保各层之间的数据传递正确,比如Controller接收的参数是否正确绑定,Service层是否处理了业务逻辑,Mapper层是否正确映射到数据库操作。此外,异常处理也是需要考虑的部分,比如数据库操作失败时的回滚或错误提示。
可能的问题点包括:批量删除时SQL语句的生成是否正确,事务管理是否在Service层启用,DTO和实体类之间的字段是否一致,以及Controller层的路由设计是否符合RESTful规范。需要参考用户提供的代码片段,特别是引用[4]中的EmpService接口和引用[2]中的EmployeeMapper,确认方法命名和参数是否正确。
总结来说,每个功能在三层中的分工明确,Controller处理请求和响应,Service处理业务逻辑,Mapper处理数据持久化。通过结合用户提供的引用内容,可以具体说明各层的代码实现细节,并确保引用正确的代码示例作为支撑。</think>### 员工管理系统三层架构实现细节
#### 1. **删除功能实现**
- **控制层(Controller)**
接收批量删除请求,验证参数合法性,调用服务层方法。
```java
@DeleteMapping("/delete")
public Result delete(@RequestBody List<Integer> ids) {
empService.delete(ids);
return Result.success();
}
```
引用[4]中`EmpService`定义了`void delete(List<Integer> ids)`接口方法。
- **服务层(Service)**
处理业务逻辑(如权限校验、关联数据清理),调用数据访问层批量删除。
```java
@Override
public void delete(List<Integer> ids) {
empMapper.deleteByIds(ids); // 通用Mapper批量删除方法
}
```
- **数据访问层(Mapper)**
使用通用Mapper的`deleteByIds`方法生成`WHERE id IN (...)`语句[^2]。
---
#### 2. **修改功能实现**
- **控制层(Controller)**
接收PUT请求,解析请求体中的员工数据,调用服务层更新。
```java
@PutMapping("/update")
public Result update(@RequestBody EmpDTO empDTO) {
empService.update(empDTO);
return Result.success();
}
```
- **服务层(Service)**
将DTO转换为实体类,补充业务字段(如更新时间),调用Mapper更新。
```java
@Override
public void update(EmpDTO empDTO) {
Emp emp = new Emp();
BeanUtils.copyProperties(empDTO, emp); // DTO转实体
emp.setUpdateTime(LocalDateTime.now());
empMapper.updateByPrimaryKeySelective(emp); // 动态更新非空字段
}
```
引用[3]强调DTO到实体的转换在Service层完成[^3]。
- **数据访问层(Mapper)**
通过`updateByPrimaryKeySelective`方法生成动态SQL,仅更新非空字段。
---
#### 3. **查询回显功能实现**
- **控制层(Controller)**
处理GET请求,通过路径参数获取ID,返回完整员工数据。
```java
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
Emp emp = empService.getById(id);
return Result.success(emp);
}
```
引用[1]指出查询回显需通过ID查询员工信息[^1]。
- **服务层(Service)**
直接调用Mapper查询接口,无额外逻辑。
```java
@Override
public Emp getById(Integer id) {
return empMapper.selectByPrimaryKey(id); // 根据主键查询
}
```
- **数据访问层(Mapper)**
使用通用Mapper的`selectByPrimaryKey`方法,自动映射实体类字段。
---
### 架构关系图
$$
\begin{array}{ccc}
\text{Controller} & \rightarrow & \text{Service} & \rightarrow & \text{Mapper} \\
\small\text{(HTTP请求处理)} & & \small\text{(业务逻辑)} & & \small\text{(SQL操作)}
\end{array}
$$
---
### 常见问题
1. **如何保证删除操作的原子性?**
在Service方法添加`@Transactional`注解,确保批量删除在事务中执行[^4]。
2. **DTO与实体类字段不一致如何处理?**
需在Service层手动映射(如`BeanUtils.copyProperties()`)或使用MapStruct工具[^3]。
3. **通用Mapper如何实现动态SQL?**
通过方法名约定(如`updateByPrimaryKeySelective`)生成基于字段非空判断的SQL。
---
mybatis resultmap 一对多,多对一,多对多
### MyBatis 中 ResultMap 对关系映射的支持
#### 一对多关系映射
在 MyBatis 中,`<collection>` 标签用于处理一对多的关系。通过 `resultMap` 定义映射规则,可以将查询结果集中的一组记录映射成一个集合属性。
```xml
<!-- 子表实体 -->
<resultMap id="orderResultMap" type="Order">
<id property="orderId" column="order_id"/>
<!-- 其他字段映射省略 -->
</resultMap>
<!-- 主表实体 -->
<resultMap id="customerWithOrdersResultMap" type="Customer">
<id property="customerId" column="customer_id"/>
<collection property="orders" ofType="Order"
select="selectOrderByCustomerId"
column="{customerId=customer_id}">
<!-- 使用子表的 resultMap 进行映射 -->
<resultMap ref-id="orderResultMap"/>
</collection>
</resultMap>
```
上述代码展示了如何利用 `<collection>` 来表示客户与订单之间的一对多联系[^1]。
#### 多对一关系映射
对于多对一的情况,则采用 `<association>` 标签实现父级对象实例化:
```xml
<!-- 父表实体 -->
<resultMap id="departmentResultMap" type="Department">
<id property="deptId" column="dept_id"/>
<!-- 更多字段... -->
</resultMap>
<!-- 子表实体 -->
<resultMap id="employeeResultMap" type="Employee">
<id property="empId" column="emp_id"/>
<association property="department" javaType="Department"
select="getDeptById"
column="dept_id">
<resultMap ref-id="departmentResultMap"/>
</association>
</resultMap>
```
这里说明了员工属于某个部门这一典型的多对一场景下的配置方式[^2]。
#### 多对多关系映射
针对多对多的情形,通常借助中间表作为桥梁连接两个独立的对象模型;此时既可以用到前面提到过的两种标签组合起来表达间接关联:
```xml
<!-- 左侧实体 -->
<resultMap id="authorResultMap" type="Author">
<id property="authId" column="auth_id"/>
<!-- ... -->
</resultMap>
<!-- 右侧实体 -->
<resultMap id="bookResultMap" type="Book">
<id property="bookId" column="book_id"/>
<!-- ... -->
</resultMap>
<!-- 联合体 (假设存在 author_book 表)-->
<resultMap id="authorBooksResultMap" type="Author">
<id property="authId" column="auth_id"/>
<collection property="books" ofType="Book"
select="findBooksByAuthId"
column="auth_id">
<resultMap ref-id="bookResultMap"/>
</collection>
</resultMap>
```
这段 XML 片段解释了一个作者可能撰写过多本书籍的同时每本书也可能由多位作家共同创作这样一个双向 N:N 映射的例子[^3]。
阅读全文
相关推荐






