Mybatis表对象继承
我们一般用表来表现对象之间的继承关系时通常有三种方式。第一种是把所有对象包含的属性都存放在一张表中,然后用一个字段来区分当前记录对应的对象类型;第二种是每个子类型一张表,每张表都存该对象所有的属性;第三种是基类作为一张表进行存储,每个子类特性的属性都新建一张表进行保存,然后在基类对应的表里面通过一个字段来区分对象的类型。第二种跟普通的处理方式没有什么区;第一种和第三种大同小异,本文将主要围绕第三种方式的实现来描述。
举个例子,就拿我们的组织关系来说吧,组织上有机构、部门、岗位、人员,它们都属于组织,从对象的角度来讲,可以把它们共性的东西,如ID、上级ID、名称等抽取出来作为一个基类,其它特性的东西在子类中表现。本文只是为了表明这种继承的意思,会简化很多。为此,我们可以定义一个基类OrganizationBase,其定义如下。
/**
* 组织基类
*
* @author Elim 2016年12月17日
*/
public abstract class OrganizationBase {
/**
* 主键
*/
private Long id;
/**
* 名称
*/
private String name;
/**
* 类型,1:机构,2:部门,3:岗位,4:个人
*/
private Integer type;
/**
* 父级组织的ID
*/
private Integer parentId;
protected OrganizationBase(Integer type) {
this.type = type;
}
/**
* @return the id
*/
public Long getId() {
return id;
}
/**
* @param id
* the id to set
*/
public void setId(Long id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name
* the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the type
*/
public Integer getType() {
return type;
}
/**
* @param type
* the type to set
*/
public void setType(Integer type) {
this.type = type;
}
/**
* @return the parentId
*/
public Integer getParentId() {
return parentId;
}
/**
* @param parentId
* the parentId to set
*/
public void setParentId(Integer parentId) {
this.parentId = parentId;
}
}
在基类中的type属性是用来区分组织类型的,机构、部门、岗位都没有自己的特殊属性,都完全从父类继承,但是从程序的角度来讲,它们的类定义还是需要的,为此我们定义了Organization、Department、Post类,它们的类定义的结构类似,其中Organization类的定义如下。
/**
* 机构
* @author Elim
* 2016年12月17日
*/
public class Organization extends OrganizationBase {
public Organization() {
super(OrgType.ORG);
}
}
我们给员工定义了一个Person类,其简单的扩充了mobile属性和email属性,具体定义如下。
/**
* 员工
* @author Elim
* 2016年12月17日
*/
public class Person extends OrganizationBase {
/**
* 员工的手机号码
*/
private String mobile;
/**
* 员工的邮箱地址
*/
private String email;
public Person() {
super(OrgType.PERSON);
}
/**
* @return the mobile
*/
public String getMobile() {
return mobile;
}
/**
* @param mobile the mobile to set
*/
public void setMobile(String mobile) {
this.mobile = mobile;
}
/**
* @return the email
*/
public String getEmail() {
return email;
}
/**
* @param email the email to set
*/
public void setEmail(String email) {
this.email = email;
}
}
组织基类型对应的表和员工对应的表的MySQL建表语句如下。
create table t_org(id int primary key auto_increment, name varchar(100), org_type int, parent_id int);
create table t_person(id int,mobile varchar(20), email varchar(100));
我们的增删改查都应该是基于主表和扩展表来的,没有扩展表的除外。我们先来说增、删、改,查放到最后来说。针对OrganizationBase,我们建立对应的OrganizationBaseMapper.xml文件,其增、删、改定义如下。
<insert id="insert" parameterType="com.elim.learn.mybatis.model.OrganizationBase" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
insert into t_org(id,name,org_type,parent_id) values(#{id},#{name},#{type},#{parentId})
</insert>
<insert id="delete" parameterType="java.lang.Long">
delete t_org where id=#{id}
</insert>
<update id="update" parameterType="com.elim.learn.mybatis.model.OrganizationBase">
update t_org
<set>
<if test="name != null">
name = #{name},
</if>
<if test="type != null">
org_type = #{type},
</if>
<if test="parentId != null">
parent_id = #{parentId}
</if>
</set>
where id = #{id}
</update>
对于没有扩展属性的组织来讲,其增、删、改操作直接通过基表对应的增、删、改操作即可,而对于有扩展属性的而言,其增、删、改操作应当还要包括对应的扩展表的操作,如我们的员工。针对员工信息,建立对应的PersonMapper.xml文件,其中的增、删、改定义如下。
<insert id="insert" parameterType="com.elim.learn.mybatis.model.Person">
insert into t_person(id,email,mobile) values(#{id},#{email},#{mobile})
</insert>
<insert id="delete" parameterType="java.lang.Long">
delete t_person where id=#{id}
</insert>
<update id="update" parameterType="com.elim.learn.mybatis.model.Person">
update t_person
<set>
<if test="email != null">
email = #{email},
</if>
<if test="mobile != null">
mobile = #{mobile},
</if>
</set>
where id = #{id}
</update>
我们在新增没有扩展表的记录时,只需要操作OrganizationBaseMapper中的对应操作即可,如下面示例的testInsert();而如果我们是操作有扩展表的,则需要同时操作多个Mapper,如下面示例的testInsertPerson()。
@Test
public void testInsert() {
Organization orgBase = new Organization();
orgBase.setName("TEST_ORG");
this.orgBaseMapper.insert(orgBase);
}
@Test
public void testInsertPerson() {
Person person = new Person();
person.setName("ZhangSan");
person.setEmail("zhangsan@163.com");
person.setMobile("15889898989");
person.setParentId(1);
this.orgBaseMapper.insert(person);
this.personMapper.insert(person);
}
删与改操作是类似的,这里就不再给出对应的测试示例了,有兴趣的朋友可以自己试一下。至于查而言,那么我们又有两种方式了,一种是基表的查询只查询通用信息,其也可以通过区分字段来区分不同的类型,有需要的时候再去查子表,而子表在查询的时候将所有的信息都查询出来。另一种是直接在基表中通过左连接查询出所有的信息。这里以方式二为例,假设我们有一个根据ID查询组织的需求,我们在OrganizationBaseMapper.xml中定义了一个findById的查询,语句如下。
<select id="findById" resultMap="baseResultMap" parameterType="java.lang.Long">
select a.id,a.name,a.org_type,a.parent_id,b.mobile,b.email from t_org a left join t_person b on a.id=b.id where a.id=#{id}
</select>
接着来看一下我们的baseResultMap的定义。
<resultMap type="com.elim.learn.mybatis.model.OrganizationBase" id="baseResultMap">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="parent_id" property="parentId" />
<discriminator javaType="java.lang.Integer" column="org_type">
<case value="1" resultType="com.elim.learn.mybatis.model.Organization" />
<case value="2" resultType="com.elim.learn.mybatis.model.Department" />
<case value="3" resultType="com.elim.learn.mybatis.model.Post" />
<case value="4" resultMap="PersonResultMap" />
</discriminator>
</resultMap>
<resultMap type="com.elim.learn.mybatis.model.Person" id="PersonResultMap">
<result column="email" property="email" />
<result column="mobile" property="mobile" />
</resultMap>
在ResultMap定义中,我们通过discriminator元素来指定类型区分列,并在其下通过case元素指定各种区分列的值对应的返回结果类型或ResultMap。我们可以看到对于没有其它扩展属性的,我们可以直接通过case元素指定返回类型,如case等于1的情况;而有扩展属性的,则可以通过case元素指定扩展属性对应的resultMap,然后再对应的resultMap中再指定扩展属性对应的映射,如case等于4的情况。其实我们也可以直接把结果集映射放到case中,但此时我们需要指定case元素的resultType属性来指定对应的类型,如:
<resultMap type="com.elim.learn.mybatis.model.OrganizationBase" id="baseResultMap">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="parent_id" property="parentId" />
<discriminator javaType="java.lang.Integer" column="org_type">
<case value="1" resultType="com.elim.learn.mybatis.model.Organization" />
<case value="2" resultType="com.elim.learn.mybatis.model.Department" />
<case value="3" resultType="com.elim.learn.mybatis.model.Post" />
<case value="4" resultType="com.elim.learn.mybatis.model.Person">
<result column="mobile" property="mobile"/>
<result column="email" property="email"/>
</case>
</discriminator>
</resultMap>
我们还可以通过resultMap的继承机制来定义结果集映射,先定义一个公共属性映射,然后在最顶层的时候就通过discriminator来区分不同的值对应不同的结果集映射,各个子类型的结果集映射都继承公用的结果集映射,如:
<resultMap type="com.elim.learn.mybatis.model.OrganizationBase"
id="baseResultMap">
<discriminator javaType="java.lang.Integer" column="org_type">
<case value="1" resultMap="OrganizationResultMap" />
<case value="2" resultMap="DepartmentResultMap" />
<case value="3" resultMap="PostResultMap" />
<case value="4" resultMap="PersonResultMap" />
</discriminator>
</resultMap>
<!-- 公共部分的结果集映射 -->
<resultMap type="com.elim.learn.mybatis.model.OrganizationBase"
id="OrganizationBaseResultMap">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="org_type" property="type" />
<result column="parent_id" property="parentId" />
</resultMap>
<!-- 机构结果映射,继承自OrganizationBaseResultMap -->
<resultMap type="com.elim.learn.mybatis.model.Organization"
id="OrganizationResultMap" extends="OrganizationBaseResultMap" />
<resultMap type="com.elim.learn.mybatis.model.Department" id="DepartmentResultMap"
extends="OrganizationBaseResultMap" />
<resultMap type="com.elim.learn.mybatis.model.Post" id="PostResultMap"
extends="OrganizationBaseResultMap" />
<resultMap type="com.elim.learn.mybatis.model.Person" id="PersonResultMap">
<result column="email" property="email" />
<result column="mobile" property="mobile" />
</resultMap>
参考文档
http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#Result_Maps
(注:本文是基于Mybatis3.3.1所写)
相关推荐
SpringBoot 集成 MyBatis-Plus 实现国产数据库适配 MyBatis-Plus 是一款在 MyBatis 的基础上进行扩展的开源工具包,只做增强不做改变,引入 MyBatis-Plus 不会对您现有的 Mybatis 构架产生任何影响。MyBatis-Plus ...
在DAO层,我们将创建`UserMapper`接口,它继承自MyBatis提供的`BaseMapper`接口,并添加一个返回`User`对象的方法,该方法与`UserMapper.xml`中的SQL语句相对应: ```java public interface UserMapper extends ...
Service层结合MyBatis Plus的 CRUD 操作,可以快速实现业务逻辑。 在`mybatisplus-spring-boot`中,你可能会看到以下内容: 1. `entity`包:包含各个数据表对应的实体类,如`User.java`,其中会用到如`@TableId`、`...
实体类的设计应遵循面向对象原则,如封装、继承和多态,以提供更符合业务逻辑的接口。 在实际开发过程中,我们还需要考虑系统的安全性、性能优化以及异常处理。例如,可以使用Spring Security来保护系统免受非法...
MyBatis可以使用简单的XML或注解进行配置和原始映射,将接口和Java的POJOs(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。 Intelij IDEA是一款广泛使用的Java集成开发环境(IDE),其强大的功能和...
Mybatis通过使用简单的XML或注解的方式,将对象与数据库表进行映射,从而帮助开发者避免了几乎所有的JDBC代码和手动设置参数以及获取结果集的问题。 Mybatis是继承自iBatis的,它支持定制化SQL、存储过程以及高级...
1. **自动CRUD操作**:MyBatis-Plus提供了对增删查改(Create, Read, Update, Delete)的基本支持,通过继承BaseMapper接口,无需编写SQL即可实现基本的数据操作。 2. **条件构造器**:QueryWrapper和...
8. **支持ActiveRecord模式**:实体类只需继承Model类即可实现基本的CRUD操作。 9. **代码生成器**:可以通过代码或Maven插件快速生成Mapper、Model、Service和Controller层的代码,支持自定义模板引擎,提高开发...
这个版本是MyBatis的一个稳定版本,发布于2018年,包含了从早期版本继承的诸多改进和新特性,旨在提供更高效、更灵活的数据库操作体验。 描述中提到的"mybatis-3-mybatis-3.4.6框架包"确认了这是一个用于开发的框架...
Mybatis的`association`和`collection`标签是用来处理这种需求的关键组件,它们允许开发者将不同表中相关的数据映射到复杂的Java对象中。 ### 实体类 在给出的内容中,定义了一个名为`EmpDept`的实体类,它继承自`...
以下我们将详细介绍如何使用 MyBatis-Plus 实现分页查询。 1. **添加依赖** 在项目中使用 MyBatis-Plus 进行分页查询,首先需要引入相应的依赖。在 Maven 的 `pom.xml` 文件中添加如下内容: ```xml <groupId>...
MyBatis是一个流行的Java持久层框架,它简化了数据库与Java对象之间的交互,允许开发者通过XML或注解定义SQL语句。在开发过程中,我们有时需要根据数据库中的表结构自动生成对应的Java实体类,这就是MyBatis ...
Mybatis 是一款流行的轻量级持久层框架,它允许开发者将SQL语句直接写在Java代码中,通过注解或XML配置文件实现映射。在本文中,我们将深入探讨如何利用Mybatis的注解实现增删查改(CRUD)操作以及多参数列表查询。 ...
首先,MyBatis会将插件配置信息加载到Configuration类中的InterceptorChain对象中,然后在InterceptorChain对象中循环调用每个插件的plugin方法,以便实现插件的增强功能。 四、插件执行过程 在插件执行过程中,...
3. **配置SqlSessionFactory**:MyBatis的核心对象是SqlSessionFactory,用于创建SqlSession。在Spring中,我们可以使用SqlSessionFactoryBean来创建,它会读取mybatis-config.xml配置文件,配置包括别名、映射文件...
同样,Mybatis-Plus也能生成对应的Mapper接口,这个接口继承了Mybatis-Plus提供的BaseMapper接口,内含了基础的CRUD方法。无需手动编写SQL,只需要定义接口方法,Mybatis-Plus会自动完成SQL拼接。 5. **Service层...
1. 创建自定义拦截器类:继承`Interceptor`接口,并实现`intercept`方法。在这个方法中,我们需要获取到SQL会话对象(`Executor`),以及执行的`StatementHandler`对象。 2. 获取分页参数:通过反射或者其他方式,...
1. **自动化CRUD**:MyBatis Plus提供了自动化的增删改查方法,无需编写SQL,只需通过注解或XML配置实体类和表的关系,即可自动生成对应的Mapper接口和实现类。 2. **无侵入性**:MyBatis Plus设计上尽可能地不改变...
"spring+hibernate和spring+myBatis实现连接多个数据库,同时操作的项目"是针对这种需求的一个解决方案,旨在提供一种灵活且动态的数据源切换机制。 首先,Spring框架作为Java领域中最受欢迎的应用框架之一,其强大...