前幾天運營提到說后台管理系統有幾個地方想要模糊查詢..

想了下是簡單的,就是要注意以前方法的被調用情況,進行增量改動,以免牽一發而動全身。整理一波記錄下(本次案例是按名字模糊查詢學生信息)。
三種方式概覽
- SQL 語句正常 like,service 層按需要添加 '%'
- SQL 使用 CONCAT 函數
- mybatis 的 bind 語法
依舊使用H2數據庫(>>springboot與H2數據庫快速本地測試),初始化腳本配置一個簡單的學生表,添幾條記錄。
H2和mybatis相關配置
1)maven依賴
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.0.1</version> </dependency>
2)application.properties
server.port=8091 server.servlet.context-path=/tsa #spring.datasource.url=jdbc:h2:mem:test spring.datasource.url=jdbc:h2:~/test spring.datasource.driver-class-name=org.h2.Driver spring.datasource.username=sa spring.datasource.password=123456 spring.datasource.schema=classpath:h2sql/schema.sql spring.datasource.data=classpath:h2sql/data.sql spring.h2.console.enabled=true #localhost:8080/projectName/h2-console spring.h2.console.path=/h2-console #mybatis.config-location=classpath:/mybatis-config.xml mybatis.mapper-locations=classpath:/sqlmap/*Mapper.xml mybatis.configuration.map-underscore-to-camel-case=true mybatis.type-aliases-package=com.hwc.tsa.bean logging.level.com.hwc.tsa.dao=debug logging.level.com.hwc.tsa.mapper=debug
3)H2初始化腳本(學生表)
h2sql/schema.sql
drop table if exists student; create table student( id int unsigned not null auto_increment comment '自增主鍵', name varchar(20) not null comment '字典類型-關聯字段', age int unsigned not null comment '年齡', status tinyint not null default 1 comment '邏輯刪除字段', crt_time timestamp not null default CURRENT_TIMESTAMP comment '創建時間', upd_time timestamp default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP comment '更新時間', PRIMARY KEY (id) );
h2sql/data.sql
insert into student(name, age) values ('菠蘿包', 1); insert into student(name, age) values ('皮卡丘', 3); insert into student(name, age) values ('悟空', 35); insert into student(name, age) values ('悟飯', 21); insert into student(name, age) values ('克林', 37); insert into student(name, age) values ('弗利沙', 999); insert into student(name, age) values ('妙蛙種子', 3); insert into student(name, age) values ('傑尼龜', 2); insert into student(name, age) values ('小傑', 17);
啟動項目並檢查項目結構
本次不是在之前的demo項目上繼續的,只需關注幾個目標包(xxx.bean.entity,xxx.mapper、resources/sqlmap、resources/h2sql)就OK。
1)先啟動springboot項目,初始化H2數據庫。
啟動項目:

控制台連接H2數據庫(>>springboot與H2數據庫快速本地測試)檢查數據初始化:

2)建立相應的包和目錄結構,使用mybatis逆向工具快速生成entity和mapper
>>簡單使用maven-mybatis插件逆向生成entity和Mapper
結構圖:

方式1
方式1即 SQL 部分只寫簡單的 like,在 service 層決定哪個字段需要模糊查(加上 '%')。
StudentMapper 新增方法(按名字模糊查):
/** * 表單模糊查詢支持 * @param record * @return */ List<Student> selectByFormLikeSelective(Student record);
StudentMapper.xml 新增查詢映射點:
<select id="selectByFormLikeSelective" parameterType="student" resultMap="BaseResultMap"> select <include refid="Base_Column_List"/> from student <where> <if test="name!=null and name!=''"> and name like #{name} </if> <if test="status!=null"> and status = #{status} </if> </where> </select>
編寫測試類:
@RunWith(SpringRunner.class) //不加載web環境,更快捷測試 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) //@SpringBootTest public class MapperDaoTests { private static final Logger logger = LoggerFactory.getLogger(MapperDaoTests.class); @Autowired StudentMapper stuMapper; @Test public void testStudentMapperLikeSelective() { //模擬controller輸入 Map<String, Object> map = new HashMap<>(); map.put("name", "悟"); Student stu = new Student(); BeanUtil.mapValueCopy2Bean(map, stu); //模擬service處理 stu.setName("悟"); stu.setName(StringUtil.addLikeStringLR(stu.getName()));//兩邊加 % //調用mapper(dao) List<Student> stuList = stuMapper.selectByFormLikeSelective(stu); //輸出驗證 預期2行 logger.info("stuList size is: {}", stuList.size()); } }
JUnit 測試結果:

方式2
方式2則是使用 SQL 的 CONCAT 函數,直接在 SQL 中連接 '%' 。
主流數據庫都有 CONCAT 函數,另外 Oracle 還可以使用 || 符號更方便,但是為了通用性,建議使用 CONCAT 函數。
修改方式1中的代碼。
test 方法中去掉/注掉加百分號行:
//stu.setName(StringUtil.addLikeStringLR(stu.getName()));//兩邊加 %
xml 中修改目標 like 處為:
<if test="name!=null and name!=''"> <!-- and name like #{name} --> and name like concat(concat('%', #{name}), '%') </if>
測試結果(注意dao傳入時是沒有加百分號的):

方式3
方式3使用 mybatis 動態 sql 的 bind 語法,官方地址:http://www.mybatis.org/mybatis-3/zh/dynamic-sql.html。
這樣的好處是既不要改 service 代碼,也不需要使用 CONCAT 函數拼接字段值,只需在 sql 語句塊開始處定義屬性綁定規則即可。
Mapper.xml 修改:
<select id="selectByFormLikeSelective" parameterType="student" resultMap="BaseResultMap"> <bind name="name" value="'%' + _parameter.getName() + '%'" /> select <include refid="Base_Column_List"/> from student <where> <if test="name!=null and name!=''"> and name like #{name} </if> <if test="status!=null"> and status = #{status} </if> </where> </select>
運行截圖:

傳入就是帶百分號的,可以看出,這種方式其實就是方式1,只不過加 '%' 的事情,mybatis 幫我們做了。
總結
這三種方式都很簡單,但是綜合而講,直男君推薦方式1,我們在 service 層自行決定哪個需要模糊查。方式2的話,SQL不簡潔;方式3則沒有通用性。