MyBatis 是⼀款优秀的持久层框架,它⽀持⾃定义 SQL、存储过程以及⾼级映射。MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO(Plain Old Java Objects,普通⽼式 Java 对象)为数据库中的记录。
简单来说 MyBatis 是更简单完成程序和数据库交互的⼯具,也就是更简单的操作和读取数据库⼯具。
JDBC 的操作流程:
框架交互流程图:
、
MyBatis 也是⼀个 ORM 框架,ORM(Object Relational Mapping),即对象关系映射。在⾯向对象编程语⾔中,将关系型数据库中的数据与对象建⽴起映射关系,进⽽⾃动的完成数据与对象的互相转换:
数据库表(table)–> 类(class)
记录(record,⾏数据)–> 对象(object)
字段(field) --> 对象的属性(attribute)
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.4version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.38version>
<scope>runtimescope>
dependency>
如果是新项⽬创建 Spring Boot 项⽬的时候添加引⽤就可以了,如下图所示:
此步骤需要进⾏两项设置,数据库连接字符串设置和 MyBatis 的 XML ⽂件配置。
如果是 application.yml 添加如下内容:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/myjava?characterEncoding=utf-8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# MyBatis 的 XML 中保存是查询数据库的具体操作 SQL,配置如下:
mybatis:
mapper-locations: classpath:mapper/**Mapper.xml
configuration: # 配置打印 MyBatis 执行的 SQL
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
注意事项:
如果使⽤ mysql-connector-java 是 5.x 之前的使⽤的是“ com.mysql.jdbc.Driver ” ,如果是⼤于 5.x 使⽤的是“ com.mysql.cj.jdbc.Driver ” 。
下⾯按照后端开发的⼯程思路,也就是下⾯的流程来实现 MyBatis 查询所有⽤户的功能:
目录解构:
import lombok.Data;
@Data
public class Login {
private int uid;
private String username;
private String password;
private String power;//职位
public Login(){}
public Login(String username, String password, String power) {
this.username = username;
this.password = password;
this.power = power;
}
}
import com.model.Login;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LoginMapper {
List<Login> selectAll();
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.LoginMapper">
</mapper>
LoginMapper.xml 查询所有⽤户的具体实现 SQL:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mapper.LoginMapper">
<select id="selectAll" resultType="com.model.Login">
select * from userregister
</select>
</mapper>
对以上标签的说明:
其他:
import com.mapper.LoginMapper;
import com.model.Login;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class LoginService {
@Autowired
private LoginMapper loginMapper;
public List<Login> selectAll(){
return loginMapper.selectAll();
}
}
import com.model.Login;
import com.service.LoginService;
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
@RequestMapping("/login")
public class LoginController {
@Autowired
private LoginService loginService;
@RequestMapping("/selectAll")
public List<Login> selectAllLogin(){
return loginService.selectAll();
}
}
以上代码写完,整个 MyBatis 的查询功能就实现完了,接下来使⽤ postman 来测试⼀下。
对应使⽤ MyBatis 的标签如下:
Integer insert(Login login);
Integer updateByCondition(@Param("uid") Integer uid,@Param("password") String password);
Integer batchDelete(Integer uid) ;
</insert>
<insert id="insert" >
insert into userregister(username,password,power)
values(#{username},#{password},#{power})
</insert>
<update id="updateByCondition">
update userregister set password = #{password}
where uid = #{uid}
</update>
<delete id="batchDelete">
delete from userregister where uid = #{deleteId}
</delete>
预编译处理是指:MyBatis 在处理#{}时,会将 SQL 中的 #{} 替换为?号,使⽤ PreparedStatement 的 set ⽅法来赋值。直接替换:是MyBatis 在处理 ${} 时,就是把 ${} 替换成变量的值。
使⽤ ${sort} 可以实现排序查询,⽽使⽤ #{sort} 就不能实现排序查询了,因为当使⽤ #{sort} 查询时, 如果传递的值为 String 则会加单引号,就会导致 sql 错误。
sql 注⼊代码:“’ or 1='1”
<select id="select" resultType="com.model.Login">
select * from userregister where uid = ${uid}
</select>
这时查询会将所有的结果查询出来,因此⽤于查询的字段,尽量使⽤ #{} 预查询的⽅式。
like 使⽤ #{} 报错
<select id="findUserByName2" resultType="com.example.demo.model.User">
select * from userregister where username like '%#{username}%';
</select>
相当于: select * from userinfo where username like ‘%‘username’%’;
这个是不能直接使⽤ ${},可以考虑使⽤ mysql 的内置函数 concat() 来处理,实现代码如下:
<select id="findUserByName3" resultType="com.example.demo.model.User">
select * from userregister where username like concat('%',#{username},'%');
</select>
如果是增、删、改返回搜影响的⾏数,那么在 mapper.xml 中是可以不设置返回的类型的,然⽽即使是最简单查询⽤户的名称也要设置返回的类型。也就是说对于 查询标签来说⾄少需要两个属性:
绝⼤数查询场景可以使⽤ resultType 进⾏返回
<select id="selectAll" resultType="com.model.Login">
select * from userregister
</select>
resultMap 使⽤场景:
比如:
username改成name,password改成psw
<resultMap id="BaseMap" type="com.model.Login2">
<id property="id" column="uid"></id>
<result property="name" column="username"></result>
<result property="psw" column="password"></result>
<result property="power" column="power"></result>
</resultMap>
<select id="getUserByName" resultMap="com.mapper.UserMapper.BaseMap">
select * from userregister where username=#{name}
</select>
在多表查询时,如果使⽤ resultType 标签,在⼀个类中包含了另⼀个对象是查询不出来被包含的对象的,⽐如以下实体类:
@Data
public class Company {
private int id;
private String company_name;
private String region;
private String address;
}
@Data
public class Staff {
private int id;
private Company company;
private String staff_name;
private String sex;
private int age;
private String phone;
private String position;
private Date entry_time;
}
⼀对⼀的表映射,⼀对⼀映射要使⽤ 标签
<mapper namespace="com.mapper.StaffMapper">
<resultMap id="BaseMap" type="com.model.Staff">
<id property="id" column="id"></id>
<association property="company" resultMap="com.mapper.LoginMapper.BaseMap"></association>
</resultMap>
<select id="queryStaff" resultType="com.model.Staff">
select * from staff left join company_information on staff.company = company_information.company_name
</select>
</mapper>
使⽤ 标签,表示⼀对⼀的结果映射:
columnPrefix 属性:绑定⼀对⼀对象时,是通过 columnPrefix+association.resultMap.column 来映射结果集字段。 防止两个重名的字段。(上面没有)
<association property="company" resultMap="com.mapper.LoginMapper.BaseMap" columnPrefix=id_></association>
</resultMap>
一对多:
⼀对多需要使⽤ 标签,⽤法和 相同,
<collection property="alist" resultMap="com.mapper.LoginMapper.BaseMap"
columnPrefix="a_">
必填字段和⾮必填字段的填入
标签结合标签,对多个字段都采取动态⽣成的⽅式。
标签中有如下属性:
<insert id="insertByCondition">
<trim prefix="(" suffix=")" prefixOverrides="," suffixOverrides=",">
insert into userregister(username,password,
<if test="power!=null">,power</if>)
values(#{username},#{password},
<if test="power!=null">,#{power}</if>)
</trim>
传⼊的⽤户对象,根据属性做 where 条件查询,⽤户对象中属性不为 null 的,都为查询条件
根据传⼊的⽤户对象属性来更新⽤户数据,可以使⽤标签来指定动态内容。
<update id="updateByCondition">
update userregister
<set>
<if test="password!=null">
password = #{password}
</if>
</set>
<where>
uid = #{uid}
</where>
</update>
对集合进⾏遍历时可以使⽤该标签。标签有如下属性:
<delete id="batchDelete">
delete from userregister where uid in
<foreach collection="ids" open="(" close=")" separator="," item="deleteId">
#{deleteId}
</foreach>
</delete>