Spring Boot初步学习03

基于前文"Spring Boot初步学习02"(点击前往查看),已经学习了Spring框架整合连接池的部分,连接池就是用于与数据库连接的工具,那么本文就继续讲解与数据库交互的部分---整合Mybatis框架.

Mybatis框架

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)

以上是百度中对于Mybatis框架的概述,在我理解来说,Mybatis框架是现在较为优秀,使用较为广泛的一个持久层框架,底层时基于JDBC去实现与数据库的交互,并且在使用的过程中,可以灵活去编写SQL语句,并且对于JDBC做了优化与封装,框架较小型,但很适用.

如今项目中使用Mybatis框架时,通常是由Spring框架进行整合,去实现数据交互操作,接下来就来说一下在Spring Boot中如何整合Mybatis.

整合过程

使用过程

测试类<-->mybatis<-->JDBC<-->Driver<-->数据库

需要注意的是:环节之间都是耦合于接口的,这样的设计更加灵活,更低耦合易维护修改.

创建项目

首先需要创建Spring Boot项目,创建过程可见Spring Boot快速入门案例.

当然如果已经有创建好的项目直接使用即可.

添加Mybatis依赖

添加依赖时,主要参考官网 mybatis.org/spring ,在springboot菜单中找到启动依赖,复制粘贴至pom.xml中

<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的整合就已经完成了,很方便简单,后面是一些基础业务的实现.

业务实现

基于单个ID进行删除


创建数据层层接口

首先要创建数据层接口,代码如下:

@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接口的业务方法,实现对数据库的操作.

基于多个ID批量删除


上文中也有提到复杂的sql语句还是要写在映射文件中(xml文件中)利用动态SQL进行映射的,这个案例就要实际操作一下.

创建xml映射文件

首先创建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映射.

增强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>

这样就解决了所有情况可以安全使用了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值