核心配置文件
MyBatis核心配置文件的顶层结构如下:
<environments> 元素
<typeAliases>元素
作用:
配置文件完成增删改查
准备环境
创建数据库表tb_brand
-- 删除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);
执行查询语句
实体类Brand
package com.mybatisDemo.pojo;
/**
* @author hyk~
*/
public class Brand {
//id 主键
private Integer id;
//品牌名称
private String brandName;
//企业名称
private String companyName;
//描述信息
private String description;
//状态: 0:禁用 1:启用
private Integer status;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrandName() {
return brandName;
}
public void setBrandName(String brandName) {
this.brandName = brandName;
}
public String getCompanyName() {
return companyName;
}
public void setCompanyName(String companyName) {
this.companyName = companyName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", description='" + description + '\'' +
", status=" + status +
'}';
}
}
测试用例
安装MyBatisX插件
MybatisX是一款基于IDEA的快速开发插件,为效率而生
主要功能
XML和接口方法相互跳转
根据接口方法生成statement
安装完成后:自动创建
查询
(1)定义接口方法
(2)编写SQL映射文件
(3)执行测试方法
1.查询所有数据
运行结果出现异常,brandName和companyName查询为空值
原因:数据库表的字段名称 和 实体类的属性名称 不一样,则不能自动封装数据
解决方案1:
起别名:对不一样的列名起别名,让别名和实体类的属性名一样
*缺点:每次查询都要定义一次别名
解决方案2:
缺点:不灵活
解决方案3:
总结
实体类属性名和数据库表列名不一致,不能自动封装数据
1)起别名:在SQL语句中,对不一样的列名起别名,别名和实体类属性名一样
*可以定义<sql>片段,提升复用性
2) resultMap:定义<resultMap>完成不一致的属性名和列名的映射
2.查看详情
定义接口方法
编写SQL映射文件
参数占位符:
1. #{}:会将其替换为 ?,为了防止SQL注入
2. ${}: 拼接sql。会存在SQL注入问题
3. 使用时机:
参数传递的时候: #{}
表名或者列名不固定的情况下: ${}
参数类型:parameterType 可以省略
特殊字符处理:
1.转义字符 例如:< 转义字符为 <
2.CDATA区
编写测试方法
@Test
public void testSelectById() throws IOException {
//接收id参数
int id = 1;
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
Brand brand = brandMapper.selectById(id);
//打印
System.out.println(brand);
//释放资源
sqlSession.close();
}
运行
3.条件查询
多条件查询
参数接收
1.散装参数
如果方法中有多个参数,需要使用@Param("SQL参数占位符名称”)
定义接口方法
编写SQL映射文件
执行测试方法
@Test
public void testSelectTerm() throws IOException {
//接收多条件查询参数
int status = 1;
String brandName ="米";
String companyName = "科技";
//数据处理
brandName = "%" + brandName+ "%";
companyName = "%" + companyName+ "%";
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
List<Brand> brands = brandMapper.selectTerm(status, brandName, companyName);
//打印
System.out.println(brands);
//释放资源
sqlSession.close();
}
运行结果
2.对象参数
定义接口方法
SQL映射文件无需变更
测试方法
其它代码无需更改,只需封装对象
并修改传参
运行未报错则成功
3.map集合参数
定义接口方法
SQL映射文件无需变更
测试方法
创建Map集合
修改传参
运行未报错则成功
总结
(1)散装参数: 需要使用@Param(“SQL中的参数占位符名称”)
(2)实体类封装参数:只需要保证sQL中的参数名和实体类属性名对应上,即可设置成功
(3)map集合:只需要保证SQL中的参数名和map集合的键的名称对应上,即可设置成功
4.多条件-动态条件查询
只需更改SQL映射文件
动态条件查询
if:条件判断
test:逻辑表达式
问题:
如果第一个条件为空,则会出现语法错误 :select * from tb_brand where and .... (第一个条件不需要逻辑运算符)
解决方案:
恒等式:where 1 = 1 没有特殊含义 只是为了语法正确
<where>标签 替换 where 关键字
5.单条件-动态条件查询
从多个条件中选择一个
choose(when,otherwise): 选择,类似于Java 中的 switch 语句
定义接口方法
编写SQL映射文件
编写测试文件
@Test
public void selectTermSingle() throws IOException {
//接收多条件查询参数
int status = 1;
String brandName ="米";
String companyName = "";
//数据处理
brandName = "%" + brandName+ "%";
companyName = "%" + companyName+ "%";
//封装对象
Brand brand = new Brand();
// brand.setStatus(status);
// brand.setBrandName(brandName);
// brand.setCompanyName(companyName);
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
SqlSession sqlSession = sqlSessionFactory.openSession();
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
// List<Brand> brands = brandMapper.selectTerm(brand);
List<Brand> brands = brandMapper.selectTermSingle(brand);
//打印
System.out.println(brands);
//释放资源
sqlSession.close();
}
可取消注释尝试各个方案
运行
添加
编写接口方法
编写SQL映射文件
测试方法
@Test
public void addData() throws IOException {
//接收参数
String brandName ="vivo";
String companyName = "维沃通信有限公司";
int ordered = 1000;
String description = "点燃生活激情,vivo与你共创无限可能";
int status = 0;
//封装对象
Brand brand1 = new Brand();
brand1.setBrandName(brandName);
brand1.setCompanyName(companyName);
brand1.setOrdered(ordered);
brand1.setDescription(description);
brand1.setStatus(status);
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
//填入 true 表示自动提交事务
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
boolean b = brandMapper.addData(brand1);
//打印
if (b == true)
System.out.println("数据添加成功");
if (b == false)
System.out.println("数据添加失败");
//手动提交事务 否则数据添加成功但无法查询到 数据库回滚
//sqlSession.commit();
//释放资源
sqlSession.close();
}
开启自动提交事务才能正常添加且查询到数据
手动提交也可以
运行结果为数据添加成功
点开数据库执行查询语句发现已经有该条数据了
MyBatis事务
openSession():默认开启事务,进行增删改操作后需要使用
sqlSession.commit();手动提交事务
openSession(true): 可以设置为自动提交事务(关闭事务)
1.添加-主键返回
在数据添加成功后,需要获取插入数据库数据的主键的值
比如:添加订单和订单项
1.添加订单
2.添加订单项,订单项中需要设置所属订单的id
返回添加数据的主键
<insert useGeneratedKeys="true" keyProperty="id">
编写测试代码
运行
修改
1.修改全部字段
定义接口方法
编写SQL映射文件
执行测试方法
@Test
public void updateData() throws IOException {
//接收参数
int id = 1;
String brandName ="HONOR";
String companyName = "荣耀手机有限公司";
int ordered = 500;
String description = "荣耀之路,始于创新,终于卓越。";
int status = 1;
//封装对象
Brand brand1 = new Brand();
brand1.setId(id);
brand1.setBrandName(brandName);
brand1.setCompanyName(companyName);
brand1.setOrdered(ordered);
brand1.setDescription(description);
brand1.setStatus(status);
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
int i = brandMapper.updateData(brand1);
//打印
if (i != 0)
System.out.println("数据修改成功,影响的行数为"+i+"行");
if (i == 0)
System.out.println("数据修改失败");
//手动提交事务 否则数据添加成功但无法查询到 数据库回滚
//sqlSession.commit();
//释放资源
sqlSession.close();
}
将原先id为1的数据三只松鼠改成HONOR的数据
运行代码
显示数据修改成功并且影响行数为1行
查看数据库表显示已经修改完成了
2.修改动态字段
定义接口方法
编写SQL映射文件
执行测试方法
//修改动态数据
@Test
public void updateTrendsData() throws IOException {
//接收参数
int id = 1;
String brandName ="HONOR-HUAWEI";
String companyName = "华为荣耀手机有限公司";
int ordered = 500;
String description = "荣耀之路,始于创新,终于卓越。";
int status = 1;
//封装对象
Brand brand1 = new Brand();
brand1.setId(id);
brand1.setBrandName(brandName);
brand1.setCompanyName(companyName);
brand1.setOrdered(ordered);
brand1.setDescription(description);
brand1.setStatus(status);
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
int i = brandMapper.updateTrendsData(brand1);
//打印
if (i != 0)
System.out.println("数据修改成功,影响的行数为"+i+"行");
if (i == 0)
System.out.println("数据修改失败");
//手动提交事务 否则数据添加成功但无法查询到 数据库回滚
//sqlSession.commit();
//释放资源
sqlSession.close();
}
主要是这一段代码
运行代码
由此可见已实现动态修改数据了
删除
1.删除一个
定义接口方法 根据id删除数据
编写SQL映射文件
执行测试方法
//删除一条数据
@Test
public void deleteData() throws IOException {
//接收参数
int id = 5;
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
boolean b = brandMapper.deleteData(id);
//打印
if (b == true)
System.out.println("数据删除成功");
if (b == false)
System.out.println("数据删除失败");
//手动提交事务 否则数据添加成功但无法查询到 数据库回滚
//sqlSession.commit();
//释放资源
sqlSession.close();
}
删除id为5的数据
执行代码
提示数据删除成功,再次查看数据表
数据表中已无id为5的数据 表示删除成功了
2.批量删除
定义接口方法
编写SQL映射文件
MyBatis会将数组参数,封装成一个Map结合
*默认: array = 数组 collection="array"
*也可以使用 @Param("ids")注解改变Map集合的默认key的名称 collection="ids"
利用循环遍历ids数组中的数据 有几个id数据就会生成几个#{id}
separator="," 分隔符
open="(" 开始的拼接
close=");" 结束时的拼接
查看数据表中数据
执行测试方法
//批量删除数据
@Test
public void deleteDataByIds() throws IOException {
//接收数组参数
int [] ids = {4,5,6};
//1.获取SqlSessionFactory
String resource = "mybatis-config.xml"; //核心配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2.获取SqlSession对象,执行SQL语句
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//获取BrandMapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
boolean b = brandMapper.deleteDataByIds(ids);
//打印
if (b == true)
System.out.println("数据删除成功");
if (b == false)
System.out.println("数据删除失败");
//手动提交事务 否则数据添加成功但无法查询到 数据库回滚
//sqlSession.commit();
//释放资源
sqlSession.close();
}
删除数组中包含的id数据
运行
查看数据表已经没有id为4,5,6的数据了
MyBatis参数传递
MyBatis 接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式
单个参数
1.POJO类型 直接使用,属性名 和 参数占位符 名称 一致
2.Map集合 直接使用,键名 和 参数占位符 名称 一致
3.Collection 封装为Map集合 可以使用@Param注解,替换Map集合中默认的arg键名
map.put("arg0",collection集合);
map.put("collection",collection集合);
4.List 封装为Map集合 可以使用@Param注解,替换Map集合中默认的arg键名
map.put("arg0",list集合);
map.put("collection",List集合);
map.put("List",List集合);
5.Array 封装为Map集合 可以使用@Param注解,替换Map集合中默认的arg键名
map.put("arg0",数组);
map.put("array”,数组);
6.其他类型 直接使用
7.多个参数:
封装为Map集合 可以使用@Param注解,替换Map集合中默认的arg键名
map.put("arg0",参数值1)
map.put("param1",参数值1)
map.put("param2",参数值2)
map.put("arg1",参数值2)
-------------@Param("username")
map.put("username",参数值1)
map.put("param1",参数值1)
map.put("param2",参数值2)
map.put("arg1",参数值2)
MyBatis提供了 ParamNameResolver 类来进行参数封装
结论: 将来都使用@Param注解来修改Map集合中默认的键名
并使用修改后的名称来获取值,这样可读性更高
定义接口方法
编写SQL映射文件
执行 运行成功
注解开发
使用注解开发会比配置文件开发更加方便
格式:
@Select("select * from tb_user where id = #{id}")
User selectById(int id);
查询: @Select
添加: @Insert
修改: @Update
删除: @Delete
代码演示
定义接口方法并编写注解SQL语句
运行测试代码
总结:
注解完成简单功能
配置文件完成复杂功能