玩转 SpringBoot 2.x 整合 Mybatis

前言

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

— 以上内容来源 MyBatis官网

说白了MyBatis 就是一个半自动的持久层框架,相对于SpringDataJap 和 Hibernate 它的使用更加灵活,对于复杂业务系统更推荐使用 MyBatis。

本文主要简单介绍如何基于SpringBoot 2 使用 Mybatis,通过本文你将了解到如下内容:

  1. SpringBoot 注解方式 进行增删改查
  2. SpringBoot xml方式 进行增删改查

阅读前需要你必须了解如何搭建 SpringBoot 项目,并且会简单使用 MySql 数据库相关操作。

接下来就开始我们 Demo 实战操作!

SpringBoot 使用MyBaties实战演示

在介绍Demo 实战之前,先带大家了解一下 MyBaties官方提供 SpringBoot 关于注解方式和 XML 方式 2个版本的 Demo。你可以把 github 上的 Samples 代码 clone 下来进行查阅

代码地址: https://github.com/mybatis/spring-boot-starter

官网提供的案例相对比较简单,于是自己对于经常使用的操作完善了一下。闲话少说,接下来直接开整。

注解方式

注解配置和初始化数据

这里开始写注解版的 Demo, 通过SpirngBoot 使用MyBaties 演示一个商品管理的增删改查。

第一步:引入Mybatis 的 starter 依赖和 Mysql 数据库驱动的依赖

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

第二步:创建商品的实体类

/**
 *  商品的实体类
 * @author lijunkui
 */
public class Product {
	private Long id;
    /**商品名称*/
	private String productName;
    /**商品价格*/
	private Double price;
    /**商品简介*/  
	private String productBrief;
    //省略get and set方法
}

第三步:在application.properties 配置文件中 配置数据库信息。

spring.datasource.url=jdbc:mysql://localhost:3306/learn?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

第四步:创建商品表的 sql

CREATE TABLE `product` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '商品id',
  `product_Name` varchar(25) DEFAULT NULL COMMENT '商品名称',
  `price` decimal(8,3) DEFAULT NULL COMMENT '价格',
  `product_Brief` varchar(125) DEFAULT NULL COMMENT '商品简介',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

insert  into `product`(`product_Name`,`price`,`product_Brief`) values ('苹果','20.000','好吃的苹果,红富士大苹果');

到这里基础步骤介绍完毕,接下来就是具体的操作CRUD 操作。

通过Id查询

创建商品的Mapper类 并添加根据id查询功能

@Mapper
public interface ProductMapper {
	
@Results(id="product" ,value= { 
  @Result(property = "id", column = "id", id = true),
  @Result(property = "productName", column = "product_Name"),
  @Result(property = "price", column = "price"),
  @Result(property = "productBrief", column = "product_Brief")
	})
@Select("select * from product where id = #{id}")
	public Product findById(@Param("id") Long id);
}

创建查询测试用例:

@SpringBootTest
@RunWith(SpringRunner.class)
public class ProductMapperTest {
	
	@Autowired
	private ProductMapper productMapper;
	
	@SuppressWarnings("deprecation")
	@Test
	public void findById() {
		Product product = productMapper.findById(1l);
		Assert.assertNotNull(product);
	}
	
}

测试结果:

图片

动态查询

定义条件查询功能
通过@SelectProvider 的type属性指定定义查询条件逻辑的Provider类

@Mapper
public interface ProductMapper {
	@SelectProvider(type = ProductProvider.class, method = "findByCondition")
	public List<Product> findByCondition(Product product);
}

条件逻辑的Provider类 通过 new SQL对象编写条件查询逻辑

public class ProductProvider {
	   
	   public String findByCondition(Product product) {
		   return new SQL() {{
			   SELECT("id,product_Name as productName ,price,product_Brief as productBrief");
			   FROM("product");
			   if (!StringUtils.isEmpty(product.getProductName())) {
				   WHERE("product_Name like CONCAT('%',#{productName},'%')");
        	   }
			   if (product.getPrice()!=null) {
				   WHERE("price = #{price} ");
        	   }
		   }}.toString();
	   }
       
}
动态添加

创建添加商品功能

