什么是MyBatis?
• MyBatis是⼀款优秀的 持久层 框架,⽤于简化JDBC的开发。
• MyBatis本是 Apache的⼀个开源项⽬iBatis,2010年这个项⽬由apache迁移到了google code,并 且改名为MyBatis 。2013年11⽉迁移到Github.
• 官⽹:MyBatis中⽂⽹ 在上⾯我们提到⼀个词:持久层
• 持久层:指的就是持久化操作的层, 通常指数据访问层(dao), 是⽤来操作数据库的.
简单来说 MyBatis 是更简单完成程序和数据库交互的框架,也就是更简单的操作和读取数据库⼯具
MyBatis入门
mybatis操作数据库的步骤:
1. 准备工作(创建springboot工程,数据库表准备,实体类等)
2. 引入mybatis相关依赖,配置mybatis数据库连接信息
3. 通过注解或者XML文件编写SQL语句
4. 测试
准备工程
为了了导入mybatis,必须加入mybatis framework和数据区driver,如果是MySQL,则加入MySQLdriver。
项⽬⼯程创建完成后,⾃动在pom.xml⽂件中,导⼊Mybatis依赖和MySQL驱动依赖
配置数据库连接字符串
为了通过mybatis连接数据库,需要数据库配置以下相关参数:
1. MySQL启动类
2. 用户名
3. 密码
4. 数据库连接字符串
我自己的配置信息: spring: datasource: url: jdbc:mysql://localhost:3306/mybatis_test?allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8 username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: configuration: map-underscore-to-camel-case: true mapper-locations: classpath:mapper/UserInfoMapperXML.xml持久层代码
持久层代码放在mapper中,这也就是我们Dao层的另一种写法。
其中,resource文件夹中的mapper,为src文件夹中mapper的xml文件映射。一个数据库操作接口对应着XML文件中的一条sql语句。我们在后面详细介绍。
两种Mybatis的操作方法
1. 使用注解
通过注解直接操作数据库
package com.spring.mybatis.mapper; import com.spring.mybatis.model.UserInfo; import org.apache.ibatis.annotations.*; import org.springframework.stereotype.Component; import java.util.List; @Mapper public interface UserInfoMapper { @Select("select * from user_info") List<UserInfo> selectAll(); @Select("select * from User_info where id=#{id}") UserInfo selectById(int id); @Options(useGeneratedKeys = true, keyProperty = "id") @Insert("insert into user_info(username, password, age) values(#{username}, #{password}, #{age})") Integer insertUser(UserInfo userInfo); @Delete("delete from user_info where id=#{id}") Integer deleteUser(int id); @Update("update user_info set delete_flag =#{delete_flag},phone=#{phone} where id=#{id}") Integer updateUser(int id, int delete_flag, String phone); }例如:@Select用于操作select语句,@Delete用于操作delete语句。在注解的括号中直接写入SQL语句,放在接口中定义的抽象方法上。
对于调用这个接口的其他类(层),只需要实例化这个接口,然后调用相关抽象方法即可。
package com.spring.mybatis.service; import com.spring.mybatis.mapper.UserInfoMapper; import com.spring.mybatis.model.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service //service层 public class UserService { @Autowired private UserInfoMapper userInfoMapper; //实例化mapper接口 public List<UserInfo> getAllUsers() { //调用接口中的方法 return userInfoMapper.selectAll(); } public UserInfo selectById(int id) { //调用接口中的方法 return userInfoMapper.selectById(id); } public Integer insertUser(UserInfo userInfo) { //调用接口中的方法 System.out.println(userInfo.getId()); return userInfoMapper.insertUser(userInfo); } }2. XML文件
XML文件实现Mybatis操作原理如下,interface方法定义和xml方法实现相互映射,共同组成数据持久层mapper:
import com.example.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserInfoXMlMapper { List<UserInfo> queryAllUser(); }操作
首先,配置连接字符串和Mybatis
application.yml⽂件, 配置内容如下
# 数据库连接配置 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/mybatis_test? characterEncoding=utf8&useSSL=false username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver # 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件 mybatis: mapper-locations: classpath:mapper/**Mapper.xml #这里是xml文件的位置随后,添加mapper接口
import com.example.demo.model.UserInfo; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface UserInfoXMlMapper { List<UserInfo> queryAllUser(); }随后,添加UserInfoXMLMapper.xml文件,放在resource文件夹中的mapper文件夹
初始化xml文件夹配置:
<?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.spring.mybatis.mapper.UserInfoMapperXML"> </mapper>注意:xml文件位置要和yml配置文件中定义的路径相对应
Mybatis的操作技巧
1. 打印日志
在yml配置文件中配置如下代码,即可打印日志
mybatis: configuration: # 配置打印 MyBatis⽇志 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl看到SQL的执行内容,参数传递和执行结果:
2. 参数传递
一般而言,SQL语句中的内容不能写成固定值,因为如果这样写每次查找都要修改值,例如查找id=4的用户,对应的SQL就是:select * from user_info where id=4。但是这样的话, 只能查找id=4 的数据, 所以SQL语句中的id值不能写成固定数值
解决方案:在queryById方法中添加⼀个参数(id),将方法中的参数,传给SQL语句
@Select("select username, `password`, age, gender, phone from user_info where id= #{id} ") //此处用的是传值,而非固定值 UserInfo queryById(Integer id);也可以通过 @Param , 设置参数的别名, 如果用 @Param 设置别名, #{...}的属性名必须和 @Param 设置的⼀样
@Select("select username, `password`, age, gender, phone from user_info where id= #{userid} ") UserInfo queryById(@Param("userid") Integer id);利用对象传递参数
如果设置了 @Param 属性, #{...} 需要使⽤ 参数.属性 来获取
@Insert("insert into user_info (username, `password`, age, gender, phone) values (#{userInfo.username},#{userInfo.password},#{userInfo.age},# {userInfo.gender},#{userInfo.phone})") //因为使用了@Param,在SQL获取参数时需要加上"userInfo." Integer insert(@Param("userInfo") UserInfo userInfo);使用对象传递参数的好处
好处1:自动匹配参数
@Insert("insert into user_info (username, `password`, age, gender, phone) values (#{username},#{password},#{age},#{gender},#{phone})") Integer insert(UserInfo userInfo); 直接传入UserInfo类,自动匹配参数好处2:返回主键
Insert 语句默认返回的是 受影响的⾏数。但有些情况下, 数据插⼊之后, 还需要有后续的关联操作, 需要获取到新插⼊数据的id
如果想要拿到自增id, 需要在Mapper接口的方法上添加⼀个Options的注解
@Options(useGeneratedKeys = true, keyProperty = "id") @Insert("insert into user_info (username, age, gender, phone) values (# {userInfo.username},#{userInfo.age},#{userInfo.gender},#{userInfo.phone})") Integer insert(@Param("userInfo") UserInfo userInfo);useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内 部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字 段),默认值:false.
keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使用 getGeneratedKeys 的返回值或 insert 语句的 selectKey 子元素设置它的值,默认值:未设置(unset)
注意事项:如果SQL中的字段和我们类属性名称不一致,将会发生匹配不上字段的情况。
如下图,框中的三个参数长相不同,无法相互匹配
解决方案:
1. 起别名
直接在SQL语句中起别名
@Select("select id, username, `password`, age, gender, phone, delete_flag as deleteFlag, " + "create_time as createTime, update_time as updateTime from user_info") public List<UserInfo> queryAllUser();2. 结果映射
@Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from user_info") //此处进行结果映射,id = "resultMap"指的是这条结果映射的id名为resultMap,其他地方如果需要同样的映射,可以直接调用 @Results(id = "resultMap",value = { @Result(column = "delete_flag",property = "deleteFlag"), @Result(column = "create_time",property = "createTime"), @Result(column = "update_time",property = "updateTime") }) List<UserInfo> queryAllUser(); @Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time " + "from user_info where id= #{userid} ") //此处直接调用上文定义的结果映射id @ResultMap(value = "resultMap") UserInfo queryById(@Param("userid") Integer id);3. 配置文件开启驼峰命名(推荐)
mybatis: configuration: map-underscore-to-camel-case: true #配置驼峰⾃动转换3. #{} 和 ${}
直接说差别:#{}为预编译SQL,${}为直接字符串拼接SQL(即时SQL)
预编译SQL可以提高效率,编译⼀次之后会将编译后的SQL语句缓存起来,后面再次执行这条语句时,不会再次编译 (只是输⼊的参数不同), 省去了解析优化等过程, 以此来提⾼效率
预编译SQL可以防止SQL注入。比如sql 注入代码: ' or 1='1,如果使用${}就会被sql注入,而#{}就不会。
4. 切换数据库连接池
数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用⼀个现有的数据库连接,而不是再重新建⼀个.
常⻅的数据库连接池: C3P0,DBCP,Druid,Hikari
Mybatis操作数据库进阶
1. 动态SQL
if标签
注册分为两种字段:必填字段和非必填字段,那如果在添加用户的时候有不确定的字段传入,程序应该如何实现呢?这个时候就需要使⽤动态标签 来判断了,如添加的时候性别 gender 为非必填字段,具体实现如下:
<insert id="insertUserByCondition"> INSERT INTO userinfo ( username, `password`, age, <if test="gender != null"> gender, </if> phone) VALUES ( #{username}, #{age}, <if test="gender != null"> #{gender}, </if> #{phone}) </insert>trim标签
之前的插入用户功能,只是有⼀个 gender 字段可能是选填项,如果有多个字段,⼀般考虑使用标签结合标签,对多个字段都采取动态生成的方式。
标签中有如下属性:
• prefix:整个语句块,以prefix的值作为前缀
• suffix:整个语句块,以suffix的值作为后缀
• prefixOverrides:整个语句块要去除掉的前缀
• suffixOverrides:整个语句块要去除掉的后缀
还有如:
where标签
set标签
foreach标签
include标签
等,在这里不再详细讲解。
总之,这些标签可以让SQL语句更加灵活,适应不同的操作条件。