代码⽰例可以参考个⼈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 //获取分页信息演⽰, 实际项⽬中⼀般会封装为⾃⼰的返回体。 int pageNum = pageInfo.getPageNum(); int pageSize = pageInfo.getPageSize(); long total = pageInfo.getTotal(); List //repository@Mapper public interface UserRepository { //分页查询⽤户 @Select(\"SELECT * FROM `user`\") List 五、动态标签 熟悉Mybatis的同学⼀定对Mybatis的动态SQL很了解,解决了我们编写动态SQL的很多痛点。接下来介绍以下Mybatis常⽤的动态sql的注解写法,其实和xml是⼏乎完全⼀致的。 ⾸先在注解中使⽤动态sql时,我们需要为sql加上标签,这时候mybatis才会解析⾥⾯的标签。1. ⽤来对参数进⾏判断,若为真,则包裹的sql语句⽣效。条件中可以使⽤and作连接 分页查询⽤户,如果sex有值,则查询相应sex的所有⽤户,sex没值则查询所有 @Select(\"\") List 例如传⼊的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 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 其中的⽤户实体等没有贴出来,太乱了,完整⽰例代码可以参考⽂章开头的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 /** * 更新单个⽤户 * 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 //实际使⽤时,最后⼀个参数传⼊要转换的类型DTO PageResult /** * 通过id集合查询⽤户,这⾥就不做分页了。 * http://localhost:8080/user/ids * [1,3] * @return */ @PostMapping(\"/ids\") public ApiResult getUserByIds(@RequestBody List /** * 通过查询条件赖查询⽤户,这⾥也不做分页了 * 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 /** * 根据条件的顺序来查询⽤户 * 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 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 //使⽤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 /** * 通过id集合查询⽤户 * @param ids * @return */ @Select(\"\") List /** * 根据条件查询⽤户 * 注意其中nickName模糊查询的处理⽅法 * 注意其中关于⽣⽇的区间判断 * @param userQueryDTO * @return */ @Select(\"\") List /** * 如果age有值,通过age查询 * 如果age没有值,则通过sex查询 * 如果age和sex都没值,则查询所有status为UNLOCK的⽤户 * @param age * @param sex * @return */ @Select(\"\") List 因篇幅问题不能全部显示,请点此查看更多更全内容