/**
	 * @param product
	 * @return Long 
	 */
    @Insert("insert into product (product_Name, price,product_Brief)
          values(#{productName}, #{price}, #{productBrief})")
	@Options(useGeneratedKeys=true,keyProperty="id")
	@SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty =
      "id", before = false, resultType = long.class)
	public Long insert(Product product);
修改

创建修改商品功能

	/**
	 * 修改商品
	 * @param product
	 */
	@Update("update product set product_Name=#{productName} , price= #{price} , product_Brief = #{productBrief} where  id=#{id}")
	public void update(Product product);
动态修改

创建动态修改商品功能
通过@UpdateProvider的type属性指定动态修改逻辑的Provider类

    @UpdateProvider(type = ProductProvider.class, method = 
      "updateDynamic")
	public void updateDynamic(Product product);

和条件查询Provider类一样我们通过 new SQL编写动态修改逻辑。

public class ProductProvider {
	   public String updateDynamic(Product product) {  
		   	return new SQL() {{
        	   UPDATE("product");
        	   if (!StringUtils.isEmpty(product.getProductName())) {
        		   SET("product_Name = #{productName}");
        	   }
        	   if (product.getPrice()!=null) {
        		   SET("price = #{price}");
        	   }
        	   if(!StringUtils.isEmpty(product.getProductBrief()))
        		   SET("product_Brief = #{productBrief}");
        	   }}.toString();
       }
}
删除

创建删除商品功能

	 @Delete("delete from product where id=#{id}")
	 public void deleteById(long id);

商品管理完整的测试用例

@SpringBootTest
@RunWith(SpringRunner.class)
public class ProductMapperTest {
	
	@Autowired
	private ProductMapper productMapper;
	
	@SuppressWarnings("deprecation")
	@Test
	public void findById() {
		Product product = productMapper.findById(1l);
		Assert.assertNotNull(product);
	}
	@SuppressWarnings("deprecation")
	@Test
	public void findByCondition() {
		Product product = new Product();
		product.setProductName("蕉");
		List<Product> findByCondition = productMapper.findByCondition(product);
		Assert.assertTrue(findByCondition.size()>0);
	}
	@SuppressWarnings("deprecation")
	@Test
	public void insert() {
		Product product = new Product();
		product.setProductName("香蕉");
		product.setPrice(45d);
		product.setProductBrief("好吃的香蕉!");
		Long insert = productMapper.insert(product);
		Assert.assertTrue(insert > 0 );
	}
	@Test
	public void update() {
		Product product = new Product();
		product.setId(3l);
		product.setProductName("香蕉3");
		product.setPrice(45d);
		product.setProductBrief("好吃的香蕉!");
		productMapper.update(product);
	}
	
	@Test
	public void updateDynamic() {
		Product product = new Product();
		product.setId(4l);
		product.setProductName("香蕉4");
		productMapper.updateDynamic(product);
	}
	@Test
	public void deleteById() {
		productMapper.deleteById(4l);
	}
}

XML方式

XML配置和初始化数据

XMl的方式 通过 Hotel 的增删改查功能进行演示。

Hotel 表sql 和测试数据

CREATE TABLE `hotel` (
  `id` bigint(10) NOT NULL AUTO_INCREMENT COMMENT '旅馆id',
  `city` varchar(125) DEFAULT NULL COMMENT '城市',
  `name` varchar(125) DEFAULT NULL COMMENT '旅馆名称',
  `address` varchar(256) DEFAULT NULL COMMENT '旅馆地址',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

INSERT INTO `hotel`(`city`,`name`,`address`) VALUES ( '北京','汉庭','朝阳区富明路112号');

创建Hotle 实体 其中包含 旅馆id 城市 旅馆名称 旅馆地址 成员属性

public class Hotel {
	private Long id;
	private String city;
	private String name;
	private String address;
}
通过Id查询

创建Mapper类映射的xml HotelMapper.xml namespace 是 HotelMapper 的包路径地址。
然后在创建通过 Id 查询 sql 配置。

<?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 namespace="cn.lijunkui.mybaties.mapper.HotelMapper">
    <select id="selectByCityId" resultType="Hotel">
        select * from hotel where id = #{id}
    </select>
</mapper>

创建mybatis-config.xml 并且设置HotelMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <package name="cn.lijunkui.mybaties.domain"/>
    </typeAliases>
    <mappers>
        <mapper resource="mybaties/mapper/HotelMapper.xml"/>
    </mappers>
</configuration>

配置文件目录地址如下图:

图片

在Hotel 的Mapper类中创建通过 Id 查询 selectByCityId 方法。

@Mapper
public interface HotelMapper {
	Hotel selectByCityId(long id);
}

需要注意的是 方法的名称要和HotelMapper.xml 通过 Id 查询 sql 配置 id一致。

编写测试用例:

@SpringBootTest
@RunWith(SpringRunner.class)
public class HotelMapperTest {
	
	@Autowired
	private HotelMapper hotelMapper;
	
	@SuppressWarnings("deprecation")
	@Test
	public void selectByCityId() {
		Hotel result = hotelMapper.selectByCityId(1l);
		Assert.assertNotNull(result);
	}
}
查询所有

HotelMapper.xml 中的配置

 <resultMap id="HotelResultMap" type="cn.lijunkui.mybaties.xml.domain.Hotel" >
	 <id column="id" property="id" jdbcType="BIGINT" />
	 <result column="city" property="city" jdbcType="VARCHAR" />
	 <result column="name" property="name" jdbcType="VARCHAR" />
	 <result column="address" property="address" jdbcType="VARCHAR" />
</resultMap>

<sql id="baseSelect">
        select id, city, name, address from hotel
</sql>

<select id="selectHotelList" parameterType="cn.lijunkui.mybaties.xml.domain.Hotel" resultMap="HotelResultMap">
  <include refid="baseSelect"/>
  <where>  
    <if test="id != null "> and id = #{id}</if>
    <if test="city != null  and city != '' "> and city = #{city}</if>
    <if test="name != null and name != '' "> and name = #{name}</if>
    <if test="address != null  and address != '' "> and address = #
        {address}</if>
  </where>
</select>

我们需要在HotelMapper.xml 配置resultMap (返回参数的结果集)
sql 定义一些公共的sql 代码

HotelMapper 类中创建查询所有的方法

@Mapper
public interface HotelMapper {
	List<Hotel> selectHotelList(Hotel hotel);
}
分页查询

HotelMapper.xml 中的配置

    <select id="selectHotelListByPage" resultMap="HotelResultMap" parameterType="cn.lijunkui.mybaties.xml.param.HotalParam">
	    <include refid="baseSelect" />
	   <where>  
            <if test="id != null "> and id = #{id}</if>
             <if test="city != null  and city != '' "> and city = #{city}</if>
             <if test="name != null and name != '' "> and name = #{name}</if>
             <if test="address != null  and address != '' "> and address = #{address}</if>
         </where>
	    limit #{startIndex} , #{pageSize}
	</select>

分页的查询条件和返回结果基础封装类

public class PageInfo {
	private Integer pageSize = 10;
    private Integer currentPage= 1;
    private Integer startIndex;
    
	public Integer getStartIndex() {
		this.startIndex = (currentPage-1) * pageSize;
		return startIndex;
	}
}

Hotal 查询条件数据封装类

public class HotalParam extends PageInfo{
	private Long id;
	private String city;
	private String name;
	private String address;
}

分页的返回结果封装类

public class Page<T> extends PageInfo {
    private Integer totalCount;
    private List<T> items;
}

HotelMapper 类中创建查询所有的方法

@Mapper
public interface HotelMapper {
	List<Hotel> selectHotelListByPage(HotalParam hotalParam);
}

分页查询测试类:

@Test
	public void selectHotelListByPage(){
        //查询第一页数据
		HotalParam hotalParam = new HotalParam();
		List<Hotel> hotelList = hotelMapper.selectHotelListByPage(hotalParam);
		List<Hotel> allHotel = hotelMapper.selectHotelList(new Hotel());
		Page<Hotel> page = new Page();
		page.setItems(hotelList);
		page.setPageSize(hotalParam.getPageSize());
		page.setCurrentPage(hotalParam.getCurrentPage());
		page.setTotalCount(allHotel.size());
		System.out.println("------------------------------------");
		//查询第二页数据
        HotalParam hotalParam2 = new HotalParam();
		hotalParam2.setCurrentPage(2);
		List<Hotel> hotelList2 = hotelMapper.selectHotelListByPage(hotalParam2);
		System.out.println("------------------------------------");
	}
动态修改

HotelMapper.xml 中的配置

    <update id="update" parameterType="cn.lijunkui.mybaties.xml.domain.Hotel">
        update hotel
        <trim prefix="SET" suffixOverrides=",">
            <if test="city != null  and city != ''  ">city = #{city},</if>
            <if test="name != null and name != '' ">name = #{name},</if>
            <if test="address != null  and address != '' ">address = #{address},</if>
        </trim>
        where id = #{id}
    </update>

HotelMapper 类中创建动态修改的方法

@Mapper
public interface HotelMapper {
	void update(Hotel hotel);
}
删除

HotelMapper.xml 中的配置

    <delete id="deleteById" parameterType="Long">
        delete from hotel where id = #{id}
    </delete>

HotelMapper 类中创建删除方法

@Mapper
public interface HotelMapper {
	void deleteById(long id);
}
批量删除

HotelMapper.xml 中的配置

    <delete id="deleteByIds" parameterType="Long">
        delete from hotel where id in 
        <foreach item="id" collection="array" open="(" separator="," close=")">
            #{id}
        </foreach>
    </delete>

HotelMapper 类中创建批量删除方法

@Mapper
public interface HotelMapper {
	void deleteByIds(Long[] ids);
}

小结

SpringBoot XML 和 注解的方式可以根据个人的喜好自行选择。不过个人还是推荐使用 XML的方式,因为注解的方式如果有改动的话还需要在去修改DAO类。如果你还没有在SpringBoot 上操作过Mybatis 还等什么抓紧根据本文操作一遍吧。

代码示例

我本地环境如下:

  • SpringBoot Version: 2.1.0.RELEASE
  • Apache Maven Version: 3.6.0
  • Java Version: 1.8.0_144
  • IDEA:Spring Tools Suite (STS)

整合过程如出现问题可以在我的GitHub 仓库 springbootexamples 中模块名为 spring-boot-2.x-mybaties 项目中进行对比查看

GitHub:https://github.com/zhuoqianmingyue/springbootexamples

参考文献

  • http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
  • http://www.mybatis.org/mybatis-3/java-api.html
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值