SpringBoot整合Mybatis
创建数据库和表
-- 删除tb_brand表
drop table if exists tb_brand;
-- 创建tb_brand表
create table tb_brand
(
-- id 主键
id int primary key auto_increment,
-- 品牌名称
brand_name varchar(20),
-- 企业名称
company_name varchar(20),
-- 排序字段
ordered int,
-- 描述信息
description varchar(100),
-- 状态:0:禁用 1:启用
status int
);
-- 添加数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
('小米', '小米科技有限公司', 50, 'are you ok', 1);
创建项目
目录结构
导入pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 日志依赖-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
yml配置
server:
port: 8888
spring:
application:
name: mybatis_test
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_test?useSSL=false&serverTimezone=UTC
username: root
password: 1234
mybatis:
mapper-locations: classpath:dao/*.xml
map-underscore-to-camel-case: true
这里主要是配置数据源和mybatis的配置
mapper-locations:xml扫描,多个目录用逗号或者分号分隔(告诉 Dao所对应的 XML 文件位置)
map-underscore-to-camel-case:驼峰命名法转换
创建对应实体类
@Data
public class Brand {
// id 主键
private Integer id;
// 品牌名称
private String brandName;
// 企业名称
private String companyName;
// 排序字段
private Integer ordered;
// 描述信息
private String description;
// 状态:0:禁用 1:启用
private Integer status;
}
创建数据层Dao类
@Mappre
public interface BrandDao {
}
@Repository和@Mapper的区别
- @Repository和@Mapper都是作用在dao层的接口,使其生成代理对象Bean。
- @Repository:需要在添加配置地址@MapperScannerConfigurer来使用,单独使用会报错
- @Mapper:只需要在dao类上使用就行,若有多个Mapper在启动类上加MapperScan(“mapper所在的包”)就行
创建对应的Dao对应的xml文件
在resources包下创建路径与Dao一样的包,这里要注意创建多级包的时候不要用“.”的方式例如:com.mybatistest.dao。而是要用“/”的方式,例如com/mybatistest/dao,创建好包后再创建与Dao类同名的xml文件如:BrandDao.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 namespace="com.example.mybatistest.dao.BrandDao">
</mapper>
这里的mapper
标签表示对应的命名空间
- namespace属性:填入对应的Dao地址
使用mybatis进行增删改查
查询方法
-
查询所有
在BrandDao中编写方法/** * 查询所有 * @return */ List<Brand> selectAll();
在BrandDao.xml中编写对应的sql语句,这里可以使用mybatisX插件来自动生成,生成方法:安装好插件并重启后选中方法名,按住 alt+enter。
在BrandDao.xml中编写条件查询所有的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="com.example.mybatistest.dao.BrandDao"> <!-- 查询所有对象--> <select id="selectAll" resultMap="brandResultMap"> select * from tb_brand; </select> <resultMap id="brandResultMap" type="com.example.mybatistest.domain.Brand"> <result column="brand_name" property="brandName"/> <result column="company_name" property="companyName"/> </resultMap> </mapper>
select
标签代表查询- id属性:Dao对应的方法名
- resultMap属性:要使用哪个resultMap标签的内容
resultMap
标签来定义字段和属性的映射关系的方式,在domain实体类属性名与表中的列名不一致的时候可以使用- id属性:唯一性的名称,以此名称用来被使用
- type属性:用来指定哪个domain实体类
- column属性:代表数据库表的列名
- property属性:代表domain实体类中的属性名
一个
result
标签代表一组映射关系在测试类中测试
@Test void testSelectAll(){ List<Brand> brands = brandDao.selectAll(); System.out.println(brands); }
运行结果
[Brand(id=1, brandName=三只松鼠, companyName=三只松鼠股份有限公司, ordered=5, description=好吃不上火, status=0), Brand(id=2, brandName=华为, companyName=华为技术有限公司, ordered=100, description=华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界, status=1), Brand(id=3, brandName=小米, companyName=小米科技有限公司, ordered=50, description=are you ok, status=1)]
-
根据id查询
在BrandDao中添加对应方法
/** * 根据id查询 * @param id * @return */ Brand selectById(int id);
在xml中添加对应的sql语句
<!-- 根据id查询对象--> <select id="selectById" resultMap="brandResultMap" parameterType="int"> select * from tb_brand where id = #{id}; </select>
parameterType属性:
ParameterType
来指定参数类型。只不过该属性都可以省略。mybatis提供了两种参数占位符:
-
#{} :执行SQL时,会将 #{} 占位符替换为?,将来自动设置参数值。#{} 底层使用的是
PreparedStatement
(安全) -
${} :拼接SQL。底层使用的是
Statement
(不安全),会存在SQL注入问题。
编写测试方法
@Test void testSelectById(){ int id = 2; Brand brand = brandDao.selectById(id); System.out.println(brand); }
运行结果
查id为2的数据
Brand(id=2, brandName=华为, companyName=华为技术有限公司, ordered=100, description=华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界, status=1)
-
-
固定条件个数的多条件查询
我们在开发中经常会遇到多条件查询,例如有好几个输入框,根据用户输入的数据进行查询
在BandDao中编写方法
/** * 固定条件个数的多条件查询 * @param brand * @return */ List<Brand> selectByCondition(Brand brand);
在xml文件中添加对应的sql语句
<!-- 多条件查询--> <select id="selectByCondition" resultMap="brandResultMap"> select * from tb_brand where status = #{status} and brandName like #{brandName} and company_name like #{companyName}; </select>
编写测试方法
@Test void testSelectCondition(){ Brand brand = new Brand(); brand.setStatus(1); brand.setBrandName("%小米%"); brand.setCompanyName("%小米科技有限公司%"); List<Brand> brands = brandDao.selectByCondition(brand); System.out.println(brands); }
运行结果:
[Brand(id=3, brandName=小米, companyName=小米科技有限公司, ordered=50, description=are you ok, status=1)]
-
动态条件个数的多条件查询
上面多条件是固定条件个数的,而在实际情况下,往往不确定客户会输入几个查询条件,以下是动态条件个数的多条件查询
该功能有多个参数,我们就需要考虑定义接口时,参数应该如何定义。Mybatis针对多参数有多种实现
-
使用
@Param("参数名称")
标记每一个参数,在映射配置文件中就需要使用#{参数名称}
进行占位List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName,@Param("brandName") String brandName);
-
将多个参数封装成一个 实体对象 ,将该实体对象作为接口的方法参数。该方式要求在映射配置文件的SQL中使用
#{内容}
时,里面的内容必须和实体类属性名保持一致。List<Brand> selectByCondition(Brand brand);
-
将多个参数封装到map集合中,将map集合作为接口的方法参数。该方式要求在映射配置文件的SQL中使用
#{内容}
时,里面的内容必须和map集合中键的名称一致。List<Brand> selectByCondition(Map map);
在BrandDao中编写方法
/** * 动态条件个数的多条件查询 * @param brand * @return */ List<Brand> selectByConditions(Brand brand);
在xml文件中添加对应的sql语句
<!-- 动态多条件查询--> <select id="selectByConditions" resultMap="brandResultMap"> select * from tb_brand <where> <if test="status != null"> and status = #{status} </if> <if test="brandName != null and brandName != ''"> and brand_name like #{brandName} </if> <if test="companyName != null and companyName != ''"> and company_name like #{companyName} </if> </where> </select>
以上语句用
where
标签代替了where关键字可以在status有传入数据的时候拼接sql语句时忽略前面的and。if
标签来判断字段有没有输入参数,有的话就拼接sql语句,没有则不拼接测试方法
@Test void testSelectConditions(){ Brand brand = new Brand(); Brand brand2 = new Brand(); Brand brand3 = new Brand(); brand.setStatus(1); brand2.setBrandName("%小米%"); brand3.setCompanyName("%小米科技有限公司%"); List<Brand> brands1 = brandDao.selectByConditions(brand); List<Brand> brands2 = brandDao.selectByConditions(brand2); List<Brand> brands3 = brandDao.selectByConditions(brand3); System.out.println(brands1); System.out.println(brands2); System.out.println(brands3); }
模拟用户输入的三种条件情况
运行结果
[Brand(id=2, brandName=华为, companyName=华为技术有限公司, ordered=100, description=华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界, status=1), Brand(id=3, brandName=小米, companyName=小米科技有限公司, ordered=50, description=are you ok, status=1)] [Brand(id=3, brandName=小米, companyName=小米科技有限公司, ordered=50, description=are you ok, status=1)] [Brand(id=3, brandName=小米, companyName=小米科技有限公司, ordered=50, description=are you ok, status=1)]
-
-
动态单条件查询
在查询时只能选择
品牌名称
、当前状态
、企业名称
这三个条件中的一个,但是用户到底选择哪儿一个,我们并不能确定。这种就属于单个条件的动态SQL语句。这种需求需要使用到
choose(when,otherwise)标签
实现, 而choose
标签类似于Java 中的switch语句。在BrandDao中编写方法
/** * 单条件动态查询 * @param brand * @return */ List<Brand> selectByConditionSingle(Brand brand);
在xml文件中添加sql语句
<!-- 单动态条件查询--> <select id="selectByConditionSingle" resultMap="brandResultMap"> select * from tb_brand <where> <choose><!-- 相当于swicth--> <when test="status != null"> <!-- 相当于case--> and status = #{status} </when> <when test="brandName != null and brandName != ''"> and brand_name like #{brandName} </when> <when test="companyName != null and companyName != ''"> and company_name like #{companyName} </when> </choose> </where> </select>
这里使用
choose
与when
标签来选择输入的数据再进行sql语句的拼接。测试方法
略
运行结果
略
增加方法
-
在BrandDao中编写方法
/** * 增加数据 * @param brand * @return */ int add(Brand brand);
-
在xml文件中添加sql语句
<!-- 增加对象--> <insert id="add" useGeneratedKeys="true" keyProperty="id"> insert into tb_brand (brand_name,company_name,ordered,description,status) values (#{brandName},#{companyName},#{ordered},#{description},#{status}) </insert>
useGeneratedKeys属性:是够获取自动增长的主键值。true表示获取
keyProperty属性:指定将获取到的主键值封装到哪儿个属性里
-
编写测试方法
@Test void testAdd(){ Brand brand = new Brand(); brand.setBrandName("魅族"); brand.setCompanyName("魅族科技有限公司"); brand.setStatus(1); brand.setOrdered(100); brand.setDescription("轻易不说完美"); int add = brandDao.add(brand); if(add > 0){ System.out.println("添加成功"); }else { System.out.println("添加失败"); } }
修改方法
-
在BandDao中编写方法
/** * 修改数据 * @param brand * @return */ int update(Brand brand);
-
在xml文件中添加sql语句
<update id="update"> update tb_brand <set> <if test="brandName != null and brandName != ''"> brand_name = #{brandName}, </if> <if test="companyName != null and companyName != ''"> company_name = #{companyName}, </if> <if test="ordered != null"> ordered = #{ordered}, </if> <if test="description != null and description != ''"> description = #{description}, </if> <if test="status != null and status != ''"> status = #{status} </if> </set> where id = #{id}; </update>
这里使用
set
标签代替了set关键字,该标签可以用于动态包含需要更新的列,忽略其它不更新的列。使用if
标签来判断哪些字段需要被修改,这里要注意不要忽略了if
标签内sql的最后一个逗号。 -
编写测试方法
@Test void testUpdate(){ Brand brand = new Brand(); brand.setBrandName("魅蓝"); brand.setDescription("年轻,无所畏惧"); brand.setId(5); int update = brandDao.update(brand); if(update > 0){ System.out.println("修改成功"); }else { System.out.println("修改失败"); } }
删除方法
-
单个数据删除
在BandDao中编写方法/** * 根据id删除数据 * @param id * @return */ int deleteById(int id);
在xml文件中添加sql语句
<delete id="deleteById"> delete from tb_brand where id = #{id}; </delete>
编写测试方法
@Test void testDeleteById(){ int i = 5; int i1 = brandDao.deleteById(i); if(i1 > 0){ System.out.println("删除成功"); }else { System.out.println("删除失败"); } }
-
批量删除
在BandDao中编写方法
/** * 批量删除 * @param ids * @return */ int deleteAll(int[] ids);
在xml文件中添加sql语句
<delete id="deleteAll"> delete from tb_brand where id in <foreach collection="array" item = "id" separator="," open="(" close=")"> #{id} </foreach> ; </delete>
这里使用
foreach
标签来循环遍历数组collection属性:
mybatis会将数组参数,封装为一个Map集合。
- 默认:array = 数组
- 可以使用@Param注解改变map集合的默认key的名称
item属性:本次迭代获取到的元素。
separator属性:集合项迭代之间的分隔符。
foreach
标签不会错误地添加多余的分隔符。也就是最后一次迭代不会加分隔符。open属性:该属性值是在拼接SQL语句之前拼接的语句,只会拼接一
close属性:该属性值是在拼接SQL语句拼接后拼接的语句,只会拼接一次
假如数组中的id数据是{1,2,3},那么拼接后的sql语句就是:
delete from tb_brand where id in (1,2,3);
编写测试方法:
@Test void testDeleteAll(){ int[] arr = {1,2,3}; int i = brandDao.deleteAll(arr); System.out.println(i); } }