这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战
个人感觉:MyBatis对结果的映射算是比Hibernate好一些的地方,但是又时候感觉还是Hibernate的全映射也是可以的,就看你怎么使用,复杂的SQL,Hibernate也是可以搞定的。
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
半自动持久层框架,只能对结果集映射
为了扩展针对于CUD操作的映射,MyBatis Plus全映射(CRUD),Hibernate默认就支持全映射
1.简单映射
前提:针对于单表的结果操作,结果集映射成Java对象的形式有哪些?
查询结果必须设置resultType或者resultMap
select标签中resultMap属性必须找到resultMap标签中id一致
1.1 结果映射为Map
- 使用
resultType="结果集要转换的对象"
(1)默认字段做为KEY
<!-- 记录 Resultset处理成名POJO -->
<select id="load" parameterType="int" resultType="hashmap">
SELECT * FROM sys_user WHERE id=#{userId}
</select>
<select id="listAll" resultType="hashmap">
SELECT * FROM sys_user
</select>
(2)自定义KEY的方式
- 可以给字段设置别名
<select id="load" parameterType="int" resultType="hashmap">
SELECT username userName,nick_name nickName FROM sys_user WHERE id=#{userId}
</select>
- resultMap标签,默认自动映射(字段作为Map中的KEY)
<!-- 最难最复杂的映射标签,指定字段和属性之间的映射关系 -->
<resultMap id="mapMapper" type="map" autoMapping="true">
<result column="username" property="userName"/>
<result column="nick_name" property="nickName"/>
</resultMap>
<!-- resultMap属性去找resultMap标签 -->
<select id="load" parameterType="int" resultMap="mapMapper">
SELECT * FROM sys_user WHERE id=#{userId}
</select>
<select id="listAll" resultMap="mapMapper">
SELECT * FROM sys_user
</select>
1.2 结果映射为自定义对象
<select id="get" parameterType="int" resultType="com.hanpang.model.User">
SELECT id userId,username userName,password pwd,nick_name,age userAge,sex userSex FROM sys_user WHERE id=#{userId}
</select>
<resultMap id="userMapper" type="com.hanpang.model.User">
<!-- JdbcType和JavaType可以忽略不设置 -->
<id column="id" jdbcType="INTEGER" property="userId" javaType="java.lang.Integer"/>
<result column="username" jdbcType="VARCHAR" property="userName" javaType="java.lang.String"/>
<result column="password" property="pwd"/>
<result column="nick_name" property="nickName"/>
<result column="age" property="userAge"/>
<result column="sex" property="userSex"/>
</resultMap>
<select id="queryOne" parameterType="int" resultMap="userMapper">
SELECT * FROM sys_user WHERE id=#{userId}
</select>
<select id="listUser" resultMap="userMapper">
SELECT * FROM sys_user
</select>
1.3 单个值或者单列
<select id="getCount" resultType="_int">
SELECT COUNT(*) FROM sys_user
</select>
<select id="getUserIdList" resultType="int">
SELECT id FROM sys_user
</select>
2.高级映射的衍化
关系数据中表和表之间的关系:一对多和多对一,通过设置外键在多方
- 一对一的关系,实际就是多方的特例索引
Unique - 多对多的关系,实际上是通过中间表(存储外键信息),拆分成两对对一对多和多对一的关系
Java中类和类之间的七种关系:
- 一对一单向
- 一对一双向
- 一对多单向
- 多对一单向
- 一对多和多对一双向
- 多对多单向
- 多对多双向
2.1 准备阶段
User.java文件
public class User {
private Integer user_id;
private String account;
private String password;
private String user_name;
private Integer status;
private Date login_time;
private String ip;
private Integer fk_role_id;
//关联对象
private Role role;
//省略getter和setter方法
}
Role.java 文件
public class Role {
private Integer role_id;
private String role_name;
private String role_key;
private Integer status;
//省略getter和setter方法
}
2.2 association 关联对象标签
主要针对一对一和多对一标签
2.2.1 传统方式处理
- UserMapper.xml映射文件
<mapper namespace="com.shxt.model.User">
<resultMap type="com.shxt.model.User" id="BaseResultMapper">
<id column="user_id" property="user_id"/>
<result column="account" property="account"/>
<result column="password" property="password"/>
<result column="user_name" property="user_name"/>
<result column="status" property="status"/>
<result column="login_time" property="login_time"/>
<result column="ip" property="ip"/>
<result column="fk_role_id" property="fk_role_id"/>
</resultMap>
<sql id="sys_user_columns">
user_id,account,password,user_name,status,login_time,ip,fk_role_id
</sql>
<select id="load" parameterType="_int" resultMap="BaseResultMapper">
SELECT
<include refid="sys_user_columns"/>
FROM
sys_user
WHERE
user_id=#{user_id}
</select>
</mapper>
- UserDao接口和UserDaoImpl实现类
UserDao.java接口代码
public interface UserDao {
User getUserByPK(int user_id);
}
UserDaoImpl.java实现类
public class UserDaoImpl implements UserDao {
@Override
public User getUserByPK( int user_id ) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
return sqlSession.selectOne(User.class.getName()+".load", user_id);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
}
- RoleMapper.xml映射文件
<mapper namespace="com.shxt.model.Role">
<resultMap type="com.shxt.model.Role" id="BaseResultMapper">
<id column="role_id" property="role_id"/>
<result column="role_name" property="role_name"/>
<result column="role_key" property="role_key"/>
<result column="status" property="status"/>
</resultMap>
<sql id="sys_role_columns">
role_id,role_name,role_key,status
</sql>
<select id="get" parameterType="_int" resultMap="BaseResultMapper">
SELECT
<include refid="sys_role_columns"/>
FROM
sys_role
WHERE role_id=#{role_id}
</select>
</mapper>
- RoleDao.java文件和RoleDaoImpl.java实现类
RoleDao.java接口
public interface RoleDao {
Role getRoleByPK(int role_id);
}
RoleDaoImpl.java实现类
public class RoleDaoImpl implements RoleDao {
@Override
public Role getRoleByPK( int role_id ) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
return sqlSession.selectOne(Role.class.getName()+".get", role_id);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
}
- Java代码测试
@Test
public void 获取用户信息(){
UserDao userDao = new UserDaoImpl();//接口回调
User user = userDao.getUserByPK(-999);
//获取对应外键信息
if(user.getFk_role_id()!=null){
RoleDao roleDao = new RoleDaoImpl();
//查询角色对应的信息
Role role = roleDao.getRoleByPK(user.getFk_role_id());
//建立关系
user.setRole(role);
}
System.out.println(user);
}
- 图解说明

