MyBatis实现查询的操作
这里引入了Idea插件 MyBatisX ,方便进行跳转生成操作
查询所有数据
接口
映射文件
测试案例
]
这里查询结果有一个问题。
brandName金额companyName查询出来的结果为NUll。原因是实体类里属性命名为驼峰,数据库里是下划线。
解决方法为:
起别名(对不一样的列名起别名,让别名和实体类的属性名一样
<!-- 起别名--> <select id="selectAll" resultType="org.example.pojo.Brand"> select id, brand_name as brandName, company_name as companyName, ordered, description, status from tb_brand </select>
sql片段(定义一个片段,每次查询都引用这个片段)
<!-- sql片段--> <sql id="brand_colume"> id, brand_name as brandName, company_name as companyName, ordered, description, status </sql> <select id="selectAll" resultType="org.example.pojo.Brand"> select <include refid="brand_colume"/> from tb_brand </select>
ResultMap
<resultMap id="brandResultMap" type="org.example.pojo.Brand"> <result column="brand_name" property="brandName"/> <result column="company_name" property="companyName"/> </resultMap> <select id="selectAll" resultMap="brandResultMap"> select * from tb_brand </select>
查询某一个的详情
整体流程与上面的一样
接口
/**
* 通过id查询详情
*/
public Brand selectById(int id);
SQL映射
<select id="selectById" resultMap="brandResultMap">
select *
from tb_brand
where id = #{id}
</select>
test
]
注意
参数占位符
#{}:会将其替换为?,为了防止SQL注入
${}:拼sql。会存在SQL注入的问题
使用时机:
- 参数传递的时候:#{}
- 表名后者列名不固定的情况下:${} 会存在SQL注入问题
特殊字符
转义字符
CDATA区
<![CDATA[ ]]>
条件查询
为了方便演示接口接收参数的格式,先去书写SQL映射
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where status = #{status}
and company_name like #{companyName}
and brand_name like #{brandName}
</select>
条件查询
参数接收
- 散装参数:如果方法中有多个参数,需要使用@Param(“SQl参数占位符名称”)
- 对象参数
- map集合参数
方式一 散装参数
/**
* 条件查询 方式一
*/
List<Brand> selectByCondition(@Param("status") int status, @Param("companyName") String companyName, @Param("brandName") String brandName);
==注意:==这里的参数 @Param(“参数”),要和sql映射文件里的参数一致 #{参数}
测试
@Test
public void testSelectByCondition() throws IOException {
// 接收参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
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 brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行方法
List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);
System.out.println(brands);
// 5. 释放资源
sqlSession.close();
}
这里处理参数是为了模糊查询,所以在字符串前后都加上"%",进行模糊查询
]
方式二 对象参数
注意对象的属性名称要和参数占位符名称一致
只需要修改接口
接口
/**
* 条件查询 方式二
*/
List<Brand> selectByCondition(Brand brand);
测试
@Test
public void testSelectByCondition() throws IOException {
// 接收参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
// 封装对象
Brand brand=new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(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 brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行方法
List<Brand> brands = brandMapper.selectByCondition(brand);
System.out.println(brands);
// 5. 释放资源
sqlSession.close();
}
]
方式三 map集合参数
这里map键的名称要和sql映射文件里的参数一样
这里依然是只修改接口即可
接口
/**
* 条件查询 方式三
*/
List<Brand> selectByCondition(Map map);
测试
@Test
public void testSelectByCondition() throws IOException {
// 接收参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
// 封装对象
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 brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行方法
List<Brand> brands = brandMapper.selectByCondition(map);
System.out.println(brands);
// 5. 释放资源
sqlSession.close();
}
动态条件查询
SQL语句会随着用户的输入或外部条件的变化而变化,称为动态SQL
官方文档点击跳转
1 多条件动态查询
sql语句
这里先使用if标签,里面有一个test属性,test里写表达式
因为companyName和brandName是字符串类型,除了判断是空对象以外还要判断是否为空字符串
<!-- 动态条件查询-->
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand where
<if test="status != null">
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>
</select>
接口
/**
* 条件查询 方式三
*/
List<Brand> selectByCondition(Map map);
测试
这个测试案例只输入了status和companyName。
@Test
public void testSelectByCondition() throws IOException {
// 接收参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
// 封装对象
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 brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行方法
List<Brand> brands = brandMapper.selectByCondition(map);
System.out.println(brands);
// 5. 释放资源
sqlSession.close();
}
成功查询
但是这个方法存在一个bug
如果只查询companyName就会报错
因为它的sql语句就会变成 select * from tb_brand where and company_name like #{companyName}
这句SQL就多了一个and
解决办法
给if标签里的都加上and
然后在where后面使用一个恒等式 1=1
<select id="selectByCondition" resultMap="brandResultMap">
select *
from tb_brand
where 1 = 1
<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>
</select>
但是这样还是很麻烦,于是MyBatis提供了一个新的标签(使用较为普遍的方法)
使用标签就可以省略自己书写恒等式
<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>
2 单条件动态查询
接口
/**
* 单条件动态查询
*/
List<Brand> selectByConditionSingle(Brand brand);
sql映射
<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>
</select>
这里的choose相当于 Switch
when 相当于 case
测试
@Test
public void testSelectByConditionSingle() throws IOException {
// 接收参数
int status = 1;
String companyName = "华为";
String brandName = "华为";
// 处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
// 封装对象
Brand brand = new Brand();
brand.setStatus(status);
// brand.setCompanyName(companyName);
// brand.setBrandName(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 brandMapper = sqlSession.getMapper(BrandMapper.class);
// 4. 执行方法
List<Brand> brands = brandMapper.selectByConditionSingle(brand);
System.out.println(brands);
// 5. 释放资源
sqlSession.close();
}
]
这个查询还有一个bug,就是如果三个条件都是null就会报错
所以加上一个标签
里面使用恒等式1=1
<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>
还有一个方法,使用 标签 效果是一样的
<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>