Mybatis入门
一、mybatis的快速入门
1、创建springboot项目
- 直接选择必须的依赖:
MyBatis Framework
和MySQL Driver
- 在项目下创建
pojo
包,用来存放数据库表对应的实体类
2、配置连接信息
- 在springboot项目的配置文件中
application.properties
写入一下信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/exe01
spring.datasource.username=root
spring.datasource.password=123456
3、在项目中再创建一个mapper
包
- 内部用来存放创建实体类对应的实现接口(操作数据库)
示例:
@Mapper // 在运行时,会自动生成该接口的实现类对象(代理对象),并且将该对象交给IOC容器管理
public interface StudentMapper {// 查询所有用户信息@Select("select * from ghr_student")public List<Student> list();
}
4、进行测试这个快速入门程序
- 在
springboot
项目的Test
程序下- 通过
@Autowired
注入我们写的操作数据库的mapper
接口 - 创建一个测试方法,使用注入的接口获取数据库中的信息,并遍历打印出来
- 通过
示例:
@SpringBootTest
class SpringMybatisQuickstartApplicationTests {@Autowiredprivate StudentMapper studentMapper;@Testvoid contextLoads() {List<Student> list = studentMapper.list();for (Student student : list) {System.out.println(student);}}}
运行这个测试方法,就可以看到:
数据库中的信息被遍历出来了!
二、数据库连接池
- 数据库连接池是个容器,负责分配、管理数据库连接
(Connection)
- 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个
- 释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏
优势:
- 资源重用
- 提升系统响应速度
- 避免数据库连接遗漏
数据库连接池的切换
- 目前
springboot
项目自带的是Hikari
连接池,如果需要切换连接池则可以通过
方法一:添加依赖
在pom
文件中添加其他数据库连接池的依赖即可。
示例:
如果要切换成Druid
数据库连接池,只需要在pom
文件中添加:
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-3-starter</artifactId><version>1.2.20</version>
</dependency>
方法二:修改配置文件
在springboot
的配置文件application.properties
的数据库配置信息修改成:
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/exe01
spring.datasource.druid.username=root
spring.datasource.druid.password=123456
三、使用lombok
工具包
- 使用
lombok
工具包简化pojo
包中的实体类 Lombok
一个实用的Java
类库,能通过注解的形式自动生成构造器、getter/setter
、equals
、hashcode
、toString
等方法,并可以自动化生成日志变量,简化java
开发、提交效率。
注解 | 作用 |
---|---|
@Getter/@Setter | 为所有的属性提供get/set方法 |
@ToString | 会给类自动生成易阅读的toString 方法 |
@EqualsAndHashCode | 根据类所拥有的非静态字段自动重写equals方法和hashcode方法 |
@Data | 提供了更综合的生成代码功能(@Getter+@Setter+@ToString+@EqualsAndHashCode) |
@NoArgsConstructor | 为实体类生成无参的构造器方法 |
@AllArgsConstructor | 为实体类生成除了static修饰的字段之外带有各参数的构造器方法 |
- 但是在
springboot
项目中使用时,需要在pom
文件中添加依赖:
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId>
</dependency>
这样我们就可以完成简化实体类的目的了:
import lombok.*;//@Getter
//@Setter
//@ToString
//@EqualsAndHashCode
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {private String Sno;private String Sname;private String Ssex;private Integer Sage;private String Sdept;}
注意:
@Data
中不包括空参构造和有参构造,因此自己添加相应的注解!
四、增删改查操作
1、参数占位符
#{…}
- 执行
SQL
时,会将#{…}
替换为?
,生成预编译SQL
,会自动设置参数值 - 使用时机:参数传递,都使用
#{…}
- 执行
${…}
- 拼接
SQL
。直接将参数拼接在SQL
语句中,存在SQL
注入问题,而且每次都需要重新编译 - 使用时机:如果对表名、列表进行动态设置时使用
- 拼接
2、删除操作
- 接口的定义:
@Delete("delete from emp where id = #{id}")
public void delete(Integer id);
// 如果定义的返回值是int 则返回的是受影响的行数
注意事项:
如果mapper接口方法形参只有一个普通类型的参数,#{…}里面的属性名可以随便写,如:#{id}、#{value}。但是还是建议不要修改。
- 像这种根据形参动态改变
SQL
语句的,使用的是预编译SQL
,在sql语句中的占位符就是#{…}
(类似于JDBC中的?
占位符) - 要查看
sql
语句的执行过程,可以将mybatis
的日志打印出来:在application.properties
中,添加配置信息,打开mybatis
的日志,并指定输出到控制台
# 指定mybatis输出日志的位置,输出控制台
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
这样之后,我们运行测试示例,就可以在控制台看到:
3、新增操作
- 如果插入的为多个参数,我们可以使用实体类对象来将多个参数封装起来,然后在
sql
语句中我们就可以使用#{…}
的形式来获取这个对象当中的属性 - 接口的定义:
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +"values(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);
4、主键回显
- 描述:在数据添加成功后,需要获取插入数据库数据的主键
- 实现:
只需在注解的sql
语句上,新加一个注解@Options(keyProperty="id", useGeneratedKets=true)
,这样就会将自动生成的主键值,赋值给自定义对象的id
属性,这样就可以通过新创建的这个自定义对象的GetId()
方法获取此主键值
@Options(keyProperty = "id", useGeneratedKeys = true)
@Insert("insert into emp(username, name, gender, image, job, entrydate, dept_id, create_time, update_time) " +"values(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
public void insert(Emp emp);
5、更新操作
- 更新操作其实也和新增操作差不多,可以将需要修改的属性值封装到一个实体类对象中,然后可以在
sql
语句中使用#{…}
的形式来获取这个对象当中的属性 - 接口的定义:
@Update("update emp set username = #{username}, name = #{name}, gender = #{gender}, image = #{image}," +"job = #{job}, entrydate = #{entrydate}, dept_id = #{deptId}, update_time = #{updateTime} where id = #{id}")
public void update(Emp emp);
6、查询操作
- 根据id查询该员工的所有数据,则可以将函数返回的数据类型改为相应的实体类对象即可
- 接口的定义:
@Select("select * from emp where id = #{id}")
public Emp select(Integer id);
注意:
- 如果实体类中的属性名和表的字段名不一致时,可能会导致该属性为空值,请看第7点即可
7、数据封装
-
实体类属性名和数据库查询返回的字段名一致,
mybatis
会自动封装 -
如果实体类属性名和数据库表查询返回的字段名不一致,不能自动封装
-
解决方法:
方案一:给sql语句的字段起别名,让别名与实体类属性一致
@Select("select id, username, password, name, gender, image, job, entrydate, dept_id deptId, create_time createTime, update_time updateTime from emp where id = #{id}")
public Emp select(Integer id);
方案二:通过@Results
,@Result
注解手动映射封装
@Results({@Result(column = "dept_id", property = "deptId"),@Result(column = "create_time", property = "createTime"),@Result(column = "update_time", property = "updateTime")})
@Select("select * from emp where id = #{id}")
public Emp select(Integer id);
映射关系:
column
是表中的字段名,property
是类中的属性名
方案三:开启mybatis
的驼峰命名自动映射开关(a_cloumn --> aCloumn)
只需在主配置文件application.properties
中写入:
mybatis.configuration.map-underscore-to-camel-case=true
8、条件查询
- 如果遇到要进行多个条件查询时,可以通过
and
进行连接 - 接口的定义:
@Select("select * from emp where name like '%${name}%' and gender = #{gender} " +"and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
注意:
字符串中不能直接使用
#{…}
当参数占位符涉及到在引号内部时,(例如上面
name
的模糊查询)此时不能使用#{…}
这个参数占位符,它不可以变成?
,所以我们需要使用${…}
这个占位符,拼接我们的sql
语句(例如:如果传入的name
是张,则拼接后就是like '%张%'
,就会达到目的)
- 如果要想使用
#{…}
的话,可以使用sql
语句的concat()
字符串拼接函数:
@Select("select * from emp where name like concat('%', #{name}, '%') and gender = #{gender} " +"and entrydate between #{begin} and #{end} order by update_time desc")
public List<Emp> list(String name, Short gender, LocalDate begin, LocalDate end);
五、XML映射文件
-
可以写
Mapper
接口相应的XML
映射文件,用来封装sql
语句(这样面对复杂的sql语句时,就比注解显得更有优势了) -
XML映射文件的规范:
-
XML映射文件的名称与
Mapper
接口的名称一致,并且将XML映射文件和Mapper
接口放置在相同包下(同包同名)-
在
resources
目录下创建相同的包 -
在相同的包下,创建文件,名字与对应的Mapper一样,后缀为
.xml
-
并且在这个
xml
文件中写入: -
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-
-
XML映射文件的
namespace
属性为Mapper接口全限定名一致 -
XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致
-
六、动态SQL
-
随着用户输入或外部条件的变化而变化的SQL语句,我们称之为:动态SQL
-
例如:当多个条件查询语句时,只填写单个条件时,即仅进行这个条件的查询,所以此时就需要动态SQL实现
我们可以将上述EmpMapper.xml
文件进行修改成:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.springmybatisstart01.mapper.EmpMapper">
<!-- resultType:单条记录所封装的类型--><select id="list" resultType="com.springboot.springmybatisstart01.pojo.Emp">select * from emp<where><if test="name != null">name like concat('%', #{name}, '%')</if><if test="gender != null">and gender = #{gender}</if><if test="begin != null and end != null">and entrydate between #{begin} and #{end}</if></where>order by update_time desc</select>
</mapper>
注意:
and
不要去除!
- 例如:当进行更新数据操作时,需要选择性的修改数据,此时也要使用到动态SQL
在上面的<mapper>
标签中加入:
<select id="update">update emp<set><if test="username != null">username = #{username},</if><if test="name != null">name = #{name},</if><if test="gender != null">gender = #{gender},</if><if test="image != null">image = #{image},</if><if test="job != null">job = #{job},</if><if test="entrydate != null">entrydate = #{entrydate},</if><if test="deptId != null">dept_id = #{deptId},</if><if test="updateTime != null">update_time = #{updateTime}</if></set>where id = #{id}</select>
- 例如:进行批量删除操作时,需要通过多个
id
进行删除,此时也要使用到动态SQL
在上面的<mapper>
标签中加入:
<delete id="deleteByIds">delete from emp where id in<foreach collection="ids" item="id" separator="," open="(" close=")">#{id}</foreach>
</delete>
其中的<if>
、<where>
、<set>
、<foreach>
标签:
-
if:用于判断条件是否成立。使用
test
属性进行条件判断,如果条件为true
,则拼接SQL
-
where:
where
元素只会在子元素有内容的情况下才插入where
子句。而且会自动去除子句的开头的AND
或OR
-
set:动态地在行首插入
SET
关键字,并会删掉额外的逗号 -
foreach:用于遍历集合元素,内部包含五个属性(一般用于一些批量操作当中)
collection
:集合名称item
:集合遍历出来的元素/项separator
:每一次遍历使用的分隔符open
:遍历开始前拼接的片段close
:遍历结束后拼接的片段
-
例如:当面对一些重复的sql语句时,我们可以通过
<sql>
和<include>
标签进行sql
语句的复用
<sql id="commonSelect">select * from emp
</sql><!-- resultType:单条记录所封装的类型-->
<select id="list" resultType="com.springboot.springmybatisstart01.pojo.Emp"><include refid="commonSelect"/><where><if test="name != null">name like concat('%', #{name}, '%')</if><if test="gender != null">and gender = #{gender}</if><if test="begin != null and end != null">and entrydate between #{begin} and #{end}</if></where>order by update_time desc
</select>
- sql:定义可复用的
SQL
片段,定义id
用于唯一性标识 - include:通过属性
refid
,指定包含的sql
片段