Mybatis笔记
由于Mybatis是面向接口进行编程的,需要注意以下两点:
1、映射文件中的namespace标签中的值需要和mapper中的全类名相同
2、映射文件中的id属性值,需要和mapper接口中的方法名一致
通过Mybatis执行sql的步骤:
- 通过Resources类进行加载核心配置文件
- 通过创建一个SqlSessionFactoryBuilder对象
- 通过SqlSessionFactoryBuilder类中的builder方法进行创建SqlSessionFactory对象
- 通过SqlSessionFactory对象中的openSession方法获取SqlSession对象
- 通过SqlSession对象进行获取mapper接口的对象
- 通过mapper对象进行执行抽象方法,通过id进行找到mapper配置文件中的sql语句,进行执行sql语句
- 因为默认的提交事务的方式是通过JDBC进行提交,所以,需要我们通过SqlSession类中的commit方法进行提交事务才会生效。(以后可通过Spring进行统一管理事务)
实例代码如下:
如何进行设置自动提交事务:
在创建SqlSession对象的时候,只需要进行传入一个Boolean参数就可以进行设置,true表示开启自动提交,false表示取消默认提交(默认为false,取消自动提交)
Log4j的日志等级:日志的级别:FATAL(致命)>ERROR(错误)>WARN(警告)>INFO(信息)>DEBUG(调试) 从左到右打印的内容越来越详细
等级越低,输出的信息越多,只会输出大于等于本生的日志等级。
在执行select语句的时候,映射文件中的select标签中必须设置resultType属性值或者resultMap属性值,如果不进行设置无法进行查询数据。
Mybatis的核心配置文件的介绍:
如何通过properties配置文件进行设置连接数据库所需要的信息:
- 创建properties文件
- 将properties文件引入mybatis核心配置文件中(通过 <properties标签中的resource属性进行引入>)
- 通过 ${ } 的方式将properties文件中的信息进行设置信息
Mybatis核心配置文件中标签的顺序:
"(properties?,settings?,typeAliases?,typeHandlers?,objectFactory?,objectWrapperFactory?,reflectorFactory?,plugins?,environments?,databaseIdProvider?,mappers?)".
如何给一个实体类对象进行取别名:(使用TypeAliases标签进行设置)
typeAlias中的type属性必须进行设置,alias属性可以设置,可以不进行设置,如果不进行设置,默认使用的是这个类的简写类名(不区分大小写)
使用实例:(编写标签的时候需要注意标签的顺序)
作用:在Mybatis范围之内,使用时候可以通过alias中的字符串获取到type中的这个类型
例如:
MyBatis中自动进行设置别名的类型及别名:
将整个包中的类进行设置别名:(通过使用typealiases下的package标签进行设置)(常用)
设置之后,这个包中的每一个类的别名分别为各自的类名,且不区分大小写
如何通过以包为单位,将mapper的Xml进行引入:
使用mappers标签中的package标签进行引入。
需要注意:
- mapper接口所在的包要和映射文件所在的包一致
- Mapper接口的类名和映射文件的文件名相同
实例代码:
如何通过文件的方式创建包:
通过 / 进行分割
例如:com/littleshark/mybatis/mapper
Mybatis中获取参数的两种方式:(重点)
Mybatis中获取参数的两种方式:
- ${ } :相当于jdbc中通过字符串拼接的方式 (会导致sql注入)
- #{ } :相当于使用占位符(?)赋值的方式
使用方式:
(使用第二种方式进行举例)
第一种情况:参数为一个的时候:
代码如下:(参数为一个参数类型)
注意:获取参数的时候#{ }中的内容可以任意取,因为我们注意的应该是进行取出的值。
如果使用${ }的方式实现通过username进行获取用户,需要注意,由于使用的是字符串进行拼接的方式,所以要使用单引号。
实例代码:
第二种情况:参数有多个的时候
当参数类型有多个的时候,mybatis会将参数作为一个map集合的值(value),将param1、param2、或者arg0,arg1作为这个map集合的key。
实例代码:
当然,也可以通过param1、param2作为key将参数进行取出
第三种情况:参数有多个的时候,直接传入一个map作为参数
当一个mapper接口中的参数有多个时,我们可以手动的将多个参数添加进map集合中,再将map集合作为参数进行传入。
示例代码:
第四种情况:当参数是一个实体类对象的时候
获取参数的时候和通过map集合进行获取的方式差不多,通过属性名进行获取参数(例如一个User对象,我们可以通过#{username}获取到这个对象中的username属性值)
实例代码:
第五种情况:是第三种和第二种情况的结合,可以将mybatis中自动生成的map的key进行修改成为我们想要的key,再将参数作为map集合的值
示例代码:
通过使用@Param注解进行设置该参数在mybatis中自动生成的map集合中的key。最后再通过@param中的value的属性值进行获取参数值
总结:
MyBatis中的各种查询功能:
如果Mybatis中查询出的数据只有一条,我们进行接收的方式有:
- 通过实体类对象进行接收
- 通过List集合进行接收
- 通过Map集合进行接收,如果是通过Map集合进行接收,就会使用数据库中的字段作为键,数据作为值,一个Map对象对应一条数据,和一个实体类对象相同。例如:
如果MyBatis中查询出的数据有多条,我们可以进行接收的方式有:
- 通过List集合进行接收
- 通过Map类型的List集合进行接收,因为一个Map对象对应一条数据,所以,需要使用到Map类型的List集合进行接收(List<Maop<>>类型),示例代码:
- 通过使用@Mapkey注解进行设置将查询出的每一条数据中的哪一个字段作为key,保存到一个Map集合中,后就可以通过@mapKey的value属性值进行获取对应的数据,示例代码:
示例代码:
需要注意的一点就是:一定不能通过一个实体类对象进行接收,否则就会报错TooManyResultException异常
通过Mysql中的模糊查询进行查询数据的注意事项:
MySql中的继续模糊查询的符号:
% 最常用的通配符,可以代表任意长度的字符串(长度可以是0),例如a%b就表示查询a开头b结尾的所有数据,%a%就表示将含有a的数据进行全部查询出来
需要注意的是:使用通配符的时候,必须添加单引号或者双引号才能生效
_ 表示任意一个长度的字符,例如a_b 可以查询出acb、adb等等
注意:也需要使用单引号或者双引号进行联合使用才能生效
再通过MyBatis进行模糊查询的时候,因为需要使用到通配符,通配符的时候需要使用到单引号或者双引号,在MyBatis中又有两种获取参数的方式,所以有两种进行模糊查询的方式:
使用#{ }的方式进行模糊查询:
因为#{ }进行查询的时候,是通过通配符(?)的方式进行查询的,所以如果我们直接在Sql语句中添加单引号或者双引号就会直接将通配符进行查询
也就是这样的Sql语句:
这样就会直接报错:
因为使用了单引号,就会直接将单引号里面的内容作为查询的条件,在没有进行获取参数的时候,Sql就已经执行了,所以就是占位符的符号
如果想通过使用#{ }进行模糊查询,代码需要进行以下编写:
需要在传参的时候手动添加%通配符
或者通过手动在Sql语句中进行添加%通配符的方式进行:(常用)
实例代码:
常用
通过使用${ }的方式进行模糊查询:
使用${ }的方式需要在Sql语句中自行添加单引号或者双引号,因为使用${ }的方式本质是使用字符串拼接的方式进行编写Sql语句
通过MyBatis进行批量删除的时候,需要注意只能使用${ }的方式进行获取参数,不能使用#{ }进行获取参数。
示例代码:
通过#{ }的方式进行获取参数就会报错
需要使用${ }的方式进行获取参数(示例代码:):
在同一个数据库中,查询不能的表的时候如何进行操作:
因为要查不同的表,所以需要有一个参数用于传入表名,在MyBatis中进行获取这个表名参数的时候,只能通过${ }的方式进行获取参数(因为在Sql语句中,表名不能含有单引号)
实力代码:
通过MyBatis进行添加数据:
实例代码:
其中,insert标签中的属性:
- useGeneratedKey:进行设置是否进行使用主键自增
- KeyProperty:将这个数据库中对应的数据中的主键赋值给KeyProperty属性值中对应对象的属性值,(举例:将t_user表中对应的这个user对象中的主键赋值给这个user对象的id属性中)
运行结果:
如果数据库中的字段名和Bean对象的属性名不相同的时候,不能进行自动赋值,应该怎么进行解决:(需要注意,如果在bean对象对象中没有无参构造,是通过无参构造创建对象,再将属性进行注入)
数据库中的字段:
Bean对象的属性名:
有三种方案:
第一种方式:将执行的Sql语句中的字段名进行取别名,取的别名需要和Bean对象对象中的属性名相同(例如: select emp_name empName from t_user 就可以将emp_name这个字段中的值赋值给empName属性),注意,这个因为是在核心配置文件中进行设置的,所以在整个MyBatis中都可以使用。
第二种解决方式:通过在mybatis-config.xml核心配置文件中进行开启将下划线转化为驼峰的标签。示例代码:
结果:
第三种方式:通过使用ResultMap将属性进行映射。
示例代码:
结果:
MyBatis中进行处理多对一的关系的方法:
第一种方式:通过级联属性赋值进行获取
实例代码:
需要有两个无参构造
第二种方式:通过使用resultMap标签中的association标签进行设置多对一的映射关系
实例代码:
结果:
第三种方式:通过分布查询的方式进行处理多对一的映射关系
通过使用resultMap标签中的association标签进行分布查询
Association标签中的属性表示的含义:
Property:在resultMap标签该类型中需要处理多对一关系的属性名
Select::通过select标签的唯一标识选择再次执行的查询语句(mybatis中的唯一标识:该语句对应的方法的全类名+方法名)
Column:下一次查询的语句需要和上一次查询出的结果有什么对应关系(例如:需要将第一次查询出的user对象的id作为下一次查询的条件)
FatchType:进行设置在开启全局延迟加载之后进行设置单个语句是否延迟加载(lazy表示延迟加载,eager表示立即加载)
实例代码:
结果:
如何开启Mybatis中的延迟加载:
通过在核心配置文件中进行设置属性 lazyLoadingEnabled属性,如果开启了aggerssiveLazyLoading属性,需要需要将他设置为false
lazyLoadingEnables属性的作用:全局延迟加载的开关,当开启之后,多有关联对象都会延迟加载,按需加载。(也就是用的时候进行执行sql语句进行查询数据,用哪一个对象中的数据,就只需要查询对应的对象中的Sql,例如:分布查询的时候,如果我们只需要查询员工的名字,不需要部门的信息,在开启了延迟加载之后就会执行第一个Sql语句,不会执行的二条查找部门的Sql语句)
aggerssiveLazyLoading属性的作用:会进行全局加载,尽管你没有用到该属性,也会将不需要的一些属性进行加载
测试:
如果我们需要进行查看对应员工的部门属性,测试结果:
如何在开启了全局延迟加载之后进行局部立即加载:
通过使用在resultMap标签中的association标签中的fetchType属性进行设置是否进行立即加载(前提是开启了全局延迟加载)
FetchType属性值:
- Lazy:进行延迟加载
- Eager:进行立即加载
如何处理一对多的问题:
第一种方式:
通过使用resultMap标签中的collection标签,再通过多表联查的方式进行解决
实例代码:
结果:
第二种方式:
通过使用分步查询的方式进行处理一对多的情况
实例代码:
当然,因为是分步查询,所以,当全局设置了延迟加载的时候,也是会进行延迟加载的,如果需要立即加载,可以通过collection标签中的fetchType属性值进行设置。
MyBatis中的动态Sql语句(实现多条件进行查询):
使用标签中的<if test=”” > Sql</if>标签进行参数的判断
实例代码:
If标签的使用:
- 只有当if标签中的test属性值为true之后,才会将里面的sql语句进行凭借
- If标签中的test属性值中,如果需要使用与运算符,需要使用 and ,不能使用&&
- If标签中的test属性值中,如果需要访问参数的属性值,不需要使用#{ }或者${ },因为当前没有进行拼接Sql语句,所以不需要使用
因为在上面的代码中,需要使用一个恒成立进行避免多余的and 连接符,以下是进行优化之后的代码:(通过使用where标签进行动态生成where)
Where的作用:
- 当where标签中有内容的时候,会自动添加where
- 会自动去掉在语句前面的and 和or(注意,不能去掉在语句后面的and和or 例如:
<if test=”true”> emp_name=#{empName} and </if> 这种情况)
使用trim标签进行处理多条件联查:
实例代码:
MyBatis中的choose、when、otherwise标签(相当于if else if else):
需要注意:when和otherwise标签需要写在choose标签中,一个choose相当于一个if ... eles if ... else 结构,其中表示else的标签为otherwise,表示if 和 else if的标签为when标签
具体实例:
结果:
只要when中的条件有一个成立,就不会在进行判断了,成立一个就直接放回,不会再继续往下执行。
MyBatis中的foreach标签:
注意:当Mapper接口中传入的参数是一个数组或者集合的时候,MyBatis会是会将参数放到MyBatis创建的Map集合中,可以通过@Param注解进行设置对应的键(key)
作用:可以通过foreach标签进行集合或者数组的遍历
Foreach标签中的属性:
Collection:需要进行遍历的集合或者数组
Item:当前数组或者集合中正在遍历的一个元素
Separator:每一个元素之间的分隔符
Open:如果在foreach标签中有值的话,就在全部内容前面添加一个符号
Close:如果在foreach标签中有值的话,就在全部内容后面添加一个符号
实例代码:
Mybatis中的Sql标签:
Sql标签的作用:
通过Sql的id可以查询出在Sql标签中的字段
实例代码:
如何去定义一个Sql标签:
<sql id="empColumn">emp_id,emp_name,emp_age,emp_sex,emp_email</sql>
如何进行引用Sql标签:
通过在Sql语句中使用include标签进行引用:
MyBatis中的一级缓存:
MyBatis中的一级缓存是默认开启的,等级是SqlSession等级,如果通过同一个SqlSession对象进行获取Mapper对象之后进行查询数据,会将数据进行缓存,如果再通过这个SqlSession对象进行查询数据,如果和缓存中的查询语句匹配就会执行进行返回,不会执行Sql语句
举例:
Mybatis中一级缓存失效的四种情况:
- 使用不同的SqlSession对象进行查询相同的数据
- 使用同一个SqlSession对象但是查询条件不同
- 使用同一个SqlSession对象,且查询条件相同,但是在两次查询之间执行使用这个SqlSession对象执行了增删改操作,就会将SqlSession对象中的缓存进行清空
- 使用同一个SqlSession对象,且查询条件相同,但是在两次查询之间手动的将SqlSession对象中的缓存进行清空(通过SqlSession对象中的clearCache()方法进行清空缓存)
MyBatis中的二级缓存:
二级缓存的级别是SqlSessionFactory等级,只要是通过同一个SqlSessionFacotry对象进行开启的SqlSession对象 查询出的数据就会被缓存,此后,再次执行相同的Sql语句,结果就会重缓存中进行返回。
如何开启MyBatis中的二级缓存:
- 在核心配置文件中,设置全局配置属性cacheEnable=“true” ,默认为true,不需要进行设置
- 在映射文件中设置缓存标签(<cache />)
- 二级缓存之后再SqlSession对象进行提交或者关闭之后才有效
- 查询数据转化的实体类型必须实现序列化接口
二级缓存失效的情况:
在两次查询中,执行了任意次增删改的操作,就会将二级缓存中的缓存进行清空
示例代码:
因为没有进行关闭SqlSessin对象(因为是进行查询,不需要进行提交事务),所以不能进行二级缓存中没有数据
在进行关闭了SqlSession对象之后,缓存中就存在数据,可以进行获取:
Mybatis中使用二级缓存需要在映射文件中添加的<cache/>标签的属性:
MyBatis中缓存查询的顺序:
- 先进行查二级缓存(因为可能有其他SqlSession关闭之后查询出数据)
- 如果二级缓存中没有就进行查一级缓存
- 如果一级缓存中没有就只能从数据库中进行查询
在SqlSession对象关闭之后,一级缓存中的内容会存入二级缓存中。
******MyBatis中的逆向工程:
在Mybatis的逆向工程中,凡是带有Example字样的方法,都是进行条件查询,可以通过逆向工程中实体类的对象的Example使用createCriteria()方法进行创建标准(条件)
实例代码:
MyBatis中的分页插件:
如何进行配置:
- 通过maven添加依赖
- 在mybatis的核心配置文件中添加插件
如何进行使用:
- 在查询之前进行开启分页
- 在查询之后获取分页信息
输出结果:
PageInfo {
pageNum = 1, pageSize = 3, size = 3, startRow = 1, endRow = 3, total = 6, pages = 2, list = Page {
count = true, pageNum = 1, pageSize = 3, startRow = 0, endRow = 3, total = 6, pages = 2, reasonable = false, pageSizeZero = false
}[Emp {
empId = 1, empName = '张三', empAge = 45, empSex = '男', empEmail = '123456@qq.com', deptId = 1
},Emp {
empId = 2, empName = '李四', empAge = 65, empSex = '男', empEmail = '123456@qq.com', deptId = 1
},Emp {
empId = 3, empName = '王五', empAge = 46, empSex = '女', empEmail = '123456@qq.com', deptId = 2
}],
prePage = 0, nextPage = 2, isFirstPage = true, isLastPage = false, hasPreviousPage = false, hasNextPage = true, navigatePages = 5, navigateFirstPage = 1, navigateLastPage = 2, navigatepageNums =[1, 2]}