什么是MyBatis
项目的DEMO代码:https://github.com/heyu52/-spring-cloud
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAOs)。这里我主要讲的是注解方式。
官方参考文档:http://www.mybatis.org/mybatis-3/zh/index.html
特点
- 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
- 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
- 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
- 提供映射标签,支持对象与数据库的orm字段关系映射
- 提供对象关系映射标签,支持对象关系组建维护
- 提供xml标签,支持编写动态sql。
创建项目
SQL中我们选择mybatis与Mysql,stringboot 的版本2.1.6
配置数据库连接
spring.datasource.url=jdbc:mysql://localhost:3306/Spring?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=csdn
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
项目可以运行起来没有报错。数据库我们依然是使用上节的数据库。
创建Model
package com.csdn.demo.model;
public class User {
private Long id;
private String name;
private int age;
private String sex;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return ("id=" + this.id + "name=" + this.name + ",age=" + this.age + ",pass=" + this.sex);
}
public User() {
}
public User(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
}
指定实体类路径
我要在 application.properties 中要指定model包的位置
增加一个配置项:
mybatis.type-aliases-package=com.csdn.demo.model
建接口Mapper
我们新增一个查询用户的接口方法,注意里面脚本使用了传参。在 SQL 中使用 #{id} 来接收同名参数。
package com.csdn.demo.mapper;
import com.csdn.demo.model.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(Long id);
}
#打印执行脚本
logging.level.com.csdn.demo.mapper=debug
新建Controller
package com.csdn.demo.web;
import com.csdn.demo.mapper.UserMapper;
import com.csdn.demo.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController {
@Autowired
private UserMapper userMapper;
@RequestMapping("/getUserById")
public User getList(long id) {
User user=userMapper.getUserById(id);
return user;
}
}
运行项目,浏览器输入:http://127.0.0.1:8080/getUserById?id=13
结果就是我们想要的了。
上面我们的数据库表的列名和我们类的名字是一致的,所以可以返回完整的实体,但是,如果我们的表的列名和类的属性定义不一样,那我们应该使用下面的方式来使之对应起来。
@Select("SELECT * FROM user WHERE id = #{id}")
@Results({
@Result(property = "name", column = "name")
})
User getUserById(Long id);
我们增加Results注解,可以指定model属性和数据表的列对应关系。
@Param
当我们的参数和脚本的参数不一致时,我们要使用@Param
我们新增一个接口方法
@Select("SELECT * FROM user WHERE sex = #{sex} and age > #{age}")
List<User> getUserByNameAndAge(@Param("sex") String userSex, @Param("age") int userage);
UserController中新增测试方法
@RequestMapping("/getUserByNameAndAge")
public List<User> getUserByNameAndAge(String userSex, int userage) {
List<User> users=userMapper.getUserByNameAndAge(userSex,userage);
return users;
}
运行项目,浏览器输入:http://127.0.0.1:8080/getUserByNameAndAge?userSex=%E7%94%B7&userage=10
查找大于10岁的男用户
@Map
如果参数不能确实有多少个,我们可以使用Map来传递。
新增map接口方法
@Select("SELECT * FROM user WHERE sex = #{sex} and age > #{age}")
List<User> getUserByMapParam(Map<String,Object> args);
新增UserController方法
@RequestMapping("/getUserByMapParam")
public List<User> getUserByMapParam() {
Map param= new HashMap();
param.put("sex","女");
param.put("age",10);
List<User> users=userMapper.getUserByMapParam(param);
return users;
}
运行项目,浏览器输入:http://127.0.0.1:8080/getUserByMapParam
传递实体对象
我们新创建一个插入用户的接口方法
@Insert("INSERT INTO user(name,sex,age) VALUES(#{name}, #{sex}, #{age})")
void insertUser(User user);
新增UserController方法
@RequestMapping("/insertUser")
public int getList() {
User user = new User();
user.setName("20190630");
user.setSex("男");
user.setAge(99);
userMapper.insertUser(user);
return 1;
}
运行项目,浏览器输入:http://127.0.0.1:8080/insertUser
在执行时,系统会自动读取对象的属性并值赋到同名的 #{xxx} 中。
前面用到了@Select,@Insert,当然我们肯定能想到,还有@Update,@Delete
我在DEMO中会给出例子,这里就不再细述了,用法和上面基本一致。
接口方法
@Update("UPDATE user SET name=#{name} WHERE id =#{id}")
void updateUser(User user);
@Delete("DELETE FROM user WHERE id =#{id}")
void deleteUser(Long id);
UserController
@RequestMapping("/updateUser")
public int updateUser() {
User user = new User();
user.setId(13L);
user.setName("201906302123");
userMapper.updateUser(user);
return 1;
}
@RequestMapping("/deleteUser")
public int deleteUser() {
userMapper.deleteUser(12L);
return 1;
}
动态 SQL的实现
MyBatis 最大的特点是可以灵活的支持动态 SQL,在注解版中提供了两种方式来支持,第一种是使用注解来实现,另一种是提供 SQL 类来支持。
注解
接口方法
@Update({"<script> ",
"update user " ,
"<set>" ,
" <if test='name != null'>name=#{name},</if>" ,
" <if test='age > 99 '>age=#{age},</if>" ,
" </set> ",
"where id=#{id} " ,
"</script>"})
void updateUserByScript(User user);
UserController
@RequestMapping("/updateUserByScript")
public int updateUserByScript() {
User user = new User();
user.setId(13L);
user.setName("2019");
user.setAge(100);
userMapper.updateUserByScript(user);
return 1;
}
这种方式写起来很痛苦,不推荐。
SQL 构建类
新增UserParam类
package com.csdn.demo.mapper;
public class UserParam {
private String userName;
private String userSex;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserSex() {
return userSex;
}
public void setUserSex(String userSex) {
this.userSex = userSex;
}
}
新增UserSql类
package com.csdn.demo.mapper;
import org.apache.ibatis.jdbc.SQL;
import org.springframework.util.StringUtils;
public class UserSql {
public String getUserCount(UserParam userParam) {
String sql = new SQL() {{
SELECT("COUNT(1)");
FROM("user");
if (!StringUtils.isEmpty((userParam.getUserName()))) {
WHERE("name=#{userName}");
}
if (!StringUtils.isEmpty((userParam.getUserSex()))) {
WHERE("sex=#{userSex}");
}
}}.toString();
System.out.println("sql :" + sql);
return sql;
}
}
接口方法
@SelectProvider(type = UserSql.class, method = "getUserCount")
int getUserCount(UserParam userParam);
UserController
@RequestMapping("/getUserCount")
public long getUserCount() {
UserParam userParam=new UserParam();
userParam.setUserName("csdn");
userParam.setUserSex("男");
long count=userMapper.getUserCount(userParam);
return count;
}
运行项目,浏览器输入:http://127.0.0.1:8080/getUserCount
说实话,这两种方式都好费劲。