2.2.2 resultMap标签之select方式
其实就是替换了
//获取对应外键信息
if(user.getFk_role_id()!=null){
RoleDao roleDao = new RoleDaoImpl();
//查询角色对应的信息
Role role = roleDao.getRoleByPK(user.getFk_role_id());
//建立关系
user.setRole(role);
}
这段代码
- 映射文件
<resultMap type="com.shxt.model.User" id="BaseResultMapper">
<id column="user_id" property="user_id"/>
<result column="account" property="account"/>
<result column="password" property="password"/>
<result column="user_name" property="user_name"/>
<result column="status" property="status"/>
<result column="login_time" property="login_time"/>
<result column="ip" property="ip"/>
<result column="fk_role_id" property="fk_role_id"/>
</resultMap>
<resultMap type="com.shxt.model.User" id="SimpleResultMapper" extends="BaseResultMapper">
<!-- association 用来映射关联对象 -->
<association property="role" javaType="com.shxt.model.Role"
column="fk_role_id"
select="com.shxt.model.Role.get"
/>
</resultMap>
<sql id="sys_user_columns">
user_id,account,password,user_name,status,login_time,ip,fk_role_id
</sql>
<!-- 使用了另一个ID resultMap="SimpleResultMapper" -->
<select id="load" parameterType="_int" resultMap="SimpleResultMapper">
SELECT
<include refid="sys_user_columns"/>
FROM
sys_user
WHERE
user_id=#{user_id}
</select>
- Java测试代码
@Test
public void SELECT方式(){
UserDao userDao = new UserDaoImpl();//接口回调
User user = userDao.getUserByPK(-999);
System.out.println(user);
}
- 图解说明

