您的当前位置:首页SpringBoot使用Mybatis注解开发教程-分页-动态sql

SpringBoot使用Mybatis注解开发教程-分页-动态sql

来源:小侦探旅游网
SpringBoot使⽤Mybatis注解开发教程-分页-动态sql

代码⽰例可以参考个⼈GitHub项⽬

⼀、环境配置

1.引⼊mybatis依赖

compile(

//SpringMVC

'org.springframework.boot:spring-boot-starter-web',

\"com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.3\", //Mybatis依赖及分页插件

\"org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.1\", \"com.github.pagehelper:pagehelper:4.1.0\", 'mysql:mysql-connector-java' )

2.数据源配置

spring:

datasource:

username: root password: 123456

driver-class-name: com.mysql.jdbc.Driver

url: jdbc:mysql:///mybatis?characterEncoding=utf8&useSSL=false //根据resources⽬录下的schema.sql⾃动建表,可省略 schema: classpath:schema.sql

//根据resources⽬录下的data.sql⾃动插⼊假数据,可省略 data: classpath:data.sql

3.分页插件配置

@Configuration

public class CommonConfiguration {

/**

* 注册MyBatis分页插件PageHelper */

@Bean

public PageHelper pageHelper() {

PageHelper pageHelper = new PageHelper(); Properties p = new Properties();

p.setProperty(\"offsetAsPageNum\", \"true\"); p.setProperty(\"rowBoundsWithCount\", \"true\"); p.setProperty(\"reasonable\", \"true\"); pageHelper.setProperties(p); return pageHelper; }}

4.配置SpringBoot扫描Mybatis仓储,有两种配置⽅式

在启动类上加⼊@MapperScan,填写Mapper接⼝所在的包名,SpringBoot就会⾃动将该包中的Mapper接⼝进⾏加载

@MapperScan(basePackages = \"com.kingboy.repository\")@SpringBootApplication

public class KingboySpringbootDataApplication {

public static void main(String[] args) {

SpringApplication.run(KingboySpringbootDataApplication.class, args); }}

  

在Mapper接⼝上加上@Mapper注解,SpringBoot就会⾃动夹在该Mapper接⼝

@Mapper

public interface UserMapper {

@Insert(\"INSERT INTO `user` VALUES (#{id}, #{nickName}, #{phoneNumber}, #{sex}, #{age}, #{birthday}, #{status})\") @Options(useGeneratedKeys = true, keyColumn = \"id\", keyProperty = \"id\") void saveUser(User user);}

这两种⽅式都可以,根据项⽬结构进⾏选择即可,也可以结合私⽤。

5.配置驼峰属性⾃动映射

mybatis:

configuration:

map-underscore-to-camel-case: true

例如实体中属性为phoneNumber,数据库属性为phone_number,Mybatis默认是不能⾃动转换的,通常我们要⾃定义以下结果集映射@Result(column = \"phone_number\", property = \"phoneNumber\")

然⽽这样很不⽅便,当我们加上以上配置之

logging: level:

#Mapper所在的包

com.kingboy.repository: debug

开启⽇志有三种⽅式,可以参考我的另⼀篇博客

后,Mybatis在映射结果时,会⾃动转换,去掉下划线,变n为⼤写N。6.设置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 pageInfo = PageHelper.startPage(page, size); List users = userRepository.listUser();

//获取分页信息演⽰, 实际项⽬中⼀般会封装为⾃⼰的返回体。 int pageNum = pageInfo.getPageNum(); int pageSize = pageInfo.getPageSize(); long total = pageInfo.getTotal();

List result = pageInfo.getResult();//和上⾯的users结果相同 return pageInfo; }}

//repository@Mapper

public interface UserRepository { //分页查询⽤户

@Select(\"SELECT * FROM `user`\") List listUser();}

  

五、动态标签

熟悉Mybatis的同学⼀定对Mybatis的动态SQL很了解,解决了我们编写动态SQL的很多痛点。接下来介绍以下Mybatis常⽤的动态sql的注解写法,其实和xml是⼏乎完全⼀致的。

⾸先在注解中使⽤动态sql时,我们需要为sql加上标签,这时候mybatis才会解析⾥⾯的标签。1.sql

⽤来对参数进⾏判断,若为真,则包裹的sql语句⽣效。条件中可以使⽤and作连接

分页查询⽤户,如果sex有值,则查询相应sex的所有⽤户,sex没值则查询所有

@Select(\"\")

List listUserByIds(List ids);

  例如传⼊的ids为[2,4,6]⽣成的sql如下:  SELECT * FROM `user` WHERE id in ( 2 , 4, 6 )3.

更新实体属性要⽤到的标签,⼀般我们使⽤动态sql更新⽤户信息update user set username = ?, age = ?,时要处理最后⼀个逗号的问题,那么使⽤set标签就可以⾃动帮我们处理这个逗号。

⽰例

/使⽤set标签进⾏动态set,要注意条件判断:没被删除的⽤户才可以更新数据 @Update(\"\")

void updateUser(User user);

4.

和更新数据时遇到的问题⼀样,我们在动态查询时也要动态拼接查询条件,最前边⼀个查询条件是没有AND或者OR的,以前通常使⽤1 =1避开这个问题,那么现在可以使⽤标签⾃动帮我们处理。⽰例

/**

* 根据条件查询⽤户

* 注意其中nickName模糊查询的处理⽅法 * 注意其中关于⽣⽇的区间判断, < > * @param userQueryDTO * @return */

@Select(\"\")

List queryByCondition(UserQueryDTO userQueryDTO);

5.

在模糊查询时,我们通常使⽤where name like %⾦%这样的⽅式来进⾏查询(当然这样效率很低,不推荐),但是在mybatis⾥⾯我们直接写wherename like %#{name}%是不⾏的,

会⽣成where name like %'⾦'%这样的sql, 很明显是不⾏的。有两种⽅式可以处理。1)、传⼊的属性上加上%号,例如传⼊的name就为%⾦%,这样可以解决,但是不⽅便。

2)、使⽤bind标签,我们可以在sql中加⼊⼀⾏赋值操作⽰例:参照上⼀个⽰例。

6.

这个java中的switch⽐较像,如果条件1成⽴,就执⾏条件1中的语句,剩下的不执⾏。条件1不成⽴就判断条件2,如果条件2还不成⽴就执⾏otherwise中的sql。⽰例

/**

* 如果age有值,通过age查询 * 如果age没有值,则通过sex查询

* 如果age和sex都没值,则查询所有status为UNLOCK的⽤户 * @param age * @param sex * @return */

@Select(\"\")

List 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\ * @param user * @return */

@PostMapping

public ApiResult save(@RequestBody User user) { userRepository.saveUser(user); return ApiResult.success(user); }

/**

* 批量保存

* http://localhost:8080/user/list * [

* {\"nickName\":\"kingboy\ * {\"nickName\":\"kingboy\ * {\"nickName\":\"kingboy\ * ]

* @param users * @return */

@PostMapping(value = \"/list\")

public ApiResult save(@RequestBody List users) { userRepository.saveUserList(users); return ApiResult.success(users); }

/**

* 更新单个⽤户

* http://localhost:8080/user * {\"id\":\"1\ * @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 pageInfo = PageHelper.startPage(pageParam.getPage(), pageParam.getSize()); List users = userRepository.listUser();

//实际使⽤时,最后⼀个参数传⼊要转换的类型DTO

PageResult 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 ids) { List 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 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 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\ void saveUser(User user);

/**

* 批量保存⽤户 * @param users */

@Insert(\"\")

@Options(useGeneratedKeys = true) void saveUserList(List users);

//使⽤set标签进⾏动态set,要注意条件判断:没被删除的⽤户才可以更新数据 @Update(\"\")

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\

@Result(column = \"phone_number\ })

User get(Long id);

//分页查询⽤户

@Select(\"SELECT * FROM `user`\") List listUser();

/**

* 通过id集合查询⽤户 * @param ids * @return */

@Select(\"\")

List listUserByIds(List ids);

/**

* 根据条件查询⽤户

* 注意其中nickName模糊查询的处理⽅法 * 注意其中关于⽣⽇的区间判断 * @param userQueryDTO * @return */

@Select(\"\")

List queryByCondition(UserQueryDTO userQueryDTO);

/**

* 如果age有值,通过age查询 * 如果age没有值,则通过sex查询

* 如果age和sex都没值,则查询所有status为UNLOCK的⽤户 * @param age * @param sex * @return */

@Select(\"\")

List getByOrderCondition(@Param(\"age\") Integer age, @Param(\"sex\") Sex sex);}

  

因篇幅问题不能全部显示,请点此查看更多更全内容