目录
一,简介
二,mybatis执行原理
1,环境搭建原理
2,功能、生命周期和作用域
三,搭建环境(基于Maven构建项目)
1,引入依赖
2,编写mybatis核心xml配置文件
3,编写返回SqlSession的工具类
4,创建实体类
5,编写*Mapper接口类
6,编写*Mapper.xml映射文件
7,测试
四、配置文件XML
1,配置文档的顶层结构
2,properties(属性)
(1)属性的三种配置方式:
(2) 三种配置方式的加载顺序和优先级
3,settings(设置)
4,typeAliases(类型别名)
(1)指定别名的两种方式
(2)Mybatis内置的常见的 Java 类型的类型别名
3,typeHandlers(类型处理器)
4,objectFactory(对象工厂)
5,plugins(插件)
6,environments(环境配置)——重要
(1)配置多个环境:
(2)配置说明
(3) 事务管理器
(4)dataSource(数据源)
7,mappers(映射器)
五,XML映射文件
1,xml映射文件的顶层标签
2,< select>标签
3,< insert>、< update>、< delete>标签
4,< sql>标签
5,参数
6,< resultMap>标签
7,< cache/>标签——缓存
(1)mybatis缓存介绍
(2)一级缓存测试
(3)二级缓存测试
8,< cache-red>标签
六,使用注解开发
1,编写步骤
七,mybatis日志实现
1,mybatis日志简介
2,日志配置步骤
3,打印的日志
八、动态SQL
1,< if>标签
2,< choose>(when,otherwise)标签
3,< where>
4,< trim>
5,< set>
6,< foreach>
学而时习之,不亦说乎?
以前只是能在项目中使用,并不懂里面的弯弯绕,而且对mybatis的认识不系统、不深刻,故在此系统的学习一下,并总结下文。
JDBC在每次执行sql时的操作步骤如下,其中①②③⑤⑦都是处处相同的代码:
MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。——mybatis官网的简介
mybatis – MyBatis 3官网中文https://mybatis.org/mybatis-3/zh/index.html
这一章节,有mybatis执行原理的说明,和重要概念的说明,通过这一章节的学习,可以让我对后面的第三章节环境搭建有个基本的认识,对为什么这样构建,为什么需要这个步骤,为什么需要这样的文件等,有 一定的认知。
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 但也可以使用任意的输入流(InputStream)实例,比如用文件路径字符串或 file:// URL 构造的输入流。MyBatis 包含一个名叫 Resources 的工具类,它包含一些实用方法,使得从类路径或其它位置加载资源文件更加容易。
——mybatis官网
作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。
SqlSessionFactoyBuilder、SqlSessionFactory、SqlSession 和 映射器实例 的主要功能、生命周期和作用域如下:
①SqlSessionFactoryBuilder
②SqlSessionFactory
③SqlSession
④映射器实例
这一章,是对整个mybatis的配置流程,执行流程,先加载配置文件确定后面mybatis的工作行为、怎么连接数据库、怎么找到编写的sql、怎么执行sql等有个整体的认知,具体的细节和更深层次的认识会在后面的第四章mybatis的核心配置文件、第五章节*Mapper.xml映射文件说明。
org.mybatis
mybatis
3.5.9
当然,因为mybatis需要连接mysql,同时,在这里通过junit测试、lombok插件;故在这里引入响应依赖:
mysql
mysql-connector-java
5.1.47
org.projectlombok
lombok
RELEASE
compile
junit
junit
RELEASE
test
具体解释可参见下文第四章节mybatis核心配置文件对xml配置文件的详解!
public class MybatisUtils {
//静态变量被,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化
private static SqlSessionFactory sqlSessionFactory;
//在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。
static {
try {
//mybatis-config.xml配置文件的路径
String resource = "mybatis-config.xml";
//使用Mybatis提供的工具类Resources加载配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
//使用SqlSessionFactoryBuilder类根据配置文件构建sqlSessionFactory
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取SqlSession连接
public static SqlSession getSession(){
return sqlSessionFactory.openSession();
}
}
上面的内容只需要编写一次,下面的内容需要在操作不同的数据表时编写不同的内容。
@Data
public class Books {
private Integer id;
private String title;
private String author;
private Integer sales;
private Date published_date;
}
public interface BooksMapper {
List findAllBooks();
}
当然,mybatis可以使用注解的方式直接在*Mapper接口方法上直接编写sql语句,这时就不在需要*Mapper.xml映射文件了,具体内容见第六章节。
对应第五章节XML映射文件!
public class BooksMapperTest {
@Test
public void findAllBooksTest(){
//①获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//②获得映射器实例(*Mapper接口对象)
BooksMapper booksMapper = sqlSession.getMapper(BooksMapper.class);
//③调用*Mapper接口对象的方法,以执行其绑定的sql
List books = booksMapper.findAllBooks();
//显示输出查询结果——处理逻辑
for(Books book : books){
System.out.println(book);
}
//④关闭sqlSession
sqlSession.close();
}
}
运行结果:
总结编写步骤:
2,mybatis-config.xml核心配置文件:
- 在刚开始配置好
之后这部分一般就不会改变; - 当增加了*Mapper.xml映射文件之后,在
标签- 中进行注册。
3,获取sqlSession的工具类
- 返回SqlSession的工具类一般编写不会在改变。
当新增一个数据表时:
- 添加一个对应数据表的实体类
- 添加一个*Mapper接口类
- 添加*Mapper.xml映射文件
- *Mapper.xml映射文件中,用
标签的namespace属性绑定*Mapper接口类 - 将*Mapper.xml映射文件通过
标签注入到mybatis-config.xml核心配置核心配置文件 当新增一个sql时:
- 在*Mapper接口类,添加一个方法
- 在*Mapper.xml映射文件中,根据功能选择
- 在标签中编写增删改查sql语句
- 在需要的地方调用*Mapper接口类的方法,以执行sql语句
根据mybatis执行原理,“SqlSessionFactoryBuilder根据mybatis-config.xml配置文件中的配置调用build()构建出SqlSessionFactory对象”,也就是说之后的一切操作的行为都是根据配置文件中的配置进行的!
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。——mybatis官网
必须按照这个顺序在mybatis-config.xml文件中配置,否则会报错:
通过
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment, props);
前面读取的属性会被后面读取的同名属性的值覆盖掉,既是加载的越晚优先级越高!
我们通过
通过
没有设置别名时:
设置别名:
当这样配置时,Books
可以用在任何使用 com.demo.model.Books 的地方。
MyBatis会在包名下面搜索需要的java Bean,在其他地方即可直接写类型名,而不用指定包名.类型:
同时, 在每一个Java Bean(实体类)中使用@Alias注解;在没有指定注解值的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如 com.demo.model.Books
的别名为 books
;若有注解,则别名为其注解值:
它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格
别名 | 映射的类型 |
---|---|
_byte | byte |
_long | long |
_short | short |
_int | int |
_integer | int |
_double | double |
_float | float |
_boolean | boolean |
string | String |
byte | Byte |
long | Long |
short | Short |
int | Integer |
integer | Integer |
double | Double |
float | Float |
boolean | Boolean |
date | Date |
decimal | BigDecimal |
bigdecimal | BigDecimal |
object | Object |
map | Map |
hashmap | HashMap |
list | List |
arraylist | ArrayList |
collection | Collection |
iterator | Iterator |
MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Java 类型。
org.apache.ibatis.type.TypeHandler
接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler
, 并且可以(可选地)将它映射到一个 JDBC 类型;MyBatis可以配置多个数据库源,比如在开发、测试和生产环境需要不同的配置,或想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。
事务管理器具体干了什么?
mybatis中有两种类型的事务管理器:JDBC、MANAGED
如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
配置数据源
mybatis中有三种内建的数据源类型:POOLED、UNPOOLED、JNDI
mybatis提供了四种找到资源的路径:
到这里,配置文件确定了Mybatis后续工作的行为,同时,Mybatis也已经知道编写好的sql语句文件了。
后面,要确定怎么编写sql、怎么让mybatis知道要执行哪个sql。
SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出):
cache
– 该命名空间的缓存配置。cache-ref
– 引用其它命名空间的缓存配置。resultMap
– 描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。sql
– 可被其它语句引用的可重用语句块。insert
– 映射插入语句。update
– 映射更新语句。delete
– 映射删除语句。select
– 映射查询语句。在里面写select语句,并通过属性id绑定*Mapper接口方法,确定传入参数类型、返回结果类型等,通过此标签将sql语句与java代码联系起来:通过java代码调用sql执行、java代码接收sql执行的结果。
当参数过多时,可以采用Map传递参数:
①在*Mapper接口方法文件中,编写接口方法
List findBooksByTitleAndAuthor2(Map map);
②在.Mapper.xml映射文件中, 指定通过parameterType属性指定传递参数类型为map
注意:也可不指定 parameterType="map",因为mybatis可通过类型处理器(TypeHandler)自动推断具体传入参数的类型。
③在调用接口方法时,给map赋值,其中key为sql中取的值,没有顺序要求
@Test
public void findAllBooksTest(){
//①获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//②获得映射器实例(*Mapper接口对象)
BooksMapper booksMapper = sqlSession.getMapper(BooksMapper.class);
//③调用*Mapper接口对象的方法,以执行其绑定的sql
Map map = new HashMap<>();
map.put("title","昨日今宵");
map.put("author","张三");
List books = booksMapper.findBooksByTitleAndAuthor2(map);
for (Books book: books) {
System.out.println(book);
}
//④关闭sqlSession
sqlSession.close();
}
示例:
①在*Mapper接口方法文件中,编写接口方法
int addBook(Books book);
②在.Mapper.xml映射文件中, 指定通过parameterType属性指定传递参数类型为map
insert into books(title,author,sales,published_date) values(#{title},#{author},#{sales},#{publishedDate});
③在调用接口方法时,给map赋值,其中key为sql中取的值,没有顺序要求
@Test
public void findAllBooksTest(){
//①获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//②获得映射器实例(*Mapper接口对象)
BooksMapper booksMapper = sqlSession.getMapper(BooksMapper.class);
//③调用*Mapper接口对象的方法,以执行其绑定的sql
Books book = new Books();
book.setAuthor("赵五");
book.setSales(13);
book.setTitle("秋天的童话");
book.setPublishedDate(new Date());
int res= booksMapper.addBook(book);
System.out.println(book.getId());
//④提交事务
sqlSession.commit();
//④关闭sqlSession
sqlSession.close();
}
注意:
- insert、update、delete操作,需要通过sqlSession.commit();提交事务,否则不会将修改写入数据库中;
- 自动生成主键,且返回到java代码中:设置 useGeneratedKeys=”true”,然后再把 keyProperty 设置为目标属性(数据表i的主键名);最后在传入的实体对象的相应属性就保存了数据库返回来的自增id值;
- 接口的多个普通参数,用@Param标注
提示:
可以在获取SqlSession对象时在sqlSessionFactory.openSession()中配置自动提交事务:
//获取SqlSession连接 public static SqlSession getSession(){ return sqlSessionFactory.openSession(true); }
通过
IN
,OUT
或 INOUT
参数。如果参数的 mode
为 OUT
或 INOUT
,将会修改参数对象的属性值,以便作为输出参数返回。jdbcType
,其他的事情交给 MyBatis 自己去推断就行了#{}和${}区别:
- 使用
#{}
参数语法时,MyBatis 会创建PreparedStatement
参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样),更安全、更迅速- ${}参数语法,MyBatis 不会修改或转义该字符串,常用于表名或列表动态生成
- 用${}接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击。因此,要么不允许用户输入这些字段,要么自行转义并检验这些参数
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap
,再根据属性名来映射列到 JavaBean 的属性上。如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。
①顶层标签结构
constructor
- 用于在实例化类时,注入结果到构造方法中
idArg
- ID 参数;标记出作为 ID 的结果可以帮助提高整体性能arg
- 将被注入到构造方法的一个普通结果id
– 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能result
– 注入到字段或 JavaBean 属性的普通结果association
– 一个复杂类型的关联;许多结果将包装成这种类型
resultMap
元素,或是对其它结果映射的引用collection
– 一个复杂类型的集合
resultMap
元素,或是对其它结果映射的引用discriminator
– 使用结果值来决定使用哪个 resultMap
case
– 基于某些值的结果映射
case
也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射②id & result
③constructor
(构造方法)
构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。
④association
(关联)
MyBatis 有两种不同的方式加载关联:
⑤collection
(集合)
MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。Mybatis包含两级缓存:一级缓存和二级缓存
因为一级缓存默认开启,且不需要进行配置(也没有可以手动配置的参数),所以在这里直接使用测试:
@Test
public void findAllBooksTest(){
//①获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//②获得映射器实例(*Mapper接口对象)
BooksMapper booksMapper = sqlSession.getMapper(BooksMapper.class);
//③调用*Mapper接口对象的方法,以执行其绑定的sql
Books book = booksMapper.selectBookById(12);
System.out.println(book);
System.out.println("-----------------------------------------------------");
Books book2 = booksMapper.selectBookById(12);
System.out.println(book2);
//④关闭sqlSession
sqlSession.close();
}
执行结果:
①mybatis-config.xml开启全局缓存
② 在*Mapper.xml映射文件中配置使用二级缓存
的作用:
- 该*Mapper.xml文件中的所有select语句的结果都将被缓存;
- 该*Mapper.xml文件中的所有insert、update和delete语句会刷新缓存(缓存只作用域cache标签所在的映射文件中的语句,如果混合使用java API和XML映射文件,在公用接口中的语句将不会被默认缓存,使用@CacheNamesapceRed注解指定缓存作用域);
- 缓存会默认使用最近最少使用算法(LRU)清除不需要的缓存;
- 缓存不会定时进行刷新;
- 缓存默认会保存列表或对象的1024个引用;
- 缓存会被是为读/写缓存,所以获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所在的潜在修改。
的属性:
- eviction:指定清除缓存的策略,可用清除策略如下:
- LRU,最近最少使用,移除最长时间不被使用的对象,默认使用;
- FIFO,先进先出,按对象进入缓存的顺序来移除他们;
- SOF,软引用,基于垃圾回收器状态和软引用规则移除对象;
- WEAK,弱引用,更积极地基于垃圾收集器状态和弱引用规则移除对象。
- flushInterval:设置刷新时间间隔,毫秒为单位,默认不设置时没有刷新间隔;
- size:引用数目,默认是1024;
- readOnly:设置只读时,缓存的对象不能被修改,缓存会给所有调用者返回缓存相同实例;设置可读写时,缓存会通过序列化返回缓存对象的拷贝。默认false。
③对实体类实现序列化接口
所有的实体类先实现序列化接口
public class Books implements Serializable {
.......
}
④测试代码
@Test
public void findAllBooksTest(){
//①获取SqlSession对象
SqlSession sqlSession = MybatisUtils.getSession();
//②获得映射器实例(*Mapper接口对象)
BooksMapper booksMapper = sqlSession.getMapper(BooksMapper.class);
//③调用*Mapper接口对象的方法,以执行其绑定的sql
Books book = booksMapper.selectBookById(12);
System.out.println(book);
//④关闭sqlSession
sqlSession.close();
//重新开启一个SqlSession会话,进行查询
//①获取SqlSession对象
SqlSession sqlSession1 = MybatisUtils.getSession();
//②获得映射器实例(*Mapper接口对象)
BooksMapper booksMapper1 = sqlSession1.getMapper(BooksMapper.class);
//③调用*Mapper接口对象的方法,以执行其绑定的sql
Books book1 = booksMapper1.selectBookById(12);
System.out.println(book1);
//④关闭sqlSession
sqlSession1.close();
}
⑤执行结果
自定义缓存:除了上述mybatis自定义缓存的方式,我们也可以通过实现你自己的缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。
对某一命名空间的语句,只会使用该命名空间的缓存进行缓存或刷新。
当想要在多个命名空间中共享相同的缓存配置和实例时,使用 cache-ref 元素来引用另一个缓存。
这时,这个*Mapper.xml中的缓存会保存在所引用的*Mapper.xml映射文件的缓存中;既是它们公用一个缓存。
利用注解开发就不需要mapper.xml映射文件了 。将sql语句直接卸载*Mapper接口方法上,通过这个位置关系直接实现了sql语句和包.类的绑定和包.类的方法的绑定。
注解 类型主要分成 (对应sql的增删改查):
@select ()
@update ()
@Insert ()
@delete ()
只需要在前面的基础上省去*Mapper.xml文件,修改mybatis-config.xml核心配置的注入,并在接口上通过注解写上sql语句即可!
①省去*Mapper.xml文件
②在mybatis-config.xml核心配置文件注入接口
③在*Mapper接口方法上写上sql
@Select("select * from books where id = #{id}")
Books selectBookById(int id);
注意:其他内容和使用*Mapper.xml文件时保持一致!
Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:
MyBatis 内置日志工厂基于运行时自省机制选择合适的日志工具。它会使用第一个查找得到的工具(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。
不少应用服务器(如 Tomcat 和 WebShpere)的类路径中已经包含 Commons Logging,所以在这种配置环境下的 MyBatis 会把它作为日志工具,我们配置的 Log4J 配置将被忽略。
如果我们的应用部署在一个类路径已经包含 Commons Logging 的环境中,而又想使用其它日志工具,我们可以通过在 MyBatis 配置文件 mybatis-config.xml 里面添加一项 setting 来选择别的日志工具。如下:
...
...
①引入log4j的jar包
log4j
log4j
1.2.17
②log4j.properties配置文件
#设置等级为DEBUG的日志信息输出到stdout
log4j.rootLogger=DEBUG, stdout
#stdout输出的相关配置
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
③在mybatis-config.xml中添加配置
也可以不添加,因为MyBatis 内置日志工厂会环境中有没有日志工具,如果有会自动启动,如果没有会禁用日志功能;
如果添加了这个配置,MyBatis会优先采用这个配置下指定的日志工具,不会先采用被其他默认优先级更高的日志工具。
就是Mybatis提供的动态拼接sql的语法规则,根据条件判断某部分sql要不要拼接。
mybatis提供的用于动态SQL的标签:
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。
set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
collection:指定输入对象中的集合属性 item:每次遍历生成的对象 open:开始遍历时的拼接字符串 close:结束时拼接的字符串 separator:遍历对象之间需要拼接的字符串 select * from blog where 1=1 and (id=1 or id=2 or id=3)
你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。
脑壳痛,整天内容大概根据mybatis的编写步骤构建了mybatis的整体,同时在每个步骤深入展示了重要的应该注意的东西;进行了一定的理解和自己的说明,总体觉得还行。但缺乏spingboot集成mybatis的部分。
剩下的就通过在项目中应用的过程深入理解吧。