2.2.3 resultMap标签之resultMap属性方式
- UserDao接口和UserDaoImpl实现类 UserDao.java代码
public interface UserDao {
User getUserLeftJoin(int user_id);
}
UserDaoImpl.java代码
public class UserDaoImpl implements UserDao {
@Override
public User getUserLeftJoin( int user_id ) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
return sqlSession.selectOne(User.class.getName()+".getUserLeftJoin", user_id);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
}
- 映射文件
<mapper namespace="com.shxt.model.User">
<sql id="sys_user_columns_alias">
${alias}.user_id,${alias}.account,${alias}.password,
${alias}.user_name,${alias}.status,${alias}.login_time,
${alias}.ip,${alias}.fk_role_id
</sql>
<resultMap type="com.shxt.model.User" id="BaseResultMapper">
<id column="user_id" property="user_id"/>
<result column="account" property="account"/>
<result column="password" property="password"/>
<result column="user_name" property="user_name"/>
<result column="status" property="status"/>
<result column="login_time" property="login_time"/>
<result column="ip" property="ip"/>
<result column="fk_role_id" property="fk_role_id"/>
</resultMap>
<resultMap type="com.shxt.model.User"
id="JoinResultMapper"
extends="BaseResultMapper">
<association property="role" javaType="com.shxt.model.Role"
resultMap="com.shxt.model.Role.BaseResultMapper"
>
<!-- <id column="role_id" property="role_id"/>
<result column="role_name" property="role_name"/>
<result column="role_key" property="role_key"/>
<result column="status" property="status"/> -->
</association>
</resultMap>
<select id="getUserLeftJoin" parameterType="_int"
resultMap="JoinResultMapper">
SELECT
<include refid="sys_user_columns_alias">
<property name="alias" value="u"/>
</include>
,
<!-- 关键如何找到那些字段 -->
<include refid="com.shxt.model.Role.sys_role_columns_alias">
<property name="alias" value="r"/>
</include>
FROM
sys_user u
LEFT JOIN sys_role r ON u.fk_role_id = r.role_id
WHERE
u.user_id =#{user_id}
</select>
- Java测试代码
@Test
public void 连接查询_结果集处理(){
UserDao userDao = new UserDaoImpl();//接口回调
User user = userDao.getUserLeftJoin(-999);
System.out.println(user);
}
- 图解说明

