MyBatis框架教程「模糊查询」

1年前 (2022) 程序员胖胖胖虎阿
273 0 0

MyBatis框架教程「模糊查询」

作者 | 王久一

编辑 | 王久一
导读:
 通过上三篇Mybatis教程文章的学习,我们已经基本掌握了环境的搭建,简单增删改查语句的编写,MyBatis工具类的使用以及单元测试组件的使用。可以移步查看:


1. MyBatis框架教程「入门起步」

2. MyBatis框架教程「实践与工具类封装」

3. MyBatis框架教程「工具类的使用」

但是面对复杂的业务逻辑这些简单的增删改查是远远不能胜任的,这篇介绍运用MyBatis进行模糊查询,学习where,set和trim标签的使用。

模糊查询

模糊查询是和精确查询对应的,恰恰相反,精确查询可以精确定位想要查询的信息。而模糊查询可以通过 like 关键字和通配符的配合实现匹配符合目标关键字的信息。比如:你想购买《Java核心编程》这本书,只需要在电商平台搜索引擎键入:核心编程 四个字,书名含这四个字的书籍信息都会罗列出来(当然这只是一个例子,可能还需要全文检索工具或者Elasticsearch来优化服务。)。

1. 新建Java项目:

MyBatis框架教程「模糊查询」

2. 导入Jar包:log4j,mybatis,mysql驱动

3. 数据库:

MyBatis框架教程「模糊查询」

4. mybatis-config.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE configuration
 PUBLIC "-//mybatis.org//DTDConfig 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-config.dtd">

 <configuration>
   <!-- 配置环境 -->
  <environments default="jujidi">
   <environment id="jujidi">
    <transactionManager type="JDBC"></transactionManager>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/dbname"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
      </dataSource>
    </environment>
 </environments>
 <!-- 加载映射文件 -->
 <mappers>
   <mapper resource="com/jujidi/test/TestMapper.xml" />
 </mappers>
</configuration>

这是Mybatis框架的核心配置文件,其中配置了相关环境和加载映射文件,环境中确定数据源,在数据源中配置你需要链接数据库的相关信息,比如用户名、密码。映射文件就是你编写SQL的xml,通过此核心配置文件进行加载关联。

5. User.java

public class User {
 private Integer userId;
 private String userName;
 private String account;
 private String pwd;
 private Integer status;
}

注:由于篇幅限制,我们对属性的getter,setter和tostring方法进行省略

6. UserDao.java

public interface UserDao {
   List<User> likes(User user);
   //void update(User user);
}

7. MyBatisUtil.java

public final class MybatisUtil {
private MybatisUtil(){}
private static final String PATH = "mybatis-config.xml";
private static InputStream is = null;
private static SqlSessionFactory sqlSessionFactory = null;
static{
 try{
   //加载核心配置文件
   is = Resources.getResourceAsStream(PATH);
   //创建sqlsession工厂 -->相当于connection
   sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
   }catch(IOException e){
    e.printStackTrace();
    throw new RuntimeException("加载映射文件失败可能是你的映射文件写错了原因:"+e.getMessage());
   }
  }
  //获取sqlsession -->相当于执行sql语句对象
  public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession();
   }
   public static void closeSqlSession(SqlSession sqlSession){
    if(sqlSession!=null){
      sqlSession.close();
    }
 }
}

上方是一个MyBatis的工具类,根据核心配置文件创建sqlsession工厂,每一个SQL操作都要创建sqlsession工厂,我们就把创建工厂和获取sqlsession的共同代码提前出来,封装成工具类,便于以后调用。

8. MyBatisTest.java

public class MybatisTest {
UserDao userDao = null;

@Before
public void init(){
 userDao = new UserDaoImpl();
}

@Test
public void likes(){
  User user = new User();
  user.setUserName("聚");
  List<User> userList = userDao.likes(user);
  System.out.println(userList);
}
}

上方是测试类,使用 @Before和 @Test注解之前必须导入JUnit的相关Jar包,关于JUnit的介绍我们已经在前面文章讲过,可以翻翻MyBatis教程系列查看。其中我们定义一个方法likes。试图查出数据用户表中user_name含有“聚”字的记录。

9. UserDaoImpl.java

public class UserDaoImpl implements UserDao {
private SqlSession sqlSession = null;
@Override
public List<User> likes(User user ) {
 try{
    sqlSession = MybatisUtil.getSqlSession();
    List<User> userList = sqlSession.selectList("com.jujidi.model.User.likes" , user);
     return userList;
   }catch(Exception e){
      e.printStackTrace();
      throw new RuntimeException("查询失败");
   }finally{
      MybatisUtil.closeSqlSession(sqlSession);
   }
  }
}

在上方类的likes方法中使用Mybatis工具类来生成对话,并执行Mapper中的SQL语句,调用UserMapper中的id为likes的对应SQL,在映射文件Mapper中进行模糊查询,符合条件(含有聚)的用户都会返回。

10. UserMapper.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

 <mapper namespace="com.jujidi.model.User">
 <sql id="jujidi">
 user_name userName,user_iduserId,account,password pwd,status
 </sql>

 <select id="likes" parameterType="com.jujidi.model.User"resultType="com.jujidi.model.User">
 select <include refid="jujidi"></include> from user
    where user_name like '%#{userName}%'
 </select>

</mapper>

通过上方搭建好的环境进行模糊查询,试图查出数据表中user_name含有“聚”字的记录。但是我们运行后是错误的!为什么呢?

记得上篇关于MyBatis教程我们说过,#{}会自动给里面的值加上单引号,所以上方错误语句中:'%#{userName}%' 真正查询时其实为:'%' 聚 '%',问题就出在了标红的单引号上面,解决方案有两种:

第一种方案(不建议):

UserMapper.xml:
<select id="likes" parameterType="com.jujidi.model.User"resultType="com.jujidi.model.User">

 select <include refid="jujidi"></include> from user
    where user_name like #{userName}
</select>


红色字体为更改的地方!

MyBatisTest.java:

@Test
public void likes()
{

  User user = new User();
  user.setUserName("%聚%");
  List<User> userList =userDao.likes(user);
  System.out.println(userList);

}

第二种方案:

此时我们把MyBatis.java文件中的 user.setUserName("%聚%")重新改为:user.setUserName("聚");

在<select>标签中使用concat函数规避错误。

UserMapper.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jujidi.model.User">

<sql id="jujidi">
 user_name userName,user_iduserId,account,password pwd,status
</sql>

<select id="likes" parameterType="com.jujidi.model.User"resultType="com.jujidi.model.User">
 select <include refid="jujidi"></include> from user
    where user_name like concat('%',#{userName},'%')
</select>

</mapper>

第三种方案:

相比原始的 like '%#{userName}%' 我们修改成了 '%${userName}%',由'#'变成了'$',也就是${}包括的值是不会自动加上单引号的。

UserMapper.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTDMapper3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jujidi.model.User">

<sql id="jujidi">
  user_nameuserName,user_iduserId,account,password pwd,status
</sql>

<!-- 模糊查询的第三种$ -->

<select id="likes2"parameterType="com.jujidi.model.User"resultType="com.jujidi.model.User">
 select <include refid="jujidi"></include> from user
  where user_name like '%${userName}%'
</select>

</mapper>

通过上方三个小小的案例,想必对模糊查询有个大体的了解了吧,接下来我们介绍关于动态模糊查询的知识。也就是说,我想通过userName查就用userName查,想通过account查就用account查,也可以一起查。Talk is cheap ,show you the code:

11. 动态模糊查询

where

if的test属性值如果为true,就会进行标签里的模糊查询,所以进行空判断就可以实现模糊查询:

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jujidi.model.User">

<sql id="jujidi">
 user_name userName,user_iduserId,account,password pwd,status
</sql>

<select id="likes" parameterType="com.jujidi.model.User"resultType="com.jujidi.model.User">
 select <include refid="jujidi"></include> from user
 <where>
  <if test="userName !=null and userName != ''">
    and user_name like concat('%',#{userName},'%')
  </if>
  <if test="account !=null and account != ''">
    and account like concat('%',#{account},'%')
  </if>
 </where>
</select>

</mapper>

上面的代码:有一个<if>成立了就会插入where的关键字。where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入"WHERE"子句(插入where关键字),而且若语句的开头为"AND"或"OR",where 元素也会将它们去除多余的"AND"或"OR"。

trim

 trim标签是比较灵活的标签,可以用来实现where:

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jujidi.model.User">

<sql id="jujidi">
 user_name userName,user_iduserId,account,password pwd,status
</sql>
<!-- trim实现where-->
<select id="likes3" parameterType="com.jujidi.model.User"resultType="com.jujidi.model.User">
 select <include refid="jujidi"></include> from user
  <trim prefix="where" prefixOverrides="and |or ">

   <if test="userName !=null and userName != ''">
     and user_name like concat('%',#{userName},'%')
   </if>
   <if test="account !=null and account != ''">
     and account like concat('%',#{account},'%')
   </if>

  </trim>
 </select>
</mapper>

prefixOverrides 属性会忽略通过管道分隔的文本序列(注意此例中的空格也是必要的)。它的作用是移除所有指定在 prefixOverrides 属性中的内容,并且插入 prefix 属性中指定的内容。

prefix里面的值替代 prefixOverrides 里面的东西 如果是 and user_name = 'xxx ' and account = 'xxx'会把第一个 and 替代为where,即:where user_name = ''xxx and account = 'xxx' 。

为什么替换的是第一个 and 二而第二个不替换呢?这里是 prefixOverrides ,prefix是前缀的意思,故替换第一个 and 使用 prefix 里面的值替代。

set  

通过上面案例可以把动态模糊查询的知识点解决了,学习了Where、Trim标签后,我们顺道学习一下set标签,为了理解set标签的作用,我们写一个没有set标签的语句:

UserMapper.xml

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
 PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jujidi.model.User">
<sql id="jujidi">
 user_name userName,user_iduserId,account,password pwd,status
</sql>

<update id="update" parameterType="com.jujidi.model.User">
 update user set
   <if test="userName !=null and userName != ''">
    user_name = #{userName},
   </if>
   <if test="account !=null and account != ''">
     account=#{account}
   </if>
    where user_id=#{userId}
</update>
</mapper>

UserDao.java

public interface UserDao {

   //List<User> likes(User user);
   void update(User user);

}

UserDaoImpl.java

public class UserDaoImpl implements UserDao {
private SqlSession sqlSession = null;

@Override
publicvoid update(User user ) {
 try{
   sqlSession = MybatisUtil.getSqlSession();
   sqlSession.update("com.jujidi.model.User.update",user);
   sqlSession.commit();
  }catch(Exception e){
    e.printStackTrace();
    throw new RuntimeException("更改失败");
  }finally{
    MybatisUtil.closeSqlSession(sqlSession);
  }      
 }
}

MyBatisTest.java

public class MybatisTest {
UserDao userDao = null;

@Before
public void init(){
 userDao = new UserDaoImpl();
}

@Test
public void update(){
 User user = new User();
 user.setUserName("聚集地");
 user.setAccount("as");
 user.setUserId(4);
 userDao.update(user);
}
}

结果:运行后成功插入了一条语句!

我们做适当改动,便会抛出异常报错,然后引出set元素使用:

MyBatisTest.java

public class MybatisTest {
UserDao userDao = null;

@Before
public void init(){
 userDao = new UserDaoImpl();
}

@Test
public void update(){
 User user = new User();
 user.setUserName("聚集地");
 //user.setAccount("as");
 user.setUserId(4);
 userDao.update(user);
 }
}

只修改userName,不修改account运行后会报错,控制台打印的sql语句

MyBatis框架教程「模糊查询」

上图红色圆圈部分,多了一个逗号照成了报错。去掉这个逗号我们可以使用set标签实现:

<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE mapper
   PUBLIC "-//mybatis.org//DTDMapper 3.0//EN"
   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.jujidi.model.User">

<sql id="jujidi">
  user_name userName,user_iduserId,account,password pwd,status
</sql>   

<update id="update" parameterType="com.jujidi.model.User">
  update user 
   <set>
     <if test="userName !=null and userName != ''">
     user_name =#{userName},
     </if>
     <if test="account !=null and account != ''">
     account=#{account}
     </if>
    </set>
    where user_id=#{userId}
 </update>

</mapper>

set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号,因为用了条件语句之后很可能就会在生成的 SQL 语句的后面留下这些逗号。(因为用的是"if"元素,若最后一个"if"没有匹配上而前面的匹配上,SQL 语句的最后就会有一个逗号遗留)

总结

这篇文章有点长,我们讲解了模糊查询,动态模糊查询,并且学习了where,set,trim标签的使用。代码也比较多,阅读起来可能有些费劲。若理清私聊,多看几遍,我认为还是可以巩固基础,有所进步。

如果您觉得我的原创教程不错的话,欢迎分享和点赞,您的支持是我最大的动力!

历史教程

1. MyBatis框架教程「入门起步」

2. MyBatis框架教程「实践与工具类封装」

3. MyBatis框架教程「工具类的使用」

MyBatis框架教程「模糊查询」

本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

版权声明:程序员胖胖胖虎阿 发表于 2022年11月13日 下午3:56。
转载请注明:MyBatis框架教程「模糊查询」 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...