复习:查询的标签select必须设置属性resultType或resultMap,用于设置实体类和数据库表的映射 关系
resultType:自动映射,用于属性名和表中字段名一致的情况 (或设置了下划线映射为驼峰)。
resultMap:自定义映射,用于一对多或多对一或字段名和属性名不一致的情况
若字段名和实体类中的属性名不一致,则可以通过resultMap设置自定义映射。
(补充:当字段名和属性名一样时,字段和属性是一 一对应的,jdbc会通过反射实现这种对应,所以,能查到完整的对象。当不一样时,又没有自己处理,那字段和属性就对应不上,查出来的对象属性全是null)
- <resultMap id="userResultMap" type="User">
- <id property="userId" column="userid">id>
- <result property="userName" column="user_name">result>
- <result property="password" column="password">result>
- <result property="age" column="age">result>
- <result property="sex" column="sex">result>
- resultMap>
- <select id="testMohu" resultMap="userResultMap">
-
- select id,user_name,password,age,sex from t_user where user_name like concat('%',#{mohu},'%')
- select>
若字段名和实体类中的属性名不一致,但是字段名符合数据库的规则,实体类中的属性 名符合Java的规则, 此时也可通过以下3种方式处理字段名和实体类中的属性的映射关系
a>可以通过为字段起别名的方式,保证和实体类中的属性名保持一致
b>可以在MyBatis的核心配置文件中设置一个全局配置信息mapUnderscoreToCamelCase,可 以在查询表中数据时,自动将_类型的字段名转换为驼峰 (推荐)
例如:字段名user_name,设置了mapUnderscoreToCamelCase,此时字段名就会转换为 userName
c> 使用resultMap
场景模拟:
查询员工信息以及员工所对应的【部门信息】
员工表和部门表的关系是多对一
多对一映射:多位员工Emp对应一个部门Dept
- public class Emp {
- private Integer empId;
- private String empName;
- private Integer age;
- private String gender;
- //查询员工对应的部门信息时,必须要在Emp类中写一个Dept属性。且提供 get、set,构造器不用加上dept
- // 表与表有关系,在数据库中,员工表里有部门id字段。
- //表与表之间的关系体现在java中,就是在类中加入对象属性。因为员工和部门是多对一的关系,所以,在员工类中
- // 加一个Dept类型的属性。
- //补充:若是一对多,那要在少的一方加一个集合,比如,在Dept里里加一个List
类型的属性. - ///根据需求判断 只在一方加,还是两方都加。
- private Dept dept;//这就是所谓的 对象属性
-
- public Emp() {
- }
-
- public Emp(Integer empId, String empName, Integer age, String gender) {
- this.empId = empId;
- this.empName = empName;
- this.age = age;
- this.gender = gender;
- }
- 。。。。。。
- //提供所有属性的get、set方法,重写toString
- }
- public class Dept {
- private Integer deptId;
- private String depName;
- public Dept() {
- }
-
- public Dept(Integer deptId, String depName) {
- this.deptId = deptId;
- this.depName = depName;
- }
- 。。。。。。。。。。。。。。。。。。。。。。。
- //提供所有属性的get、set方法,重写toString
- }
Mapper接口:
- public interface EmpMapper {
- /**
- * 查询指定员工的信息以及他所在部门的信息
- * @param empId
- * @return
- */
- Emp getEmpAndDeptByEid(@Param("empId") int empId);
- }
想明白字段该和哪个属性进行映射
因为dept是Emp类里的对象属性,所以,字段dept_name 对应 dept.depName
- <resultMap id="empDeptMap" 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_name" property="dept.depName">result>
- resultMap>
-
- <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
- SELECT t_emp.*, t_dept.dept_name
- FROM t_emp NATURAL JOIN t_dept
- WHERE t_emp.emp_id=#{empId}
- select>
根据自己具体业务需求写SQL语句,有时候可能写成外连接。
同上。需要先在java类Emp中添加一个属性private Dept dept ;并提供get、set方法,构造器不用加上dept。重写toString。
association标签:处理多对一的映射关系(处理实体类类型的属性)。比如Employee类中有一个Department属性
用上这个标签更好理解,阅读也方便。我个人比较喜欢这种方式。
将映射文件写成下面这样:
- <resultMap id="empDeptMap" 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>
-
-
-
- <association property="dept" javaType="Dept">
-
- <id column="dept_id" property="deptId">id>
- <result column="dept_name" property="deptName">result>
-
- association>
- resultMap>
-
-
- <select id="getEmpAndDeptByEid" resultMap="empDeptMap">
- SELECT t_emp.*, t_dept.*
- FROM t_emp NATURAL JOIN t_dept
- WHERE t_emp.emp_id=#{empId}
- select>
- @Test
- public void testEmpDept(){
- SqlSession sqlSession = sqlSessionUtils.getSqlSession();
- EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);
- Emp empAndDeptByEid = mapper.getEmpAndDeptByEid(1);
- System.out.println(empAndDeptByEid);
- //Emp{empId=1, empName='赵四', age=20, gender='男', dept=Dept{deptId=1, depName='a部门'}}
-
- }
文字记录不太清楚
去看尚硅谷杨博超老师的SSM视频。或其他学习资源
多对一反过来就是一对多,一个部门对应多个员工。需要在部门类中加一个List
属性,提供get、set方法,toString。 构造器中不用加List
。 处理一对多的映射关系:
方式一:collection
方式二:分步查询
- public class Dept {
- private Integer deptId;
- private String deptName;
- //一对多,一个部门里有多个员工
- private List
emps; - ..........
- }
需求:根据部门id查询部门以及该部门中所有员工的信息
根据具体业务需要写sql语句,看是否需要使用左外连接或右外连接. 例如下面的左外连接,因为有的人没有部门,但是又想查所有人。
- SELECT *
- FROM t_dept
- LEFT JOIN t_emp ON t_dept.dept_id = t_emp.dept_id
- WHERE t_dept.dept_id=#{deptId}
-
- * 表示查询2表的所有字段
我的例子用的是自然连接:
- SELECT * # 两个表的所有字段
- FROM t_dept
- NATURAL JOIN t_emp WHERE t_dept.dept_id=#{deptId}
- DeptMapper接口里:
- /**
- * 根据部门id查新部门以及该部门中的员工信息
- * @param did
- * @return
- */
- Dept getDeptAndEmpByDeptId(@Param("deptId") int deptId);
- DeptMapper.xml 里:
-
- <resultMap id="deptAndEmpResultMap" type="Dept">
- <id column="dept_id" property="deptId">id>
- <result column="dept_name" property="deptName">result>
-
-
-
- <collection property="emps" ofType="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>
- collection>
- resultMap>
-
- <select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
- SELECT t_dept.*,t_emp.*
- FROM t_dept
- NATURAL JOIN t_emp WHERE t_dept.dept_id=#{deptId}
- select>
- @Test
- public void testGetDeptAndEmpByDeptId(){
- SqlSession sqlSession = sqlSessionUtils.getSqlSession();
- DeptMapper mapper = sqlSession.getMapper(DeptMapper.class);
- Dept deptAndEmpByDeptId = mapper.getDeptAndEmpByDeptId(1);
- System.out.println(deptAndEmpByDeptId);
-
- }
-
- DEBUG 09-16 19:51:25,389 ==> Preparing: SELECT t_dept.*,t_emp.* FROM t_dept NATURAL JOIN t_emp WHERE t_dept.dept_id=? (BaseJdbcLogger.java:137)
- DEBUG 09-16 19:51:25,421 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:137)
- DEBUG 09-16 19:51:25,455 <== Total: 2 (BaseJdbcLogger.java:137)
-
- Dept{deptId=1, deptName='a部门',
- emps=[
- Emp{empId=1, empName='aaaa', age=20, gender='男', dept=null},
- Emp{empId=2, empName='bbbb', age=23, gender='男', dept=null}
- ]
- }
个人理解:
association 是“关系,关联”的意思,专门用来 负责属性为实体类对象(非List集合)时的映射规则,
collection 是“集合”的意思,专门用来负责属性为List
所以,association负责“多对一”,collection负责”一对多“。
去看尚硅谷杨博超老师的SSM视频。或其他学习资源