在说动态SQL语句之前,先提两个小知识点
1. mybatis连接池的配置
主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是表示采用何种连接池方式。我们之前用的一直是池的思想
<dataSource type="POOLED">
type属性的取值:
- POOLED 采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现
- UNPOOLED 采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
2. 自动提交
查找不需要提交事务,但增删改必须提交事务,否则对原数据没有影响。当然,如果我们不想手动提交事务,可以在创建SqlSession对象时传入true,表示自动提交事务。
SqlSession session = factory.openSession(true);
多说一句,虽然自动提交很方便,但我们更多采用手动提交。举个简单例子,实现一个甲给乙转账的功能,若先转钱,然后提交了,这时遇到了一个bug,程序中断。最终结果是甲的钱少了,但是乙的钱并没有变多,这是有问题的。当我们手动提交时,中间遇到bug,可以设置事务回滚。这样即便中间遇到问题,甲的钱也不会变少了。
聊聊今天学习的内容,mybatis的动态SQL语句。 试想一个模糊查询功能,根据输入的姓名,住址信息,将所有满足要求的用户搜索出来。这里,有四种情况:什么都不输入,只输入一个,两个都输入。为了解决这种情况,动态SQL语句就能用上了。
1.if标签
在IUserDao中新增一个功能
//动态查询,根据用户名和地址查询
List<User> findByUser(User user);
然后在IUserDao.xml中写主要SQL语句,如下:
<select id="findByUser" resultType="user" parameterType="user">
select * from user where 1=1
<if test="username != null and username != ''">
and username like #{username}
</if>
<if test="address != null and address != ''">
and address like #{address}
</if>
</select>
这里实现的功能,主要是根据输入的姓名、住址信息进行模糊查询。在第一行写一个“1=1”,可以方便后面写and,将SQL语句连接起来。test属性中写的是对象的属性名。测试文件略。
2. where标签
就是单纯用if标签来拼接条件,我们在写条件的时候,得把 where 1=1 写上,麻烦。那能不能 不写where 和 1=1 呢?
可以,那就得使用一个标签叫where标签。
在IUserDao中新增一个功能
//动态查询,这里不写1=1
List<User> findByAddressAndSex(User user);
然后在IUserDao.xml中写主要SQL语句,如下:
<select id="findByAddressAndSex" parameterType="user" resultType="user">
select * from user
<where>
<if test="address!=null and address!=''">
and address like#{address}
</if>
<if test="sex!=null and sex!=''">
and sex like #{sex}
</if>
</where>
</select>
正常测试是没有问题的,这里展示一下,如果什么也不输入,测试的结果
@Test
public void testFindByAddressAndSex(){
User user = new User();
List<User> users = dao.findByAddressAndSex(user);
for (User u : users) {
System.out.println(u);
}
}
测试结果如上图所示,并不会因为没有输入用户名和地址而报错。
3. foreach标签
看一下这条语句,
SELECT * FROM USERS WHERE username LIKE '%张%' AND id IN (10,29,16) ;
这是一个简单的范围查询语句,但有时候,“in”中的值不能写死,而要作为参数动态添加进来。这样我们如何进行参数传递呢?
新建一个实体类,起名QueryVO,添加两个属性,一个是User对象,一个是集合ids,用来模拟要导入的id参数。如下:
public class QueryVO implements Serializable {
User user;
List<Integer> ids;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
}
然后在IUserDao中新增一个功能
//动态查询,传入多个id
List<User> findByIds(QueryVO vo);
最后在IUserDao.xml中写主要sql语句
<select id="findByIds" parameterType="QueryVO" resultType="user">
select * from user
<where>
<if test="user.username!=null and user.username!=''">
and username like #{user.username}
</if>
<foreach collection="ids" open="and id in(" close=")" item="uid" separator=",">
#{uid}
</foreach>
</where>
</select>
解释一下foreach中几个属性的含义
- collection:代表要遍历的集合元素,注意编写时不要写#{}
- open:代表语句的开始部分
- close:代表结束部分
- item:当前遍历的集合中的元素
- separator:分隔符
- 最后,此sql写完整是这样的:
SELECT * FROM USER WHERE username like #{user.username} and id IN(1,2,3,4,5,28,30);
最后括号中的数据,是根据测试文件而写的。
@Test
public void testFindByIds(){
User user = new User();
user.setUsername("%张%");
List<Integer> ids= Arrays.asList(1,2,3,4,5,28,30);
QueryVO vo = new QueryVO();
vo.setUser(user);
vo.setIds(ids);
List<User> list = dao.findByIds(vo);
for (User u : list) {
System.out.println(u);
}
}
测试结果如下: