作者 | 王久一
通过上三篇Mybatis教程文章的学习,我们已经基本掌握了环境的搭建,简单增删改查语句的编写,MyBatis工具类的使用以及单元测试组件的使用。可以移步查看:
1. MyBatis框架教程「入门起步」
2. MyBatis框架教程「实践与工具类封装」
3. MyBatis框架教程「工具类的使用」
但是面对复杂的业务逻辑这些简单的增删改查是远远不能胜任的,这篇介绍运用MyBatis进行模糊查询,学习where,set和trim标签的使用。
模糊查询
模糊查询是和精确查询对应的,恰恰相反,精确查询可以精确定位想要查询的信息。而模糊查询可以通过 like 关键字和通配符的配合实现匹配符合目标关键字的信息。比如:你想购买《Java核心编程》这本书,只需要在电商平台搜索引擎键入:核心编程 四个字,书名含这四个字的书籍信息都会罗列出来(当然这只是一个例子,可能还需要全文检索工具或者Elasticsearch来优化服务。)。
1. 新建Java项目:
2. 导入Jar包:log4j,mybatis,mysql驱动
3. 数据库:
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语句:
上图红色圆圈部分,多了一个逗号照成了报错。去掉这个逗号我们可以使用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框架教程「工具类的使用」
本文分享自微信公众号 - Java后端(web_resource)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。