2.2.4 多对一映射测试
- UserDao接口和UserDaoImpl实现类 UserDao.java代码
public interface UserDao {
List<User> list01();
List<User> list02();
}
UserDaoImpl.java代码
public class UserDaoImpl implements UserDao {
@Override
public List<User> list01() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
return sqlSession.selectList(User.class.getName()+".list01");
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
@Override
public List<User> list02() {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
return sqlSession.selectList(User.class.getName()+".list02");
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
}
- 映射文件
<select id="list01" resultMap="SimpleResultMapper">
SELECT
<include refid="sys_user_columns"/>
FROM
sys_user
</select>
<select id="list02" resultMap="JoinResultMapper">
SELECT
<include refid="sys_user_columns_alias">
<property name="alias" value="u"/>
</include>
,
<include refid="com.shxt.model.Role.sys_role_columns_alias">
<property name="alias" value="r"/>
</include>
FROM
sys_user u
LEFT JOIN sys_role r ON u.fk_role_id = r.role_id
</select>
- 图解说明

3 collection 关联对象标签
主要针对一对多和多对多标签
3.1 准备阶段
User.java持久化类
public class User {
private Integer user_id;
private String account;
private String password;
private String user_name;
private Integer status;
private Date login_time;
private String ip;
private Integer fk_role_id;
}
这里没有设置关联对象了
Role.java持久化类
public class Role {
private Integer role_id;
private String role_name;
private String role_key;
private Integer status;
//关联对象
private List<User> userList;
}
一个角色对应多个用户,我们使用集合进行处理
3.2 MyBatis的处理方式
3.2.1 collection标签之select方式
- 映射文件说明 RoleMapper.xml代码如下:
<mapper namespace="com.shxt.model.Role">
<!-- 基础的映射 -->
<resultMap type="Role" id="BaseResultMapper">
<id column="role_id" property="role_id"/>
<result column="role_name" property="role_name"/>
<result column="role_key" property="role_key"/>
<result column="status" property="status"/>
</resultMap>
<!-- 公共代码字段提取 -->
<sql id="sys_role_columns">
role_id,role_name,role_key,status
</sql>
<sql id="sys_role_columns_alias">
${alias}.role_id,${alias}.role_name,${alias}.role_key,${alias}.status
</sql>
<resultMap type="Role" id="SimpleResultMapper"
extends="BaseResultMapper">
<!-- 配置集合 List<User>-->
<collection property="userList"
javaType="java.util.List"
ofType="com.shxt.model.User"
column="role_id"
select="com.shxt.model.User.listUser"
/>
</resultMap>
<select id="load" parameterType="int" resultMap="SimpleResultMapper">
SELECT
<include refid="sys_role_columns"/>
FROM
sys_role
WHERE
role_id=#{role_id}
</select>
</mapper>
这里使用了<collection> 标签
<collection property="类中的属性"
javaType="类中属性对应的类型,可以省略"
ofType="结果集处理的类型,也可以理解为结合中泛型的类型,必须填写"
column="通过查询的那个字段的值,在进行查询,该字段必须有查询,不然无法查找数据"
select="com.shxt.model.User.listUser 命名空间.ID 使用column的值去执行对应的SQL语句"
/>
UserMapp.xml代码如下:
基本上不会对其进行改变
<mapper namespace="com.shxt.model.User">
<resultMap type="com.shxt.model.User" id="BaseResultMapper">
<id column="user_id" property="user_id"/>
<result column="account" property="account"/>
<result column="password" property="password"/>
<result column="user_name" property="user_name"/>
<result column="status" property="status"/>
<result column="login_time" property="login_time"/>
<result column="ip" property="ip"/>
<result column="fk_role_id" property="fk_role_id"/>
</resultMap>
<sql id="sys_user_columns">
user_id,account,password,user_name,status,login_time,ip,fk_role_id
</sql>
<sql id="sys_user_columns_alias">
${alias}.user_id,${alias}.account,${alias}.password,
${alias}.user_name,${alias}.status,${alias}.login_time,
${alias}.ip,${alias}.fk_role_id
</sql>
<select id="listUser" parameterType="int" resultMap="BaseResultMapper">
SELECT
<include refid="sys_user_columns"/>
FROM
sys_user
WHERE
fk_role_id=#{role_id}
</select>
</mapper>
- RoleDao接口和RoleDaoImpl实现类 RoleDao.java代码如下:
public interface RoleDao {
Role getRoleByPK(int role_id);
}
RoleDaoImpl.java代码如下:
public class RoleDaoImpl implements RoleDao {
@Override
public Role getRoleByPK( int role_id ) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
return sqlSession.selectOne(Role.class.getName()+".load", role_id);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
}
- Java测试代码
@Test
public void test01(){
RoleDao roleDao = new RoleDaoImpl();
System.out.println(roleDao.getRoleByPK(-100));
}
- 图解说明

3.2.2 collection标签之resultMap属性说明
因为select方式总是执行的SQL语句比较多,我们可以通过连接查询解决问题
- 映射文件 RoleMapper.xml代码如下:
<mapper namespace="com.shxt.model.Role">
<resultMap type="Role" id="BaseResultMapper">
<id column="role_id" property="role_id"/>
<result column="role_name" property="role_name"/>
<result column="role_key" property="role_key"/>
<result column="status" property="status"/>
</resultMap>
<sql id="sys_role_columns">
role_id,role_name,role_key,status
</sql>
<sql id="sys_role_columns_alias">
${alias}.role_id,${alias}.role_name,${alias}.role_key,${alias}.status
</sql>
<resultMap type="Role" id="JoinResultMapper" extends="BaseResultMapper">
<collection property="userList" javaType="list" ofType="com.shxt.model.User"
resultMap="com.shxt.model.User.BaseResultMapper"
/>
</resultMap>
<select id="getJoin" parameterType="int" resultMap="JoinResultMapper">
SELECT
<include refid="sys_role_columns_alias">
<property name="alias" value="sr"/>
</include>
,
<include refid="com.shxt.model.User.sys_user_columns_alias">
<property name="alias" value="su"/>
</include>
FROM
sys_role sr
LEFT JOIN sys_user su ON sr.role_id = su.fk_role_id
WHERE
sr.role_id =#{role_id}
</select>
</mapper>
说明
<collection property="userList" javaType="list" ofType="com.shxt.model.User"
resultMap="com.shxt.model.User.BaseResultMapper 命名空间.ID找到结果集映射的位置"
- RoleDao接口和RoleDaoImpl实现类 RoleDao.java代码
public interface RoleDao {
Role getJoinRolrByPK(int role_id);
}
RoleDaoImpl.java代码
public class RoleDaoImpl implements RoleDao {
@Override
public Role getJoinRolrByPK( int role_id ) {
SqlSession sqlSession = null;
try {
sqlSession = MyBatisUtils.getSqlSession();
return sqlSession.selectOne(Role.class.getName()+".getJoin", role_id);
} finally {
MyBatisUtils.closeSqlSession(sqlSession);
}
}
}
- Java测试代码
@Test
public void test02(){
RoleDao roleDao = new RoleDaoImpl();
System.out.println(roleDao.getJoinRolrByPK(-100222));
}
后话:Hibernate的多对多和MyBatis的多对多处理方案不太一样,但是个人还是比较喜欢MyBatis的方式,其实Hibernate也可以一样优秀的处理