内容简介:本小节主要讲解fastmybatis的查询功能。fastmybatis提供丰富的查询方式,满足日常查询所需。前端传递两个分页参数pageIndex,pageSize
简介
fastmybatis 是一个mybatis开发框架,其宗旨为:简单、快速、有效。
- 零配置快速上手
- 无需编写xml文件即可完成CRUD操作
- 支持mysql,sqlserver,oracle,postgresql,sqlite
- 支持自定义sql,sql语句可写在注解中或xml中
- 支持与spring-boot集成,依赖starter即可
- 轻量级,无侵入性,是官方mybatis的一种扩展
快速开始(springboot)
- 新建一个springboot项目
- pom.xml添加fastmybatis-spring-boot-starter
<dependency> <groupId>net.oschina.durcframework</groupId> <artifactId>fastmybatis-spring-boot-starter</artifactId> <version>最新版本(见changelog.md)</version> </dependency>
-
假设数据库有张
t_user
表,添加对应的实体类TUser.java
和MapperTUserMapper.java
(可用fastmybatis-generator来生成) -
在
application.propertis
中配置数据库连接 - 编写测试用例
@Autowired TUserMapper mapper; // 根据主键查询 @Test public void testGetById() { TUser user = mapper.getById(3); System.out.println(user); }
查询
本小节主要讲解fastmybatis的查询功能。fastmybatis提供丰富的查询方式,满足日常查询所需。
分页查询
方式1
前端传递两个分页参数pageIndex,pageSize
// http://localhost:8080/page1?pageIndex=1&pageSize=10 @GetMapping("page1") public List<TUser> page1(int pageIndex,int pageSize) { Query query = new Query(); query.page(pageIndex, pageSize); List<TUser> list = mapper.list(query); return list; }
方式2
PageParam里面封装了pageIndex,pageSize参数
// http://localhost:8080/page2?pageIndex=1&pageSize=10 @GetMapping("page2") public List<TUser> page2(PageParam param) { Query query = param.toQuery(); List<TUser> list = mapper.list(query); return list; }
返回结果集和总记录数
方式1和方式2只能查询结果集,通常我们查询还需返回记录总数并返回给前端,fastmybatis的处理方式如下:
// http://localhost:8080/page3?pageIndex=1&pageSize=10 @GetMapping("page3") public Map<String,Object> page3(PageParam param) { Query query = param.toQuery(); List<TUser> list = mapper.list(query); long total = mapper.getCount(query); Map<String,Object> result = new HashMap<String, Object>(); result.put("list", list); result.put("total", total); return result; }
fastmybatis提供一种更简洁的方式来处理:
// http://localhost:8080/page4?pageIndex=1&pageSize=10 @GetMapping("page4") public PageInfo<TUser> page4(PageParam param) { PageInfo<TUser> pageInfo = MapperUtil.query(mapper, query); return result; }
PageInfo里面包含了List,total信息,还包含了一些额外信息,完整数据如下:
{ "currentPageIndex": 1, // 当前页 "firstPageIndex": 1, // 首页 "lastPageIndex": 2, // 尾页 "list": [ // 结果集 {}, {} ], "nextPageIndex": 2, // 下一页 "pageCount": 2, // 总页数 "pageIndex": 1, // 当前页 "pageSize": 10, // 每页记录数 "prePageIndex": 1, // 上一页 "start": 0, "total": 20 // 总记录数 }
根据参数字段查询
查询姓名为张三的用户
// http://localhost:8080/sch?username=张三 @GetMapping("sch") public List<TUser> sch(String username) { Query query = new Query(); query.eq("username", username); List<TUser> list = mapper.list(query); return list; }
查询姓名为张三并且拥有的钱大于100块
// http://localhost:8080/sch2?username=张三 @GetMapping("sch2") public List<TUser> sch2(String username) { Query query = new Query(); query.eq("username", username).gt("money", 100); List<TUser> list = mapper.list(query); return list; }
查询姓名为张三并带分页
// http://localhost:8080/sch3?username=张三&pageIndex=1&pageSize=5 @GetMapping("sch3") public List<TUser> sch3(String username,PageParam param) { Query query = param.toQuery(); query.eq("username", username); List<TUser> list = mapper.list(query); return list; }
查询钱最多的前三名
// http://localhost:8080/sch4 @GetMapping("sch4") public List<TUser> sch4() { Query query = new Query(); query.orderby("money", Sort.DESC) // 按金额降序 .page(1, 3); List<TUser> list = mapper.list(query); return list; }
将参数放在对象中查询
// http://localhost:8080/sch5?username=张三 @GetMapping("sch5") public List<TUser> sch5(UserParam userParam) { Query query = userParam.toQuery(); query.eq("username", userParam.getUsername()); List<TUser> list = mapper.list(query); return list; }
UserParam继承PageSortParam类,表示支持分页和 排序 查询
使用普通bean查询
假设有个User类如下
public class User { private Integer id; private String userName; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
我们将这个类作为查询参数,那么在springmvc中可以这样写:
@GetMapping(path="findUserBean.do") public List<User> findUser(User user) { Query query = Query.build(user); List<User> list = dao.find(query); return list; }
Query query = Query.build(user);这句是将User中的属性转换成对应条件,假设userName的值为”jim”,那么会封装成一个条件where user_name=’jim’
浏览器输入链接: http://localhost:8080/fastmybatis-springmvc/findUserBean.do?userName=jim
后台将会执行如下SQL:
SELECT id,user_name FROM user t WHERE t.user_name = ?
?的值为jim
@Condition注解
@Condition注解用来强化查询,有了这个注解可以生成各种查询条件。
@Condition注解有三个属性:
- joint:表达式之间的连接符,AND|OR,默认AND
- column:数据库字段名,可选
- operator:连接符枚举,存放了等于、大于、小于等连接符
如果要查询id大于2的用户只需在get方法上加上一个@Condition注解即可:
@Condition(operator=Operator.gt) public Integer getId() { return this.id; }
这样,当id有值时,会封装成一个 where id>2 的条件
- 需要注意的是,如果不指定column属性,系统会默认取get方法中属性名,然后转换成数据库字段名。如果需要指定数据库字段名的话,可以使用@Condition的column属性。
public Integer get++UserName++() {
return this.userName;
}
这种情况下会取下划线部分字段,然后转换成数据库字段名。
@Condition(column="username") // 显示指定字段名 public Integer getUserName() { return this.userName; }
使用@Condition可以生产更加灵活的条件查询,比如需要查询日期为2017-12-1~2017-12-10日的记录,我们可以这样写:
@Condition(column="add_date",operator=Operator.ge) public Date getStartDate() { return this.startDate; } @Condition(column="add_date",operator=Operator.lt) public Date getEndDate() { return this.endDate; }
转换成 SQL 语句:
t.add_date>='2017-12-1' AND t.add_date<'2017-12-10'
IN查询
假设前端页面传来多个值比如checkbox勾选多个id=[1,2],那么我们在User类里面可以用Integer[]或List来接收.
private Integer[] idArr; public void setIdArr(Integer[] idArr) {this.idArr = idArr;} @Condition(column="id") public Integer[] getIdArr() {return this.idArr;}
这样会生成where id IN(1,2)条件。
排序查询
// 根据添加时间倒序
Query query = new Query(); query.orderby("create_time",Sort.DESC); dao.find(query);
多表关联查询
多表关联查询使用的地方很多,比如需要关联第二张表,获取第二张表的几个字段,然后返回给前端。
fastmybatis的用法如下:
假如我们需要关联第二张表 user_info
,筛选出user_info中的城市为杭州的数据。
Query query = new Query() // 左连接查询,主表的alias默认为t .join("LEFT JOIN user_info t2 ON t.id = t2.user_id").page(1, 5) .eq("t2.city","杭州"); List<TUser> list = mapper.list(query); System.out.println("=============="); for (TUser user : list) { System.out.println(user.getId() + " " + user.getUsername()); } System.out.println("==============");
多表关联返回指定字段
有时候不需要全部字段,需要取表1中的几个字段,然后取表2中的几个字段,fastmybatis实现方式如下:
Query query = new Query(); // 左连接查询,主表的alias默认为t query.join("LEFT JOIN user_info t2 ON t.id = t2.user_id"); // 指定返回字段 List<String> column = Arrays.asList("t2.user_id as userId", "t.username", "t2.city"); // 查询结果返回到map中 List<Map<String, Object>> mapList = mapper.listMap(column, query); // 再将map转换成实体bean List<UserInfoVo> list = MyBeanUtil.mapListToObjList(mapList, UserInfoVo.class);
执行的SQL语句对应如下:
SELECT t2.user_id as userId , t.username , t2.city FROM `t_user` t LEFT JOIN user_info t2 ON t.id = t2.user_id
使用@Select查询
@Select注解是mybatis官方提供的一个功能,fastmybatis可以理解为是官方的一种扩展,因此同样支持此功能。
在Mapper中添加如下代码:
@Select("select * from t_user where id=#{id}") TUser selectById(@Param("id") int id);
编写测试用例
@Test public void testSelectById() { TUser user = dao.selectById(3); System.out.println(user.getUsername()); }
对于简单的SQL,可以用这种方式实现。除了@Select之外,还有@Update,@Insert,@Delete,这里就不多做演示了。
Query类详解
Query是一个查询参数类,配合Mapper一起使用。
参数介绍
Query里面封装了一系列查询参数,主要分为以下几类:
- 分页参数:设置分页
- 排序参数:设置排序字段
- 条件参数:设置查询条件
- 字段参数:可返回指定字段
下面逐个讲解每个参数的用法。
分页参数
一般来说分页的使用比较简单,通常是两个参数,
pageIndex:当前页索引,pageSize:每页几条数据。
Query类使用 page(pageIdnex, pageSize) 方法来设置。
假如我们要查询第二页,每页10条数据,代码可以这样写:
Query query = new Query(); query.page(2, 10); List<User> list = dao.find(query);
如果要实现不规则分页,可以这样写:
Query query = new Query(); query.limit(3, 5) // 对应mysql:limit 3,5
排序参数
orderby(String sortname, Sort sort)
其中sortname为数据库字段,非javaBean属性
- orderby(String sortname, Sort sort)则可以指定排序方式,Sort为排序方式枚举
假如要按照添加时间倒序,可以这样写:
Query query = new Query(); query.orderby("create_time",Sort.DESC); mapper.list(query);
添加多个排序字段可以在后面追加:
query.orderby("create_time",Sort.DESC).orderby("id",Sort.ASC);
条件参数
条件参数是用的最多一个,因为在查询中往往需要加入各种条件。
fastmybatis在条件查询上面做了一些封装,这里不做太多讲解,只讲下基本的用法,以后会单独开一篇文章来介绍。感兴趣的同学可以自行查看源码,也不难理解。
条件参数使用非常简单,Query对象封装一系列常用条件查询。
-
等值查询eq(String columnName, Object value),columnName为数据库字段名,value为查询的值
假设我们要查询姓名为张三的用户,可以这样写:
Query query = new Query(); query.eq("username","张三"); List<User> list = mapper.list(query);
通过方法名即可知道eq表示等于’=’,同理lt表示小于<,gt表示大于>
查询方式 | 说明 |
---|---|
eq | 等于= |
gt | 大于> |
lt | 小于< |
ge | 大于等于>= |
le | 小于等于<= |
notEq | 不等于<> |
like | 模糊查询 |
in | in()查询 |
notIn | not in()查询 |
isNull | NULL值查询 |
notNull | IS NOT NULL |
notEmpty | 字段不为空,非NULL且有内容 |
isEmpty | 字段为NULL或者为” |
如果上述方法还不能满足查询需求的话,我们可以使用自定sql的方式来编写查询条件,方法为:
Query query = new Query(); query.sql(" username='Jim' OR username='Tom'");
注意:sql()方法不会处理sql注入问题,因此尽量少用。
自定义SQL
方式1
直接写在Mapper.java中
public interface TUserMapper extends CrudMapper<TUser, Integer> { // 自定义sql,官方自带,不需要写xml /** * 修改用户名 * @param id * @param username * @return 返回影响行数 */ @Update("update t_user set username = #{username} where id = #{id}") int updateById(@Param("id") int id, @Param("username") String username); }
简单SQL可采用这种形式。
方式2
fastmybatis提供的Mapper已经满足大部分的操作需求,但是有些复杂的sql语句还是需要写在xml文件中。fastmybatis同样支持将sql语句写在xml中,具体配置如下:
- 在application.properties添加一句,指定xml文件存放路径
mybatis.mapper-locations=classpath:/mybatis/mapper/*.xml
- 在resources/mybatis/mapper目录下新建一个xml文件TUserMapper.xml,内容如下:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mayapp.mapper.TUserMapper"> <select id="selectByName" parameterType="String" resultMap="baseResultMap"> select * from t_user t where t.username = #{username} limit 1 </select> </mapper>
这个xml文件跟其它的mybatis配置文件一样,baseResultMap没有看到定义,但是确实存在,因为这个是fastmybatis提供的一个内置resultMap。
- 在TUseroMapper.java中添加:
TUser selectByName(@Param("username")String username);
- 编写单元测试用例
@Test public void testSelectByName() { TUser user = dao.selectByName("张三"); System.out.println(user.getUsername()); }
多文件同一个namespace
在以往的开发过程中,一个Mapper对应一个xml文件(namespace)。如果多人同时在一个xml中写SQL的话会造成各种冲突(虽然能够最终被解决)。
fastmybatis打破这种常规,允许不同的xml文件定义相同的namespace,程序启动时会自动把他们的内容合并到同一个文件当中去。
- 张三的UserMapper_zs.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mayapp.mapper.TUserMapper"> <select id="selectByName" parameterType="String" resultMap="baseResultMap"> select * from t_user t where t.username = #{username} limit 1 </select> </mapper>
- 李四的UserMapper_ls.xml
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mayapp.mapper.TUserMapper"> <select id="updateUser" parameterType="String" resultMap="baseResultMap"> update t_user set username = #{username} where id=#{id} </select> </mapper>
最终会合并成
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.mayapp.mapper.TUserMapper"> <!-- 张三部分 --> <select id="selectByName" parameterType="String" resultMap="baseResultMap"> select * from t_user t where t.username = #{username} limit 1 </select> <!-- 李四部分 --> <select id="updateUser" parameterType="String" resultMap="baseResultMap"> update t_user set username = #{username} where id=#{id} </select> </mapper>
这样也体现了开闭原则,即新增一个功能只需要新增一个文件就行,不需要修改原来的文件。
如果SQL写多了还可以把它们进行分类,放到不同的xml中,便于管理。
注:合并动作是在启动时进行的,并不会生成一个真实的文件。
字段自动填充
填充器设置
假设数据库表里面有两个时间字段gmt_create,gmt_update。
当进行insert操作时gmt_create,gmt_update字段需要更新。当update时,gmt_update字段需要更新。
通常的做法是通过Entity手动设置:
User user = new User(); user.setGmtCreate(new Date()); user.setGmtUpdate(new Date());
因为表设计的时候大部分都有这两个字段,所以对每张表都进行手动设置的话很容易错加、漏加。
fastmybatis提供了两个辅助类DateFillInsert和DateFillUpdate,用来处理添加修改时的时间字段自动填充。配置了这两个类之后,时间字段将会自动设置。
配置方式如下:
EasymybatisConfig config = new EasymybatisConfig(); config.setFills(Arrays.asList( new DateFillInsert() ,new DateFillUpdate() ));
在spring的xml中配置如下:
<bean id="sqlSessionFactory" class="com.gitee.fastmybatis.core.ext.SqlSessionFactoryBeanExt"> <property name="dataSource" ref="dataSource" /> <property name="configLocation"> <value>classpath:mybatis/mybatisConfig.xml</value> </property> <property name="mapperLocations"> <list> <value>classpath:mybatis/mapper/*.xml</value> </list> </property> <!-- 以下是附加属性 --> <!-- dao所在的包名,跟MapperScannerConfigurer的basePackage一致 多个用;隔开 --> <property name="basePackage" value="com.myapp.dao" /> <property name="config"> <bean class="com.gitee.fastmybatis.core.EasymybatisConfig"> <!-- 定义填充器 --> <property name="fills"> <list> <bean class="com.gitee.fastmybatis.core.support.DateFillInsert"/> <bean class="com.gitee.fastmybatis.core.support.DateFillUpdate"/> </list> </property> </bean> </property> </bean>
springboot中可以这样定义:
在application.properties中添加:
mybatis.fill.com.gitee.fastmybatis.core.support.DateFillInsert= mybatis.fill.com.gitee.fastmybatis.core.support.DateFillUpdate=
如果要指定字段名,可以写成:
mybatis.fill.com.gitee.fastmybatis.core.support.DateFillInsert=add_time
自定义填充器
除了使用fastmybatis默认提供的填充之外,我们还可以自定义填充。
自定义填充类要继承FillHandler类。
表示填充字段类型,如Date,String,BigDecimal,Boolean。
实战(springboot)
现在有个remark字段,需要在insert时初始化为“备注默认内容”,新建一个StringRemarkFill类如下:
public class StringRemarkFill extends FillHandler<String> { @Override public String getColumnName() { return "remark"; } @Override public FillType getFillType() { return FillType.INSERT; } @Override protected Object getFillValue(String defaultValue) { return "备注默认内容"; } }
StringRemarkFill类中有三个重写方法:
- getColumnName() : 指定表字段名
- getFillType() : 填充方式,FillType.INSERT:仅insert时填充; FillType.UPDATE:insert,update时填充
- getFillValue(String defaultValue) :返回填充内容
然后在application.properties中添加:
mybatis.fill.com.xx.StringRemarkFill=
这样就配置完毕了,调用dao.save(user);时会自动填充remark字段。
指定目标类
上面说到StringRemarkFill填充器,它作用在所有实体类上,也就是说实体类如果有remark字段都会自动填充。这样显然是不合理的,解决办法是指定特定的实体类。只要重写FillHandler类的getTargetEntityClasses()方法即可。
@Override public Class<?>[] getTargetEntityClasses() { return new Class<?>[] { TUser.class }; }
这样就表示作用在TUser类上,多个类可以追加。最终代码如下:
public class StringRemarkFill extends FillHandler<String> { @Override public String getColumnName() { return "remark"; } @Override public Class<?>[] getTargetEntityClasses() { return new Class<?>[] { TUser.class }; // 只作用在TUser类上 } @Override public FillType getFillType() { return FillType.INSERT; } @Override protected Object getFillValue(String defaultValue) { return "备注默认内容"; // insert时填充的内容 } }
关于自动填充的原理是基于mybatis的TypeHandler实现的,这里就不多做介绍了。感兴趣的同学可以查看FillHandler源码。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Algorithmic Beauty of Plants
Przemyslaw Prusinkiewicz、Aristid Lindenmayer / Springer / 1996-4-18 / USD 99.00
Now available in an affordable softcover edition, this classic in Springer's acclaimed Virtual Laboratory series is the first comprehensive account of the computer simulation of plant development. 150......一起来看看 《The Algorithmic Beauty of Plants》 这本书的介绍吧!