springboot mybatis 注解sql,springboot集成mybatisplus分页
目录
一、环境配置二、Mybatis注解三、方法参数读取1.普通参数读取2.对象参数读取四、分页插件的使用五、动态标签六、完整示例
一、环境配置
1.引入框架依赖
编译(//spring MVC org。spring框架。启动:弹簧启动启动网站。更快的XML。杰克逊。数据类型:杰克森数据类型-JSR 310:2。9 .3 ,//Mybatis依赖及分页插件org。我的巴蒂斯。春天。启动: my batis-弹簧-启动:1。3 .1 , com。github。页面助手:页面助手:4。1 .0 , MySQL : MySQL-connector-Java )2。数据源配置
spring :数据源:用户名: root密码: 123456驱动程序类名称: com。MySQL。JDBC。驱动URL : JDBC : MySQL :///mybatis?字符编码=ut F8使用ssl=false//根据资源目录下的schema.sql自动建表,可省略架构:类路径:架构。SQL//根据资源目录下的data.sql自动插入假数据,可省略数据:类路径:数据。SQL 3分页插件配置
@ configuration公共类通用配置{/* * *注册米巴蒂斯分页插件page helper */@ Bean public page helper page helper(){ page helper page helper=new page helper();Properties p=new Properties();p.setProperty(offsetAsPageNum , true );p .设置属性( rowBoundsWithCount , true );p.setProperty(合理,真);页面助手。设置属性(p);返回pageHelper}}4。配置跳羚扫描框架仓储,有两种配置方式
在启动类上加入@MapperScan,填写制图人接口所在的包名,跳靴就会自动将该包中的制图人接口进行加载
@ MapperScan(base packages= com。金童。repository )@ spring boot application公共类kingboyspringbootdata application { public static void main(String[]args){ spring application。运行(kingboyspringbootdata应用程序。class,args);}}在制图人接口上加上@Mapper注解,跳靴就会自动夹在该制图人接口
@ mapper公共接口用户映射程序{ @ Insert( Insert INTO ` User ` VALUES(# { id }、#{nickName}、#{phoneNumber}、#{sex}、#{age}、#{birthday}、# { status })@ Options(useGeneratedKeys=true,keyColumn=id ,key property= id )void save User(User用户用户);}这两种方式都可以,根据项目结构进行选择即可,也可以结合私用。
5.配置驼峰属性自动映射
我的蝙蝠
is: configuration: map-underscore-to-camel-case: true例如实体中属性为phoneNumber,数据库属性为phone_number,Mybatis默认是不能自动转换的,通常我们要自定义以下结果集映射
@Result(column = "phone_number", property = "phoneNumber")
然而这样很不方便,当我们加上以上配置之后,Mybatis在映射结果时,会自动转换,去掉下划线,变n为大写N。
6.设置mybatis日志打印,在配置文件中加入如下配置
logging: level: #Mapper所在的包 com.kingboy.repository: debug
开启日志有三种方式,可以参考我的另一篇博客
logback中显示mybatis查询日志文件并写入的方法
二、Mybatis注解
Mybatis提供了四个注解,先简单了解一下,后面的完整示例中演示了相应的实例
@Insert(sql) 增@Delete(sql) 删@Update(sql) 改@Select(sql) 查
三、方法参数读取
1.普通参数读取
在方法参数前使用@Param注解对参数进行标记,在sql中使用#{属性名}来读取属性。
示例
//删除用户,根据用户ID和名称删除用户 @Delete("DELETE FROM `user` WHERE id = #{id} AND nick_name = #{nickName}") void delete(@Param(value = "id") Long id, @Param(value = "nickName") String nickName);
2.对象参数读取
直接在sql中使用#{属性名}来读取属性
示例
@Insert("INSERT INTO `user` VALUES (#{id}, #{nickName}, #{phoneNumber}, #{sex}, #{age}, #{birthday}, #{status})") @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id") void saveUser(User user);
这里补充一点,@Options注解和@Insert注解结合使用,可以将保存后的主键设置到user实体中。也就是说保存前user的id是没值的,保存后mybatis会自动将数据库中的主键设置到user的id属性上,keyColumn = "id"为数据库主键名,keyProperty = "id"为实体的主键属性名。
四、分页插件的使用
分页插件单独拿出来说,是因为项目实战中发现很多同学都使用错了,所以着重强调一下。
分页插件的核心类是PageHelper,这个类提供了很多的静态方法,其中我们最常用的是PageHelper.startPage(int page, int size)这个方法,返回com.github.pagehelper.Page对象,该对象包含了包含了查询结果result, 当前页pageNum,每页大小pageSize, 总条数total等信息,可以获取这些信息返回给前端。需要注意的是,PageHelper的页数是从1开始的。
我们来看一段实际的代码操作,这里就不写service层了。
//controllerRestController@RequestMapping(value = "/user")public class UserController { @Resource UserRepository userRepository; @GetMapping @Transactional(readOnly = true) public Page get(@RequestParam Integer page, @RequestParam Integer size) { //分页并查询 Page<User> pageInfo = PageHelper.startPage(page, size); List<User> users = userRepository.listUser(); //获取分页信息演示, 实际项目中一般会封装为自己的返回体。 int pageNum = pageInfo.getPageNum(); int pageSize = pageInfo.getPageSize(); long total = pageInfo.getTotal(); List<User> result = pageInfo.getResult();//和上面的users结果相同 return pageInfo; }}//repository@Mapperpublic interface UserRepository { //分页查询用户 @Select("SELECT * FROM `user`") List<User> listUser();}
五、动态标签
熟悉Mybatis的同学一定对Mybatis的动态SQL很了解,解决了我们编写动态SQL的很多痛点。接下来介绍以下Mybatis常用的动态sql的注解写法,其实和xml是几乎完全一致的。
首先在注解中使用动态sql时,我们需要为sql加上<script></script>
标签,这时候mybatis才会解析里面的标签。
1.<if test="条件判断">sql</if>
用来对参数进行判断,若为真,则包裹的sql语句生效。条件中可以使用and作连接
//分页查询用户,如果sex有值,则查询相应sex的所有用户,sex没值则查询所有 @Select("<script>SELECT * FROM `user` <if test=sex != null>where sex = #{sex}</if><script>") List<User> listUser(Sex sex);//sex是一个枚举类型,值为BOY,GIRL
2.<foreach item = 'item' index = 'index' collection='list' separator=',', open='(', close=')'>sql</foreach>
循环参数中的集合参数进行操作,和java中的for循环比较类似,不过多了open/close/separator三个参数。
open
是在操作之前加上一个"("
close
是在操作之后加上一个")"
separator
是每个元素间的分割符
需要注意的是,collection的值只能是list或者collection
示例
@Select("<script>" + "SELECT * FROM `user` WHERE id in " + "<foreach item=item collection=list open=( close=) separator=,>" + "#{item}" + "</foreach>" + "</script>") List<User> listUserByIds(List<Long> ids);
例如传入的ids为[2,4,6]生成的sql如下:
SELECT * FROM `user` WHERE id in ( 2 , 4, 6 )
3.<set></set>
更新实体属性要用到的标签,一般我们使用动态sql更新用户信息 update user set username = ?, age = ?,时要处理最后一个逗号的问题,那么使用set标签就可以自动帮我们处理这个逗号。
示例
//使用set标签进行动态set,要注意条件判断:没被删除的用户才可以更新数据 @Update("<script>" + "UPDATE `user` " + "<set>" + "<if test=nickName != null>nick_name = #{nickName}, </if>" + "<if test=age != null>age = #{age}, </if>" + "<if test=phoneNumber != null>phone_number = #{phoneNumber}, </if>" + "<if test=birthday != null>birthday = #{birthday}, </if>" + "<if test=status != null>status = #{status}, </if>" + "<if test=sex != null>sex = #{sex}, </if>" + "</set>" + "WHERE id = #{id} AND status != DELETE;" + "</script>") void updateUser(User user);
4.<where></where>
和更新数据时遇到的问题一样,我们在动态查询时也要动态拼接查询条件,最前边一个查询条件是没有AND或者OR的,以前通常使用1 = 1避开这个问题,那么现在可以使用标签自动帮我们处理。
示例
/** * 根据条件查询用户 * 注意其中nickName模糊查询的处理方法 * 注意其中关于生日的区间判断, < > * @param userQueryDTO * @return */ @Select("<script>" + "SELECT * FROM `user`" + "<where>" + "<bind name=nickName value="% + nickName + %" />" + "<if test=nickName != null>AND nick_name like #{nickName}</if>" + "<if test=phoneNumber !=null>AND phone_number = #{phoneNumber}</if>" + "<if test=sex !=null>AND sex = #{sex}</if>" + "<if test=age !=null>AND age = #{age}</if>" + "<if test=fromBirthday !=null>AND birthday > #{fromBirthday}</if>" + "<if test=toBirthday !=null>AND birthday < #{toBirthday}</if>" + "<if test=status !=null>AND status = #{status}</if>" + "</where>" + "</script>") List<User> queryByCondition(UserQueryDTO userQueryDTO);
5.<bind name='新属性' value="'%' + 原属性 + '%'" />
在模糊查询时,我们通常使用 where name like %金% 这样的方式来进行查询(当然这样效率很低,不推荐),但是在mybatis里面我们直接写 where name like %#{name}% 是不行的,会生成 where name like %'金'% 这样的sql, 很明显是不行的。有两种方式可以处理。
1)、传入的属性上加上%号,例如传入的name就为 %金% ,这样可以解决,但是不方便。
2)、使用bind标签,我们可以在sql中加入一行赋值操作
<bind name='newName' value="'%' + name + '%'" />
示例:参照上一个示例。
6.<choose><when test='条件1'></when><when test='条件2'></when><otherwise></otherwise></choose>
这个java中的switch比较像,如果条件1成立,就执行条件1中的语句,剩下的不执行。条件1不成立就判断条件2,如果条件2还不成立就执行otherwise中的sql。
示例
/** * 如果age有值,通过age查询 * 如果age没有值,则通过sex查询 * 如果age和sex都没值,则查询所有status为UNLOCK的用户 * @param age * @param sex * @return */ @Select("<script>" + "SELECT * FROM `user`" + "<where>" + "<choose>" + "<when test=age != null>AND age = #{age}</when>" + "<when test=sex != null>AND sex = #{sex}</when>" + "<otherwise>AND status = UNLOCK</otherwise>" + "</choose>" + "</where>" + "</script>") List<User> getByOrderCondition(@Param("age") Integer age, @Param("sex") Sex sex);
六、完整示例
其中的用户实体等没有贴出来,太乱了,完整示例代码可以参考文章开头的github项目。
UserController
package com.kingboy.controller.user;import com.github.pagehelper.Page;import com.github.pagehelper.PageHelper;import com.kingboy.common.utils.page.PageParam;import com.kingboy.common.utils.page.PageResult;import com.kingboy.common.utils.page.PageResultFactory;import com.kingboy.common.utils.result.ApiResult;import com.kingboy.domain.user.Sex;import com.kingboy.domain.user.Status;import com.kingboy.domain.user.User;import com.kingboy.dto.user.UserQueryDTO;import com.kingboy.repository.user.UserRepository;import org.springframework.transaction.annotation.Transactional;import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;import java.util.List;/** * @author kingboy--KingBoyWorld@163.com * @date 2017/12/30 下午11:59 * @desc 用户接口. */@RestController@RequestMapping(value = "/user")public class UserController { @Resource UserRepository userRepository; @Resource PageResultFactory pageResultFactory; /** * 保存单个用户 * http://localhost:8080/user * {"nickName":"kingboy","age":"26","sex":"BOY","phoneNumber":"13132296607","birthday":"2011-12-12 12:12","status":"UNLOCK"} * @param user * @return */ @PostMapping public ApiResult save(@RequestBody User user) { userRepository.saveUser(user); return ApiResult.success(user); } /** * 批量保存 * http://localhost:8080/user/list * [ * {"nickName":"kingboy","age":"26","sex":"BOY","phoneNumber":"13132296607","birthday":"2011-12-12 12:12","status":"UNLOCK"}, * {"nickName":"kingboy","age":"26","sex":"BOY","phoneNumber":"13132296607","birthday":"2011-12-12 12:12","status":"UNLOCK"}, * {"nickName":"kingboy","age":"26","sex":"BOY","phoneNumber":"13132296607","birthday":"2011-12-12 12:12","status":"UNLOCK"} * ] * @param users * @return */ @PostMapping(value = "/list") public ApiResult save(@RequestBody List<User> users) { userRepository.saveUserList(users); return ApiResult.success(users); } /** * 更新单个用户 * http://localhost:8080/user * {"id":"1","nickName":"kingboy","age":"26","sex":"BOY","phoneNumber":"13132296607","birthday":"2011-12-12 12:12","status":"UNLOCK"} * @return */ @PutMapping public ApiResult update(@RequestBody User user) { userRepository.updateUser(user); return ApiResult.success("success"); } /** * 删除用户 * http://localhost:8080/user/1 * @return */ @DeleteMapping("/{id}") public ApiResult remove(@PathVariable Long id) { //软删除 userRepository.remove(id, Status.DELETE); //硬删除 //userRepository.delete(id); return ApiResult.success("success"); } /** * 通过ID获取用户 * http://localhost:8080/user/1 * @return */ @GetMapping("/{id}") public ApiResult get(@PathVariable Long id) { User user = userRepository.get(id); return ApiResult.success(user); } /** * 分页查询用户集合 * http://localhost:8080/user * 需要注意的是PageHelper是从1开始分页,而Hibernate/Jpa是从0开始分页的 * @return */ @GetMapping @Transactional(readOnly = true) public ApiResult get(@ModelAttribute PageParam pageParam) { //分页并查询 Page<User> pageInfo = PageHelper.startPage(pageParam.getPage(), pageParam.getSize()); List<User> users = userRepository.listUser(); //实际使用时,最后一个参数传入要转换的类型DTO PageResult<User> result = pageResultFactory.createAndConvert(pageParam.getMybatisPage(), pageInfo.getTotal(), users, User.class); return ApiResult.success(result); } /** * 通过id集合查询用户,这里就不做分页了。 * http://localhost:8080/user/ids * [1,3] * @return */ @PostMapping("/ids") public ApiResult getUserByIds(@RequestBody List<Long> ids) { List<User> users = userRepository.listUserByIds(ids); return ApiResult.success(users); } /** * 通过查询条件赖查询用户,这里也不做分页了 * http://localhost:8080/user/query * { * "nickName":"i", * "fromBirthday":"1999-12-31 12:12", * } * @param userQueryDTO * @return */ @PostMapping("/query") public ApiResult queryUser(@RequestBody UserQueryDTO userQueryDTO) { List<User> users = userRepository.queryByCondition(userQueryDTO); return ApiResult.success(users); } /** * 根据条件的顺序来查询用户 * http://localhost:8080/user/query?age=24 * 演示choose标签的用法:如果传入age就按年龄查询用户,age没有传入就按照sex赖查询用户。如果两者都没有传入,那就查询所有status没有冻结的用户 * 类似如下: * switch(value) { * case age: * //查询age * break; * case sex: * //查询sex * break; * default: * //查询status * break; * } */ @GetMapping("/query") public ApiResult findUserByOrderCondition(@RequestParam(required = false) Integer age, @RequestParam(required = false) Sex sex) { List<User> users = userRepository.getByOrderCondition(age, sex); return ApiResult.success(users); }}
UserRepository
package com.kingboy.repository.user;import com.kingboy.domain.user.Sex;import com.kingboy.domain.user.Status;import com.kingboy.domain.user.User;import com.kingboy.dto.user.UserQueryDTO;import org.apache.ibatis.annotations.*;import java.util.List;/** * @author kingboy--KingBoyWorld@163.com * @date 2017/12/31 上午12:01 * @desc 用户仓储. */public interface UserRepository { /** * 添加用户 * @Options返回在数据库中主键,自动赋值到user的id字段中 * keyProperty = "id"的默认值为id,可以省略 */ @Insert("INSERT INTO `user` VALUES (#{id}, #{nickName}, #{phoneNumber}, #{sex}, #{age}, #{birthday}, #{status})") @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id") void saveUser(User user); /** * 批量保存用户 * @param users */ @Insert("<script>" + "INSERT INTO `user` VALUES " + "<foreach item = item index = index collection=list separator=,>" + "(#{item.id}, #{item.nickName}, #{item.phoneNumber}, #{item.sex}, #{item.age}, #{item.birthday}, #{item.status})" + "</foreach>" + "</script>") @Options(useGeneratedKeys = true) void saveUserList(List<User> users); //使用set标签进行动态set,要注意条件判断:没被删除的用户才可以更新数据 @Update("<script>" + "UPDATE `user` " + "<set>" + "<if test=nickName != null>nick_name = #{nickName}, </if>" + "<if test=age != null>age = #{age}, </if>" + "<if test=phoneNumber != null>phone_number = #{phoneNumber}, </if>" + "<if test=birthday != null>birthday = #{birthday}, </if>" + "<if test=status != null>status = #{status}, </if>" + "<if test=sex != null>sex = #{sex}, </if>" + "</set>" + "WHERE id = #{id} AND status != DELETE;" + "</script>") void updateUser(User user); //删除用户,软删除 @Update("UPDATE `user` SET status = #{status} WHERE id = #{id}") void remove(@Param(value = "id") Long id, @Param(value = "status") Status status); //删除用户,硬删除 @Delete("DELETE FROM `user` WHERE id = #{id}") void delete(@Param(value = "id") Long id); /** * 查询用户 * 单个参数时,@Param注解可以省略 * 在配置中指定了驼峰映射,所以@Results的结果映射可以省略,不是驼峰类型的仍然需要写结果映射。 */ @Select("SELECT * FROM `user` WHERE id = #{id}") @Results({ @Result(column = "nick_name", property = "nickName"), @Result(column = "phone_number", property = "phoneNumber") }) User get(Long id); //分页查询用户 @Select("SELECT * FROM `user`") List<User> listUser(); /** * 通过id集合查询用户 * @param ids * @return */ @Select("<script>" + "SELECT * FROM `user` WHERE id in " + "<foreach item=item collection=list open=( close=) separator=,>" + "#{item}" + "</foreach>" + "</script>") List<User> listUserByIds(List<Long> ids); /** * 根据条件查询用户 * 注意其中nickName模糊查询的处理方法 * 注意其中关于生日的区间判断 * @param userQueryDTO * @return */ @Select("<script>" + "SELECT * FROM `user`" + "<where>" + "<bind name=nickName value="% + nickName + %" />" +&n
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。