基于前文"Spring Boot初步学习02"(点击前往查看),已经学习了Spring框架整合链接池的部分,链接池就是用于与数据库链接的工具,那么本文就继续讲解与数据库交互的部分---整合Mybatis框架.java
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,而且更名为MyBatis 。2013年11月迁移到Github。spring
iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)sql
以上是百度中对于Mybatis框架的概述,在我理解来讲,Mybatis框架是如今较为优秀,使用较为普遍的一个持久层框架,底层时基于JDBC去实现与数据库的交互,而且在使用的过程当中,能够灵活去编写SQL语句,而且对于JDBC作了优化与封装,框架较小型,但很适用.数据库
现在项目中使用Mybatis框架时,一般是由Spring框架进行整合,去实现数据交互操做,接下来就来讲一下在Spring Boot中如何整合Mybatis.apache
测试类<-->mybatis<-->JDBC<-->Driver<-->数据库segmentfault
须要注意的是:环节之间都是耦合于接口的,这样的设计更加灵活,更低耦合易维护修改.数组
首先须要建立Spring Boot项目,建立过程可见Spring Boot快速入门案例.安全
固然若是已经有建立好的项目直接使用便可.springboot
添加依赖时,主要参考官网 mybatis.org/spring ,在springboot菜单中找到启动依赖,复制粘贴至pom.xml中mybatis
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.1</version> </dependency>
另外一种方式:右键项目中pom.xml-->spring-->Edit Starters-->搜索Mybatis,添加依赖.
但要注意:springboot并无为mybatis指定版本,以这种方式添加依赖,须要本身指定版本.
Spring Boot特色就是零配置或简单配置,在mybatis官网中,虽然提供了一些配置,可是也都是可选的,不配置也能够正常运行,这里建议配置几点
#spring.mybatis mybatis.configuration.default-statement-timeout=30 mybatis.configuration.map-underscore-to-camel-case=true logging.level.com.cy=DEBUG
前两个配置分别是:设置sql超时时间以及将数据库中的user_name(这类下划线命名)自动转换为userName(Java中的驼峰命名)
第三个配置是mybatis中的sql日志的输出:其中com.cy为我项目中的根包.
到这里关于mybatis与Springboot的整合就已经完成了,很方便简单,后面是一些基础业务的实现.
首先要建立数据层接口,代码以下:
@Mapper public interface GoodsDao {}
其中@Mapper注解是由Mybatis提供,描述数据层接口的的注解,用于告诉Spring框架此接口的实现由mybatis建立,并将其实现类对象存储到spring容器,交由spring管理.
须要在数据层接口中,编写实际运行的业务方法,代码以下:
@Mapper public interface GoodsDao { /** * 基于商品id执行删除业务 * @param id * @return 删除的行数 */ @Delete("delete from tb_goods where id=#{id}") public int deleteById(Integer id); }
这种业务方法的编写模式,是将简单的sql语句经过注解的形式进行定义,写在方法上进行描述,可是复杂的sql语句仍是要写在映射文件中(xml文件中).
首先须要说的是,在测试类中咱们声明属性时只经过@Autowired注解声明接口(@Mapper描述的接口)不写实现类,是因为基于咱们已经将springboot和mybatis整合,实现类会由mybatis建立再交由spring框架进行依赖注入(DI),因此咱们只要"面向接口"便可,实际建立由框架替咱们操心.
另外,若是你想要去肯定框架建立的实现类到底是什么呢?
能够经过打桩(System.out.println(goodsDao.getClass().getName());)或是加断点的方式获得答案.
测试类代码以下:
@SpringBootTest public class GoodsDaoTests { @Autowired private GoodsDao goodsDao; @Test public void testDeleteById() { int rows = goodsDao.deleteById(10); System.out.println("rows="+rows); } }
测试类是经过建立的实现类对象去调用@Mapper接口的业务方法,实现对数据库的操做.
上文中也有提到复杂的sql语句仍是要写在映射文件中(xml文件中)利用动态SQL进行映射的,这个案例就要实际操做一下.
首先建立xml映射文件,springboot项目中有严格的目录分类,须要将xml文件放在src/main/resource目录下,咱们能够再建立mapper/goods目录,而后将咱们的GoodsMapper.xml映射文件放入其中.
在映射文件中,首先须要添加官网中给出的头标签:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
而后在头标签下添加<mapper>标签并在其中添加sql标签及其语句,此案例是根据ID批量删除,代码以下:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods where id in <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </delete> </mapper>
在@Mapper接口中定义批量删除多个元素的方法,代码以下:
@Mapper public interface GoodsDao { /** * 基于多个商品id删除 * @param ids * @return 删除的行数 */ public int deleteObjects(@Param("ids")Integer... ids); }
方法中传参为"(@Param("ids")Integer... ids)",这是可变参数,能够理解为一类特殊的数组,能够传入0/1/2...n个数均可.通常最新版本的mybatis能够不加"@Param("ids")"这部分.
注意:xml文件中的namespace与接口的全限定类名对应,SQL标签的ID要与对应的接口方法名对应.
如今咱们已经写好了映射文件,以及接口方法,可若是有多个xml文件,spring框架如何知道那个是咱们要它进行管理的呢?
就须要在application.properties配置文件中添加配置以下:
mybatis.mapper-locations=classpath:/mapper/*/*.xml
"*"为通配符,意味全部的,咱们的xml映射文件路径是在根目录下的mapper/goods/GoodsMapper.xml,就在配置的范围内.
在src/test/java目录下编写测试类,代码以下:
@SpringBootTest public class GoodsDaoTests { @Autowired private GoodsDao goodsDao; @Test public void testDeleteObjects() { int rows = goodsDao.deleteObjects(6,7,8,9); System.out.println("rows="+rows); } }
底层的执行顺序是:
测试方法执行时,咱们调用接口实现类的方法,实现类内部会检测接口方法上是否有定义sql映射;假如没有会基于接口类全名找到对应的配置的映射文件,而后再基于方法名找到对应映射文件中的标签,进而获取sql映射.
以上已经完成了咱们的要求,可是在xml映射文件中写复杂SQL语句时,咱们须要增强SQL语句的可靠性,尤为是删除语句,在对数据库进行操做时,删除语句永远是咱们最须要当心的!
咱们须要考虑到传入各类数据的状况,如上文所写的:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods where id in <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </delete> </mapper>
当咱们若是什么都不传时,SQL语句就变为:delete from tb_goods where id in ;这样就会报错,因此咱们能够添加动态SQL完善!以下:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods <if test="ids!=null and ids.length>0"> where id in <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </if> </delete> </mapper>
加入<if>标签进行判断,排除了传入null的状况,可是又发现ids不为null时能够正常执行,但若是ids为null,没进入判断,SQL语句是没有语法问题,可是执行就变为:delete from tb_goods,删除整个表,在工做中这就是铸成大错了!因此还须要进一步改进,以下再加入<where>标签:
<mapper namespace="com.cy.pj.goods.dao.GoodsDao"> <delete id="deleteObjects"> delete from tb_goods <where> <if test="ids!=null and ids.length>0"> id in <!-- (1,2,3,4) --> <foreach collection="ids" open="(" item="id" separator="," close=")"> #{id} </foreach> </if> or 1=2 </where> </delete> </mapper>
这样就解决了全部状况能够安全使用了.