【MyBatis整合Spring开发+MyBatis多对多关联查询】

时间:2023-02-22 15:25:45

MyBatis整合Spring开发

本文关键词

  • SqlSessionFactoryBean
  • MapperScannerConfigurer

一、引言

JDBC规范了Java编程如何去操作数据库,MyBatis框架让程序开发更集中于关键的sql编写。但是MyBatis框架对应的Mapper接口、以及XML的配置往往也是比较繁琐的。因此,可以考虑将MyBatis整合Spring框架中,减少一些不必要的重复代码,优化程序开发。


二、MyBatis单独使用产生的问题

代码耦合
每次在获取对应的mapper对象来执行sql,都需要获得sqlSession对象,再用sqlSession对象去获取mapper对象。


String resource = "mybatis-config.xml";
//加载核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
//获取sqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取对应映射对象,执行sql
XXXMapper mapper = sqlSession.getMapper(XXXMapper.class);

当然,获取sqlSession对象可以单独抽离出来,可以不用每次都再去获取一遍。但是通过sqlSession对象去获取mapper对象的过程却难以省略,而且跟程序耦合死了。


三、MyBatis整合Spring开发

① 相关依赖
mybatis-spring整合开发的maven依赖


<!--spring和mybatis整合开发的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>

② 获取SqlSessionFactory
MyBatis是通过SqlSessionFactoryBuilder来获取SqlSessionFactory对象的。在整合开发的情形,通过SqlSessionFactoryBean来创建。
SqlSessionFactoryBean相应配置
可以在Spring核心配置文件applicationcontext.xml中做如下配置:


<!--spring和mybatis整合的工厂bean-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>

因为是Spring框架开发,数据源的配置也可以在applicationcontext.xml中完成。


<!--数据源-->
<bean id="dataSource"
class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="username" value="root" />
<property name="password" value="root" />
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8" />
</bean>

③ 获取mapper/dao对象
Ⅰ、硬编码
单独使用MyBatis是需要通过sqlSession去获取对应的mapper,是硬编码的形式来获取sql执行对象,不便于后期的维护。


//获取对应映射对象,执行sql
XXXMapper mapper = sqlSession.getMapper(XXXMapper.class);

Ⅱ、通过MapperFactoryBean注入容器
通过配置应用容器,获取MapperFactoryBean工厂bean。这种形式虽然解耦了,但是不难发现一次配置只对应了一个mapper对象。mapper对象一多,配置起来就显得相当繁琐。


//MapperFactoryBean工厂bean,用于获取对象
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

Ⅲ、通过MapperScannerConfigurer注入容器
MapperScannerConfigurer的作用其实与MapperFactoryBean类似,都是通过工厂bean获取程序需要的mapper对象。但是MapperScannerConfigurer的属性允许它批量注册包路径下的所有类到容器中。


//MapperScannerConfigurer实现了FactoryBean接口,可以批量注入
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.viewscenes.netsupervisor.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>


四、总结

MyBatis开发到MyBatis整合Spring开发,整个优化流程更类似于在生命周期上优化:获取SqlSessionFactory -> SqlSession对象 -> 获取mapper/dao对象。在各个节点做适当的抽离,让程序编码更加优雅。



》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》》

接下来讲解:

MyBatis多对多关联查询

一、引言

MyBatis有一个强大结果映射功能,在开发中能帮助快速封装查询结果。


二、一般单表结果映射

①隐式resultMap
Ⅰ map类型
在隐式的resultMap结果映射里面,我们无需配置resultMap。只需要将resultType设置为map类型即可,MyBatis会帮助我们将列名映射到HashMap的键Key上,以封装我们查询到的结果,如下:


<select id="findUserById" resultType="map">
select id, username, password
from t_user
where id = #{id}
</select>

Ⅱ 实体/结果类
实际开发中,我们经常会用POJO、简单JavaBean、Entity、DTO类型来封装我们的查询结果。当然MyBatis也可以帮我们隐式的完成封装,如下:


<select id="findUserById" resultType="com.example.dto.User">
select id, username, password
from t_user
where id = #{id}
</select>

②显式resultMap
显示配置resultMap,允许我们实体/结果类的属性,与实际数据库表的字段不同(实际开发中,表设计的字段会与实体类的属性有所不同)。比如属性id对应表字段可能是user_id,如下:


<!-- mybatis-config.xml 中 -->
<typeAlias type="com.someapp.model.User" alias="User"/>
<!-- SQL 映射 XML 中 -->
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>

配置好resultMap,我们只需在相应的sql语句内做好引用即可。


<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>

单是看到这里,可能会觉得使用resultType隐式配置resultMap反而更简单易用,不需要再费劲去配置resultMap。但是实际开发中,我们的结果/实体类可能会嵌套结果/实体类的集合,可以先往下看。


三、多对多关联结果映射

结果内含list集合嵌套(2主表+1中间关系表)
结果/实体类,此处我们的结果/实体类为CheckItem和CheckGroup,其中CheckGroup的内部又嵌套有CheckItem的List集合,具体如下:


//检查项
public class CheckItem implements Serializable {
private Integer id;//主键
private String name;//项目名称
//...此处省略其他非关键代码
}
//检查组
public class CheckGroup implements Serializable {
private Integer id;//主键
private String name;//名称
private List<CheckItem> checkItems;//一个检查组合包含多个检查项
//...此处省略其他非关键代码
}

Ⅰ 一般sql形式
在学习sql的时候我们会去使用join的形式来完成多表查询,具体sql如下:


/* 为了更容易看清结构,此处故意将各个模块拆开展示
SELECT
cg.id cgid,
cg.name cgname,
ci.id ciid,
ci.name ciname
FROM
t_checkgroup cg
LEFT OUTER JOIN
t_checkgroup_checkitem cgci
ON
cgci.checkgroup_id = cg.id
LEFT OUTER JOIN
t_checkitem ci
ON
ci.id = cgci.checkitem_id
WHERE
cg.id = 1;

虽然通过编写能够帮助我们查询到想要的数据,但是往往这个时候的结果类是嵌套的,即CheckGroup的结果类里面包含了CheckItem的集合。我们无法直接对结果进行封装,这个时候resultMap就可以帮助我们解决这样的问题。
Ⅱ resultMap形式
显示配置resultMap,可以帮助我们实现封装嵌套集合的结果类。当然其他更复杂的结果类型也可以做类似封装,具体如下:

【MyBatis整合Spring开发+MyBatis多对多关联查询】

关键配置: ①collection集合的配置; ②sql语句中列id的传递。


四、总结

结果映射在MyBatis的使用中非常关键,resultMap的功能非常强大,能帮助我们做好结果映射这件事情。所以可以多加练习resultMap的使用。