Spring Boot (9) mybatis全注解化
ORM对比图
框架对比 | Spring JDBC | Spring Data Jpa | Mybatis |
---|---|---|---|
性能 | 性能最好 | 性能最差 | 居中 |
代码量 | 多 | 少 | 多 |
学习成本 | 低 | 高 | 居中 |
推荐指数 | ❤❤❤ | ❤❤❤❤❤ | ❤❤❤❤❤ |
首先在pom.xml中添加引用
<!-- 引入mybatis --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <!-- mybatis分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.1.1</version> </dependency>
基本SQL操作
spring boot已经自动实现了mybatis所有配置,直接写dao接口即可
package com.david.dao; import com.david.bean.Cat; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; //声明一个mybatis的dao接口,会被spring boot扫描到 @Mapper public interface MyBatisDao { //声明一个查询方法,相应的增删改使用@Insert @Delete @Update @Select("select * from Cat where id = #{id}") List<Cat> findById(Cat param); }
扫描Mapper
可以在配置类加上@MapperScan("com.david.dao") 注解,扫描dao包中的所有接口,替代在每个dao中写@Mapper注解,不过这样会提高耦合度。而@Mapper可以与dao自成一体,与@Controller、@Service遥相呼应,整体结构更优雅。
驼峰命名
在properties添加以下配置,在执行查询后,可以讲数据库的NN_NN格式字段在java结果集对象中自动转换成驼峰命名参数。
mybatis.configuration.mapUnderscoreToCamelCase=true
结果映射@Results
如果结果集不是java对象而是map,map中的列名回合数据库中的NN_NN一样,是不会自动驼峰转换的,可以使用@Result来指明结果映射,同时也适用java对象。
@Mapper public interface MyBatisDao { @Select("select * from Cat where id = #{id}") List<Cat> findById(Cat param); @Results({ @Result(property = "catName", column = "cat_name"), @Result(property = "catAge", column = "cat_age") }) @Select("select * from Cat") List<Map> findAll(Cat param); }
使用List<Map>不用去维护pojo,适于用数据库字段不确定或经常变化的场景。但是程序的可读性、可维护性不如List<Cat>。
可复用的@Results
声明时给id赋值为cat
public interface MyBatisDao { @Results(id="cat",value={ @Result(property = "catName", column = "cat_name"), @Result(property = "catAge", column = "cat_age") }) @Select("select * from Cat") List<Map> findAll(Cat param); @ResultMap("cat") @Select("select * from Cat where id = #{id}") List<Cat> findById(Cat param); }
在其他方法中直接@ResultMap("cat")即可重复适用id为cat的结果映射
打印SQL日志到控制台
在application.properties中添加以下配置
logging.level.你的包名.mybatis接口包=debug
logging.level.org.springframework=WARN logging.level.com.david.dao.MyBatisDao=DEBUG #输出日志文件,默认不输出 logging.file=logs/spring-boot-logging.log #修改日志级别,默认为INFO logging.level.root=DEBUG
执行SQL时,会在控制台打印sql日志,并记录到日志里去
@RestController public class HelloController { @Resource private MyBatisDao myBatisDao; @GetMapping("/findAll") public List<Map> findAll() { return myBatisDao.findAll(); }
分页
分页逻辑写在service层
@Service @Transactional public class MyBatisService { @Resource private MyBatisDao myBatisDao; public Page<Cat> findAll(){ //分页插件:查询第1页,每页10行 Page<Cat> page = PageHelper.startPage(1,10); myBatisDao.findAll(); //数据表的总行数 page.getTotal(); //分页查询结果的总行数 page.size(); //第一个cat对象 page.get(0); return page; } }
controller
@RestController public class HelloController { @Autowired private MyBatisService myBatisService; @GetMapping("/findAll") public Page<Cat> findAll() { return myBatisService.findAll(); }
执行原理:PageHelper.startPage会拦截下一个sql,也就是mybatisDao.findAll()的sql。并且根据当前数据库的语法,把这个sql改造成一个高性能的分页sql,同时还会查询该表的总行数。
PageHelper.startPage最好和myBatisDao.findAll()紧跟在一起,中间不要有别的逻辑,否则可能出现bug。
Page<Cat> page:相当于一个list集合,findAll()方法查询完成后回给page对象的相关参数赋值
回传ID
数据库的id主键是自增长的,添加一条数据后,想得到这条自动增长的id,在dao层添加以下代码
@Mapper public interface MyBatisDao { @Insert("insert into Cat (cat_name,cat_age) values (#{catName},#{catAge})") @Options(useGeneratedKeys = true,keyProperty = "id") int insert(Cat cat); }
useGeneratedKeys=true:获取数据库生成的主键
keyProperty="id":把主键存入Cat cat对象的id属性
service
public int insert(Cat cat){ return myBatisDao.insert(cat); }
controller
@GetMapping("/addCat") public int insert(){ Cat cat = new Cat(); cat.setCatAge(18); cat.setCatName("mimi"); myBatisService.insert(cat); return cat.getId(); //回传id }
存储过程
创建一个mysql存储过程,传入一个id值,根据这个id查询出name并传出参数
CREATE DEFINER=`root`@`localhost` PROCEDURE `helloPROC`(IN id_in int,out name_out varchar(10)) BEGIN select cat_name into name_out from cat where id = id_in; END
dao层
mode=IN:传入参数,就是cat.id
mode=OUT:传出参数,就是cat.catName
StatementType.CALLABLE:说明这是一个存储过程
@Select("call helloPROC(#{id,mode=IN,jdbcType=INTEGER},#{catName,mode=OUT,jdbcType=VARCHAR})") @Options(statementType = StatementType.CALLABLE) void call(Cat cat);
service层
public void call() { Cat cat = new Cat(); cat.setId(2); myBatisDao.call(cat); System.out.print(cat.getCatName()); }
调用方法 返回tom.