前言
Mybatis学习以及自己的理解
一、mybaits是什么?
1.1 ORM
mybatis是一种ORM框架,ORM是Object Relational Mapping的缩写,中文翻译过来就是对象关系映射。对象就是java对象,指的是通过Java对象与数据库表之间的映射关系将Java应用程序中的对象持久化到数据库的表中。
1.2 Mybatis概述
MyBatis 是一个支持自定义 SQL、存储过程以及高级映射的持久层框架。
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO映射成数据库中的记录。
1.3 对Mybatis概述的理解
自定义 SQL:sql语句可以进行灵活的修改,在使用JDBC的时候,sql语句和java代码是融合在一起,mybatis是将sql语句和java代码分开来,sql代码写xml文件里,此时sql语句的修改会非常方便。
例如:如果给的要求是如下,sql 代码如下
mybatis代码:可以根据条件不同,动态的变化执行的sql语句。
select id,username,age,gender form t_user
<where>
<if test="username != null and username != ''">
AND username = #{userName, jdbcType=VARCHAR}
</if>
</where>
存储过程:函数
高级映射:javabean和数据库对象的映射→输入映射和输出映射
输入参数映射:输入参数类型可以是 Map、List 等集合类型,也可以是基本数据类型和 POJO 类型。输入参数映射就是为sql语句提供参数的过程。下面的代码中#{id}就是提供输入映射。
输出结果映射:输出结果类型可以是 Map、 List 等集合类型,也可以是基本数据类型和 POJO 类型。输出映射对结果集进行封装的过程。下面的sql代码中,就是对查询出来的id,username,password,age,gender进行封装,比如下面的代码把这些结果封装在一个User对象里(resultType="com.form.User")。
<select id="selectUserById" resultType="com.form.User">
select id,username,password,age.gender from t_user where id = #{id}
</select>
MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集:下面是JDBC操作数据库的代码,可以看出,执行sql代码前都要连接数据库,最后都要释放资源,这样会很影响系统性能,这样的JDBC代码最好避免。mybatis就是使用了数据库连接池,避免了资源的浪费。手动设置参数,先创建一个Statement对象来将SQL语句发送到数据,然后执行sql语句的查询,这个查询过程是手动设置的。结果集的获取也是手动设置的,代码如下。如果查询条件发生变化,就要改sql代码,修改获取结果集的代码。总之就是代码发生变化的时候,使用JDBC代码非常麻烦,不够灵活,而mybatis避免了这些问题。
public void testGetConnection1() throws SQLException {
// 注册驱动
Driver driver = new com.mysql.jdbc.Driver();
// 建立连接
String url = "jdbc:mysql://localhost:3306/test";
Properties info = new Properties();
info.setProperty("user", "root");
info.setProperty("password", "root");
Connection con = driver.connect(url, info); //javaAPI,需要url和properties,得到连接对象
// 获取SQL语句执行平台
Statement stmt = con.createStatement(); //创建一个Statement对象来将SQL语句发送到数据库
String sql = "select * from t where id = 1";
// 执行SQL语句
ResultSet resultSet = stmt.executeQuery(sql); //查询
// 处理结果
if (resultSet.next()) {
int id = resultSet.getInt(1);
int a = resultSet.getInt(2);
int b = resultSet.getInt(3);
int c = resultSet.getInt(4);
System.out.printf("%d, %d, %d, %d", id, a, b, c);
}
// 关闭连接,释放资源
con.close();
}
MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJO映射成数据库中的记录:
mybatis有两种书写方式,xml形式或者注解形式,平时用到的大多是xml形式。
xml形式:进行mybatis的配置,写上接口文件,再写上xml对应的文件。
接口文件:
@Repository
public interface BusinessProductDao {
int insert(BusinessProduct record);
}
对应的xml文件:
<insert id="insert" parameterType="com.formssi.third.dto.BusinessProduct">
insert into business_product (product_id, product_name, state,belong_to_group
)
values (#{productId,jdbcType=VARCHAR}, #{productName,jdbcType=VARCHAR},
#{state,jdbcType=VARCHAR},#{belongToGroup,jdbcType=VARCHAR}
)
</insert>
注解形式:用@Select, @Insert, @Update and @Delete在接口上声明增删查改方法,@Resluts与<reslutMap>的作用相同,用来获取结果,用了注解以后,就不用xml文件了。
package com.concretepage;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
public interface VillageMapper {
@Results({
@Result(property = "vid", column = "id"),
@Result(property = "villageName", column = "name"),
@Result(property = "district", column = "district")
})
@Select("SELECT id, name, district from village WHERE id = #{id}")
Village selectVillage(int id);
@Insert("INSERT into village(name,district) VALUES(#{villageName}, #{district})")
void insertVillage(Village village);
@Update("UPDATE village SET name=#{villageName}, district =#{district} WHERE id =#{vid}")
void updateVillage(Village village);
@Delete("DELETE FROM village WHERE id =#{id}")
void deleteVillage(int id);
}
MyBatis 3 Annotation Example with @Select, @Insert, @Update and @Delete
二、mybatis入门
1.引入mybatis的配置
用的springboot参考的文章:SpringBoot整合Mybatis完整详细版_海岛拾贝的博客-CSDN博客_springboot mybatis
mybatis的xml文件详解:
第一行是编码方式,
第二行是mybatis的约束配置,
第三行的<mapper>元素是配置文件的根元素,包含一个namespace属性,namespace属性为<mapper>元素指定了唯一的命名空间,通常会设置成“包名+SQL映射文件名”的形式,com.form.third.dao都是包名,BusinessGroupDao是BusinessGroupDao.java这个文件名。在同一个映射文件下id不能重复--->namespace+id是唯一的-->能找到唯一与之对应的sql语句。在不同的映射文件下,id可以重复,因为namespace不一样,仍然可以保持namespace+id的唯一性。
子元素<select>中的信息是用于执行查询操作的配置,其id属性是<select>元素在映射文件中的唯一标识,映射文件中的getListByPage和xml文件中的id里的getListByPage相对应。parameterType属性用于指定传入参数的类型,这里表示传递给执行SQL的是一个BusinessGroupDto对象类型的参数。resultType属性用于指定返回结果的类型,返回的也是BusinessGroupDto对象类型的参数。
持久层接口文件:
@Repository
public interface BusinessGroupDao {
List<BusinessGroupDto> getListByPage(@Param("form") BusinessGroupDto businessGroup);
}
xml映射文件:
1<?xml version="1.0" encoding="UTF-8"?>
2<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
3<mapper namespace="com.form.third.dao.BusinessGroupDao">
4 <select id="getListByPage" parameterType="com.form.third.dto.BusinessGroupDto" resultType="com.form.third.dto.BusinessGroupDto">
select id,group_id,group_name,state from business_group
</select>
</mapper>
mybatis的核心对象:
2.mybatis配置文件元素:
转义字符:xml文件,&要使用转义字符&
空格:
>: > greater than
<: < less than
1.<properties>元素:properties(属性)
(1)单项配置:放在同一个配置文件mybatis.xml里进行配置
(2)引入配置文件:经常改动的值放在db.properties,其余仍然是放在mybatis.xml里。
2.<settings>元素:<settings>元素主要用于改变MyBatis运行时的行为,例如开启二级缓存、开启延迟加载等。(未完。。。。。)
3.<typeAliases>元素:
3.1 typeAliases(类型别名)
3.2包扫描:com.cskaoyan.bean.User,因为是包目录下的javabean,别名就可以直接是User的小写形式user。
mybatis系统定义的别名:可以直接在xml中文件中用系统给的别名就行了。
参考文章:mybatis定义别名_转身未来的博客-CSDN博客_mybatis 别名
4.<typeHandler>元素
MyBatis在预处理语句(Prepared Statement)中设置一个参数或者从结果集(Resultset)中取出一个值时,都要对参数和结果集进行处理,将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型),或者从数据库取出结果时将jdbcType转换为javaType。
5.<plugins>元素
MyBatis允许在已映射语句执行过程中的某一点进行拦截调用(通过插件来实现),<plugins>元素的作用就是配置用户所开发的插件。
6.<environments>元素
<environments>元素用于在配置文件中对数据库进行配置。default里放的是默认的环境id。<environments>里可以有很多个<environment>,就是可以配置多种数据库,<environment>里的id定义的数据库的环境id。然后就是事务管理和数据源的配置。<transactionManager>元素用于配置事务管理,它的type属性用于指定事务管理的方式,即使用哪种事务管理器;<dataSource>元素用于配置数据源,它的type属性用于指定使用哪种数据源。
mybatis提供了三种数据源类型,UNPOOLED:在每一次请求时会打开一次连接和关闭一次连接,对数据库资源是一种浪费。 POOLED:使用数据库连接池,每次请求去池里取就行了,就不用每次都创建和关闭,可以快速地响应请求。 JNDI:为了可以在EJB或应用服务器等容器中使用。
7.<mappers>元素
在配置文件中,<mappers>元素用于指定MyBatis映射文件的位置。有四种引入的方式,但是现在开发比较常用的是接口引入的方式。
使用class属性引入接口的全路径名称的使用规则:
1)接口名称和映射文件名称除拓展名要完全相同。
2)接口和映射文件要放同一个目录下。
参考文章:MyBatis框架中,使用class属性引入接口的全路径名称的使用规则和例子_我有一根魔法棒的博客-CSDN博客
(如下图所示,AccountMapper接口和AccountMapper映射文件同名并且在同一级classpath目录下,编译以后就可以在target的classpath看到它们在同一级目录下)
接口文件和映射文件之间的关系:
1)1中指的是namesapce要写接口文件的全类名。
2)2中指的是xml映射文件中id是接口文件中方法名。
3.映射文件:
<select>元素
<insert>元素
useGenerateKeys:
selectKey:
数据库主键包括自增和非自增,有时候新增一条数据不仅仅知道成功就行了,后边的逻辑可能还需要这个新增的主键,这时候再查询数据库就有点耗时费力,我们可以采用selectKey来帮助我们获取新增的主键。
1. order为after
2.order为before
<update>元素和<delete>元素略。
4.mybatis的动态SQL
3.1<if>标签:<if>元素是常用的判断语句,主要用于实现某些简单的条件选择。在实际应用中,我们可能会通过多个条件来精确地查询某个数据。例如,要查找某个用户信息,可以通过姓名和职业来查找用户,也可以不填写职业,直接通过姓名来查找用户,还可以都不填写而查询出所有用户,此时姓名和职业就是非必需条件。类似于这种情况,在MyBatis中就可以通过<if>元素来实现。
<?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.form.third.dao.UserMapper">
<!--if元素的使用-->
<select id="findUserByNameAndJods" parameterType="com.form.third.dto.User" resultType="com.form.third.dto.User">
select * from t_user where 1=1
<if test="username != null and username != ''">
and username = #{userName, jdbcType=VARCHAR}
</if>
<if test="jobs != null and jobs != ''">
and jobs = #{jobs, jdbcType=VARCHAR}
</if>
</select>
</mapper>
使用<if>元素的test属性分别对username和jobs进行了非空判断(test属性多用于条件判断语句中,用于判断真假,大部分的场景中都是进行非空判断的,有时也需要判断字符串、数字和枚举等),如果传入的查询条件非空,就进行动态SQL组装。
if标签中的test写的是条件:
等于: ==
不等于: !=
大于:gt
小于:lt
大于等于:大于或等于 → 年龄≥15 → test=”age gt 15 or age == 15”
小于等于:小于或等于 → 年龄≤15 → test=“age lt 15 or age == 15”
and和or如何表达:and、or
字符串的比较:username等于songge → test=“username == ‘songge’”
字符串的长度:username的长度大于5 → test=“username.length gt 5”
简而言之,使用<if>条件进行判断,如果传入的条件符合,就进行动态sql组装。test属性一般放条件判断语句。
3.2 <choose><when><otherwise>元素
<choose><when><otherwise> 标签组:也是一个用于条件判断的标签组,和<if>的不同之处在于条件从<choose>进入,去匹配<when>中的添加,一旦匹配马上结束;若到找不到匹配项,将执行<other>中的语句;可以理解为<if>是 && 关系 <choose>是 || 关系 ,从多个选择条件去选择一个条件进行搜索。MyBatis提供了choose 元素,按顺序判断when中的条件出否成立,如果有一个成立,则choose结束。当choose中所有when的条件都不满则时,则执行 otherwise中的sql。类似于Java 的switch 语句,choose为switch,when为case,otherwise则为default。 if是与(and)的关系,而choose是或(or)的关系。
MyBatis-动态SQL的if、choose、when、otherwise、trim、where、set、foreach使用(各种标签详解), 以及实体间关系配置 - 雪洗中关村 - 博客园
使用了<choose>元素进行SQL拼接,若第一个<when>元素中的条件为真,则只动态组装第一个<when>元素内的SQL片段;否则继续向下判断第二个<when>元素中的条件是否为真,以此类推;若前面所有when元素中的条件都不为真,则只组装<otherwise>元素内的SQL片段。
3.3<where>元素
<where>元素会自动判断组合条件下拼装的SQL语句,只有<where>元素内的条件成立时,才会在拼接SQL中加入where关键字,否则将不会添加;即使where之后的内容有多余的“AND”或“OR”,<where>元素也会自动将它们去除。如下例,username为空的时候,where后面就多了一个and,<where>就会帮我们把那个多出来的and去掉了。
3.4<trim>元素
更新update:根据id更新一个user,user的哪个字段不为null,我们就更新哪个字段
prefix:在trim标签里面内容的最前面新增某个内容
suffix:在trim标签里面内容的最后面新增某个内容
prefixOverrides:如果最前面出现个啥,我们去掉它
suffixOverrides:如果最后面出现个啥,我们去掉它
3.5<set>元素
<set>元素主要用于更新操作,主要作用是在动态包含的SQL语句前输出一个SET关键字,并将SQL语句中最后一个多余的逗号去除。
<update id="insertUser" parameterType="java.lang.String" >
update t_user
<set>
<if test="name != null and name.length() > 0">name = #{name},</if>
<if test="gender != null and gender.length() > 0">gender = #{gender},</if>
</set>
where id = {#id}
</update>
update user set name='xxx' , gender='xx' where id='x' ,上面的代码里gender后面多了个逗号,<set>元素就可以把这个逗号去掉。
<set>标签也相当于:
3.6<foreach>元素
item:配置的是循环中当前的元素。 index:配置的是当前元素在集合中的位置下标。 collection:配置的list是传递过来的参数类型(首字母小写),可以是一个array、list(或collection)、Map集合的键、POJO包装类中的数组或集合类型的属性名等。 open和close:配置的是以什么符号将这些集合元素包装起来。 separator:配置的是各个元素的间隔符。
集合参数。当使用可迭代对象或者数组时,index是当前迭代的次数,item的值是本次迭代获取的元素。当使用字典(或者MapEntry对象的集合)时,index是键,item是值。
在使用<foreach>时,最关键、最容易出错的就是collection属性,该属性是必须指定的,而且在不同情况下该属性的值是不一样的,主要有以下3种情况。 如果传入的是单参数且参数类型是一个数组或者List的时候,collection属性值分别为array、list(或collection)。 如果传入的参数有多个,就需要把它们封装成一个Map,当然单参数也可以封装成Map集合,这时collection属性值就为Map的键。 如果传入的参数是POJO包装类,collection属性值就为该包装类中需要进行遍历的数组或集合的属性名。
3.7 sql include
把sql语句放到sql标签中,include标签就可以引用 → 把通用的sql语句提取出来,通过include标签进行引用。sql标签做了全局的sql片段,可以进行引用。
sql片段中也可以写其他的标签
5.Mybatis的关联映射
输入映射
5.1 没有注解
5.1.1 基本类型、包装类、String
5.1.2 javabean
5.1.3 map
5.1.4 多个参数
基本类型、包装类、String:param或arg
javabean或map:(param或arg) 加上(javabean的成员变量名或map的key)
接口中的方法上,可以在形参中写多个参数
param和arg对应的是第几个参数:
如果使用param:下标从1开始 → 对应第一个参数
如果使用arg:下标从0 → 对应第一个参数
5.1.5 使用注解
@Param中写了什么value,那么你在#{}中就用什么值。(不管你的参数类型是什么,不管你的参数有几个)
javabean → #{}中写@Param中的值+javabean的成员变量名
基本类型、包装类和String → #{}就用@Param中的value
map → #{}中写@Param中的值+map的key
输出映射
查询结果的封装 → 做的是查询select
select标签中resultType不能少,resultType始终写的是单条数据的类型
mybatis不管你接口中的方法返回值为单条还是多条数据,mybatis在底层接收查询结果的时候,都是先通过list来接收的,所以resultType大家直接写单条数据类型就可以了。
5.2 基本类型、包装类、String
查询user表中的记录数:
根据id查询username:
封装多条数据:数组或list接收
javabean的成员变量名和表的列名不一致,用as
多表映射:
user userDetail 一对一关系,在一个javabean中创建一个成员变量为另一个javabean类型
分次查询:
第一次查询查左表,第二次查询查右表,association或collection标签中,property:父标签javabean的成员变量名
column:查询结果的列名,并且为第二次查询提供参数,select:第二次查询的命名空间+id
用户和订单user和order存在一对多的关系,在左边的javabean中创建右多类型的list,在User中创建一个List<Order>。
多对多(本质上就是一对多)
课程和学生:多对多关系,一门课程对应多名学生,一名学生对应多门课程,互为一对多关系
在javabean中创建另一个javabean的list
Course中包含List<Student>
Student中包含List<Course>
6.1 setting
6.1.1 缓存cache
执行一个查询,把查询结果记录下来,下一次执行相同的查询,就不会执行jdbc操作。
两级缓存:
一级缓存:sqlSession级别,使用相同的sqlSession,默认开启的
同一个sqlSession下执行相同的查询
一级缓存何时失效?sqlSession进行commit则会清空一级缓存
二级缓存:命名空间级别
需要做以下几步才能使用到二级缓存
- setting → cacheEnabled=true
- resultType对应的javabean要实现序列化 implements Serializable
- 映射文件中增加<cache/>
二级缓存我们不必要同一个sqlSession下去执行
需要通过commit放入二级缓存中
二级缓存何时失效?
当我们执行修改数据库中数据操作(insert、update、delete),通过提交sqlSession时会失效。
6.1.2 懒加载
当你去获得对象的时候才去执行查询。 → 输出映射的过程 → 分次查询
增加lazyLoadingEnabled之后,所有的分次查询均为懒加载了,我们想要立即加载,增加fetchType=eager
settings增加lazyLoadingEnabled=true
参考文章:
https://tudan.blog.csdn.net/article/details/104316949
SpringBoot整合Mybatis完整详细版_海岛拾贝的博客-CSDN博客_springboot mybatis
MyBatis 3 Annotation Example with @Select, @Insert, @Update and @Delete
参考图书:Spring + Spring MVC + Mybatis 从零开始学