JAVA WEB MyBatis 视频学习笔记
- MyBatis案例
- 1 环境准备
- 2 编写接口
- 3 MyBatis参数传递
MyBatis案例
1 环境准备
1.1 数据库准备
DROP TABLE IF EXISTS tb_brand;
CREATE TABLE tb_brand(
id INT PRIMARY KEY AUTO_INCREMENT,
brand_name VARCHAR(20),
company_name VARCHAR(20),
ordered INT,
description VARCHAR(100),
status INT
);
INSERT INTO tb_brand(brand_name, company_name, ordered, description, status)
VALUES
('Huawei', 'huawei company', 10, 'phone compnany', 0),
('MI', 'XIAOMI company', 20, 'LOW phone compnany', 1),
('APPLE', 'APPLE company', 40, 'BIG phone compnany', 1);
SELECT * FROM tb_brand;
1.2 准备一个Brand实体类
package com.feifei.pojo;
public class Brand {
private Integer id;
private String brandName;
private String companyName;
private Integer ordered;
private Integer description;
private Integer status;
public Brand(Integer id, String brandName, String companyName, Integer ordered, Integer description, Integer status) {
this.id = id;
this.brandName = brandName;
this.companyName = companyName;
this.ordered = ordered;
this.description = description;
this.status = status;
}
@Override
public String toString() {
return "Brand{" +
"id=" + id +
", brandName='" + brandName + '\'' +
", companyName='" + companyName + '\'' +
", ordered=" + ordered +
", description=" + description +
", status=" + 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 Integer getOrdered() {
return ordered;
}
public void setOrdered(Integer ordered) {
this.ordered = ordered;
}
public Integer getDescription() {
return description;
}
public void setDescription(Integer description) {
this.description = description;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
1.3 准备测试用例
在test.java下创建com.XXXX.test.MyBatisTest.java
1.4 安装MyBatisX插件
基于IDEA的快速开发插件,为效率而生
主要功能:
XML和接口方法相互跳转
根据接口方法生成statement
会出现小蓝鸟和小红鸟在侧边栏,实现自动跳转
2 编写接口
编写接口的固定套路:
- 编写接口方法: Mapper接口
- 参数
- 返回结果
- 编写SQL语句: SQL映射文件
- 执行方法,进行测试
2.1 编写查询所有
2.1.1 编写Mapper接口
public interface BrandMapper {
/*
* 查询所有
* */
List<Brand> selectAll();
}
2.1.2 编写SQL映射文件
使用插件自动生成,完善SQL语句,将resultType修改成为别名
<select id="selectAll" resultType=brand">
select*
from tb_brand;
</select>
2.1.3 编写测试语句完成测试
@Test
public void testSelectAll() throws IOException {
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2.获取SqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3.获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4.执行对象
List<Brand> brands = mapper.selectAll();
System.out.println(brands);
// 5.释放资源
sqlSession.close();
}
2.1.4 BugFix
查询结果部分属性值出现null的情况:原因在于数据库中的命名与Java对象属性命名不一致一个采用下划线分割,一个采用驼峰机制,如company_name VS companyName;
(PS: 我发现如果事先编写Constructor后可以自动完成对象构造,不会出现Null的情况)
解决方案:
使用resultMap进行解决
<!--
namespace:名称空间
-->
<mapper namespace="com.feifei.mapper.BrandMapper">
<!-- statement-->
<!--
id : 唯一表述
type: 映射的类型,支持别名
-->
<!--
resultMap:
1. 定义<resultMap>标签
2. 在<select>标签中,使用resultMap属性替换 resultType属性
-->
<resultMap id="brandResultMap" type="brand">
<!--
column: 数据库列名
property: 实体类属性名
-->
<result column="company_name" property="companyName"/>
<result column="brand_name" property="brandName"/>
</resultMap>
<!-- <select id="selectAll" resultType=brand">-->
<!-- select*-->
<!-- from tb_brand;-->
<!-- </select>-->
<select id="selectAll" resultMap="brandResultMap">
select *
from tb_brand;
</select>
</mapper>
2.2 查看详情
还是按照同样的步骤完成编写,编写前分析接口方法的参数与返回类型如下:(因为是查看商品详情,肯定是按照id进行查询,返回结果肯定是保存在对象中)
- 编写接口方法: Mapper接口
- 参数 : id
- 返回结果 : Brand
- 编写SQL语句: SQL映射文件
- 执行方法,进行测试
2.2.1 编写Mapper接口
User selectById(int id);
2.2.2 生成statement
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand
where id = #{id};
</select>
2.2.3 测试方法
@Test
public void selectById() 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
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
Brand brand = mapper.selectById(id);
System.out.println(brand);
// 5.释放资源
sqlSession.close();
}
2.2.4 传参注意点
在BrandMapper.xml中传参,参数占位符有两种可选
#{}: 会将其替换为? 为了防止sql注入问题
${}: 直接拼接sql,会存在sql注入问题
// 使用时机:参数传递都使用#{}, 而表名或者列名不固定的情况下使用¥{}
// 在映射时,可以指定传参类型 parameterType: int, 一般可以省略
// 特殊字符处理:如<,直接写不符合xml语法,需要使用转义字符,或者使用CDATA区
2.3 条件查询
条件查询有三种查询方式:(对应三种传参方式)
- 散装变量查询
- 对象查询
- map对象查询
2.3.1 编写Mapper接口
/*
* 条件查询
* 参数接收
* 1. 散装参数: 如果方法中有多个参数,需要使用@Param("SQL参数占位符") 需要保持一致
* 2. 对象参数: 对象属性名称要和参数占位符名称一致
* 3. map集合参数
*
* */
// List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
// List<Brand> selectByCondition(Brand brand);
List<Brand> selectByCondition(Map map);
2.3.2 生成对应statement
<!-- Condidtion Search-->
<select id="selectByCondition" resultMap="brandResultMap">
select*
from tb_brand
where status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName}
</select>
2.3.3 编写sql测试
@Test
public void selectByCondition() throws IOException {
// 接收参数
int status = 0;
String companyName = "huawei company";
String brandName = "Huawei";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
// 对象参数处理方法
// Brand brand = new Brand();
// brand.setStatus(status);
// brand.setBrandName(brandName);
// brand.setCompanyName(companyName);
Map map = new HashMap();
map.put("status",status);
map.put("companyName", companyName);
map.put("brandName", brandName);
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
// 散装参数处理
// List<Brand> brand = mapper.selectByCondition(status, companyName, brandName);
// 对象参数查询
List<Brand> brands = mapper.selectByCondition(map);
// map对象参数查询
System.out.println(brands);
// 5.释放资源
sqlSession.close();
}
2.3.4一些注意点
实际用户使用中,肯定不可能每次都选择三个条件,所以以上查询方式还并不完善,需要进行动态查询设计
2.4 动态查询条件
MyBatis提供了强大的动态SQL语句, 其中
使用if,判断参数是否有值,使用test属性进行条件判断;
使用where标签能够根据条件自动添加and或者省略and。
2.4.1 多条件 动态条件查询
只要重新编写statement,其他两个条件查询步骤保持不变
<!-- 动态 Condition Search
* if: 条件判断
* 问题:
* 恒等式 1=1
* <where> 替换 where关键字
-->
<select id="selectByCondition" resultMap="brandResultMap">
select*
from tb_brand
<where>
<if test="status != null">
and status = #{status}
</if>
<if test="companyName != null and companyName != '' ">
and company_name like #{companyName}
</if>
<if test="brandName != null and brandName != '' ">
and brand_name like #{brandName}
</if>
</where>
</select>
2.4.2 单条件 动态条件查询
具体改动任然是聚焦于statement的修改,同样需要首先编写Mapper接口
List<Brand> selectByConditionSingle(Map map);
编写statement
这里使用choose标签实现单条件动态查询,类似switch语句,使用otherwise预防用户什么都不查询的情况。
<select id="selectByConditionSingle" resultMap="brandResultMap">
select*
from tb_brand
where
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="companyName != null and companyName != ''">
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
<otherwise>
1=1
</otherwise>
</choose>
</select>
当然也可以使用where标签,自动修改语句,进而不使用otherwise标签。
<select id="selectByConditionSingle" resultMap="brandResultMap">
select*
from tb_brand
<where>
<choose>
<when test="status != null">
status = #{status}
</when>
<when test="companyName != null and companyName != ''">
company_name like #{companyName}
</when>
<when test="brandName != null and brandName != '' ">
brand_name like #{brandName}
</when>
</choose>
</where>
</select>
2.5 添加
- 编写接口方法: Mapper接口
- 参数: 除了id以外的所有数据
- 返回结果: void
- 编写SQL语句: SQL映射文件
- 执行方法,进行测试
以下介绍两种方法,一种是传入所有参数,另一种是传入Brand brand对象
2.5.1 mapper接口
这里注意,如果是接口传入多个参数,必须要添加注解@Param
所有java在运行的时候会把例如add(int ordered, int status);中的参数变成这样:add(int arg0,int arg1),这样我们就没有办法去传递多个参数。所以需要使用@Param注解给方法参数命名。
/*
* 添加
* */
void add(@Param("brandName") String brandName,
@Param("companyName") String companyName,
@Param("ordered") int ordered,
@Param("description") String description,
@Param("status") int status);
传入brand对象写法
void add(Brand brand);
2.5.2 sql映射文件
<insert id="add">
insert into tb_brand(brand_name, company_name, ordered, description, status)
VALUES (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status})
</insert>
2.5.3 test add
@Test
public void add() throws IOException {
// 传入参数
String companyName = "OracleCompany";
String brandName = "Oracle";
Integer ordered = 20;
String description = "Oracle is a database company";
Integer status = 0;
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
mapper.add(brandName, companyName, ordered, description, status);
// 4.1 提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
传入brand对象写法
@Test
public void add() throws IOException {
// 传入参数
String companyName = "OracleCompany";
String brandName = "Oracle";
Integer ordered = 20;
String description = "Oracle is a database company";
Integer status = 0;
Brand brand = new Brand();
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
mapper.add(brand);
// 4.1 提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
在关闭sqlSession前,还需要完成事务sqlSession.commit(),因为默认是不开启自动完成事务
可以设置openSession(false)来设置不开启事务。
2.5.4 返回插入数据库的主键值
需要在sql xml文件中insert中添加两个属性值
- useGeneratedKeys默认为false
- 将generatedKey指向brand属性,即keyProperty=id
<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>
2.5.5 为什么传入对象也能与sql xml字段进行匹配
只要保证Brand对象属性名称与sql xml字段中的参数占位符保持一致,那么MyBatis就会给你匹配上对应的参数。
2.6 修改全部字段
- 编写接口方法: Mapper接口
- 参数: 所有数据 brand对象
- 返回结果: void
- 编写SQL语句: SQL映射文件
- 执行方法,进行测试
2.6.1 mapper接口
/*
* 修改
* */
int update(Brand brand);
2.6.2 sql语句
<update id="update">
update tb_brand
set brand_name = #{brandName},
company_name = #{companyName},
ordered = #{ordered},
description = #{description},
status = #{status}
where id = #{id};
</update>
2.6.3 testUpdate
@Test
public void testUpdate() throws IOException {
// 传入参数
String companyName = "OracleCompanyHHH";
String brandName = "OracleHHH";
Integer ordered = 210;
String description = "Oracle is a database companyHHHH";
Integer status = 1;
int id = 6;
Brand brand = new Brand();
brand.setBrandName(brandName);
brand.setCompanyName(companyName);
brand.setOrdered(ordered);
brand.setDescription(description);
brand.setStatus(status);
brand.setId(id);
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
int count = mapper.update(brand);
System.out.println(count);
// 4.1 提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
2.7 修改部分字段
2.7.1 mapper接口保持不变
int update(Brand brand);
2.7.2 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">
status = #{status}
</if>
</set>
where id = #{id};
</update>
2.7.3 test
注释掉部分set语句,测试动态修改是否成功
@Test
public void testUpdate() throws IOException {
// 传入参数
// String companyName = "OracleCompanyHHH";
// String brandName = "OracleHHH";
Integer ordered = 210;
// String description = "Oracle is a database companyHHHH";
Integer status = 1;
int id = 3;
Brand brand = new Brand();
// brand.setBrandName(brandName);
// brand.setCompanyName(companyName);
brand.setOrdered(ordered);
// brand.setDescription(description);
// brand.setStatus(status);
brand.setId(id);
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
int count = mapper.update(brand);
System.out.println(count);
// 4.1 提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
2.8 删除一个
- 编写接口方法: Mapper接口
- 参数: id
- 返回结果: void
- 编写SQL语句: SQL映射文件
- 执行方法,进行测试
2.8.1
void deleteById(int id);
2.8.2
<delete id="deleteById">
delete from tb_brand
where id = #{id}
</delete>
2.8.3
@Test
public void testDeleteById() throws IOException {
// 传入参数
int id = 2;
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
mapper.deleteById(id);
// 4.1 提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
2.9 批量删除
2.9.1 mapper接口
/*
* 批量删除
* */
void deleteByIds(@Param("ids") int[] ids);
2.9.2 sql
使用open close设置sql语句中的左括号右括号
<!--
mybatis会默认将数组封装一个Map集合
默认:array = 数组
使用@Param注解改变map集合的默认key的名称
-->
<delete id="deleteByIds">
delete from tb_brand
where id
in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
2.9.3 test
@Test
public void testDeleteByIds() throws IOException {
// 传入参数
int[] ids = {5,7,8};
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
BrandMapper mapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行对象
mapper.deleteByIds(ids);
// 4.1 提交事务
sqlSession.commit();
// 5.释放资源
sqlSession.close();
}
3 MyBatis参数传递
3.1 参数传递分析
MyBatis提供了ParamNameResolver类来进行参数封装,感兴趣可以在里面敲断点调试。
双击shift即可查找
ParamNameResolver.getNamedParams()
这边使用tb_user的案例来做解释,下面是添加注解@Param时的情况
3.1.1 Mapper接口
User select(@Param("username") String username, @Param("password") String password);
3.1.2 Sql
<select id="select" resultType="user">
select *
from tb_user
where username = #{username}
and password = #{password}
</select>
3.1.3 test
@Test
public void testSelectUser() throws IOException{
// 传入参数
String username = "ZS";
String password = "123";
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4. 执行对象
User user = mapper.select(username, password);
System.out.println(user);
// 5. 释放资源
sqlSession.close();
}
以下是添加注解,查询成功的结果
3.1.4 不添加注解
在mapper接口中删除@Param注解,报错情况
通过源码分析,MyBatis底层会首先封装传入参数, 将参数封装进Map集合
map.put("arg0“, 参数1)
map.put("param1”, 参数1)
map.put("arg1“, 参数2)
map.put("param2”, 参数2)
当使用@Param注解,会替换Map集合中默认的arg键名,下面展示将username添加注解的情况:
显而易见,arg0被替换为username,而password由于未添加注解,所以无法被匹配。
3.2 传入参数总结
偷懒直接将JavaWeb黑马的笔记复制在下面。
不要使用默认的map集合的键名进行传参,全部使用@Param注解,来提升代码阅读流畅性!
3.3注解开发
使用注解开发会比配置文件开发更加方便。
但是对于稍微复杂的语句,Java注解会显得力不从心,还会让你本来的SQL语句更加混乱不堪。因此,如果需要一些复杂操作,最好使用XML来映射语句。
下面展示一个注解开发案例
3.3.1 mapper接口
@Select("select * from tb_user where id = #{id}")
User selectById(int id);
3.3.2 test
@Test
public void testSelectByUserId() throws IOException{
// 传入参数
int id = 1;
// 1. 获取SqlSessionFactory
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 2. 获取SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 3. 获取Mapper接口代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 4. 执行对象
User user = mapper.selectById(1);
System.out.println(user);
// 5. 释放资源
sqlSession.close();
}
标签:status,JavaWeb,companyName,brand,案例,sqlSession,MyBatis,id,String
From: https://blog.csdn.net/BruceFei1/article/details/140571055