mybatis整合spring之后,mybatis的配置文件“mybatis-config.xml”就好像没什么用了!
在pom.xml文件中不导入如下代码,就会报错:
<build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes></resource><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>true</filtering></resource></resources> </build>
出现如下的错误:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.heng.dao.BirdMapper.insert
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235)
at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:53)
at org.apache.ibatis.binding.MapperProxy.lambda$cachedInvoker$0(MapperProxy.java:115)
at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1708)
at org.apache.ibatis.binding.MapperProxy.cachedInvoker(MapperProxy.java:102)
at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:85)
at jdk.proxy2/jdk.proxy2.$Proxy8.insert(Unknown Source)
mybatis的核心配置文件:
(JDBC:手动
MyBatis:半自动
Hibernate:自动)
(mybatis-config.xml核心配置文件
<environments>配置连接数据库的环境
<mappers>引入映射文件)
(MyBatis中的mapper接口相当于以前的dao。但是区别在于,mapper仅仅是接口,我们不需要提供实现类)
查询功能的标签必须设置resultType或resultMap
resultType:设置默认的映射关系
resultMap:设置自定义的映射关系
id:唯一标识
类型别名不区分大小写
alias可写可不写。
${}使用字符串拼接的方式拼接sql,若为字符串类型或日期类型的字段进行赋值时,需要手动加单引号;但是#{}使用占位符赋值的方法拼凑sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动添加单引号。
mybatis的在进行对数据库操作的时候,如果在DAO接口中,所传递的参数是一个实例对象,那么在xml配置文件中,不能把对象中的属性名写错了!
<insert id="insert" parameterType="Bird">
insert into mybird (id,namese) values (#{id},#{namese});
</insert>
主键自增,居然用null
resource是路径,/代替‘.’ 。
MyBatis面向接口编程的两个一致:
- 映射文件的namespace要和mapper接口的全类名保持一致
- 映射文件中SQL语句的id要和mapper接口中的方法名一致
获取mapper接口对象
两者的区别是什么?
Spring 的上下文的使用!
两种转换的形式:
- SqlSession:代表Java程序和数据库之间的会话。(HttpSession是Java程序和浏览器之间的会话)
- SqlSessionFactory:是“生产”SqlSession的“工厂”。
- 工厂模式:如果创建某一个对象,使用的过程基本固定,那么我们就可以把创建这个对象的相关代码封装到一个“工厂类”中,以后都使用这个工厂类来“生产”我们需要的对象。
MyBatis同时支持XML和注解两种配置方式,帮助程序员屏蔽了近乎所有的JDBC代码,提高开发效率。
ORM(Object Relational Mapping)框架: 根据映射配置文件,完成数据在对象模型与关系模型之间的映射,同时也屏蔽了上述重复的代码,只暴露简单的API供开发人员使用。
mybatis的整体架构:
- 基础支持层
- 核心处理层
- 接口层
基础支持层包含整个MyBatis的基础模块:
- 反射模块
- 类型转换模块
- 日志模块
- 资源加载模块
- 数据源模块
- 事务管理
- 缓存模块
- Binging模块
核心处理层:
- 配置解析
- SQL解析与scripting模块
- SQL执行
- 插件
接口层:
- SqlSession接口
解析器模块
XML解析常见的方式有三种:
- DOM(Document Object Model)
- SAX(Simple API for XML)
- StAX(Streaming API for XML)
DOM是基于树形结构的XML解析方式,他会将整个XML文档读入内存并构建一个DOM树,基于这棵树形结构对各个节点进行操作。
SAX是基于事件模型的XML解析方式,它并不需要将整个XML文档加载到内存中,而只需将XML文档的一部分加载到内存中,即可开始解析,在处理过程中并不会在内存中记录XML中的数据,所以占用的资源比较小。
XPath是一种为查询XML文档而设计的语言,它可以与DOM解析方式配合使用,实现对XML文档的解析。
从 XML 中构建 SqlSessionFactory
每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。
String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例的数据源(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><properties resource="db.properties"><property name="username" value="root"/></properties><!-- <settings>-->
<!--<!– <setting name="logImpl" value="STDOUT_LOGGING"/>–>-->
<!-- <setting name="logImpl" value="LOG4J"/>-->
<!-- </settings>--><typeAliases>
<!-- <package name="mybatis01.pojo"/>--></typeAliases><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><mappers><mapper resource="mybatis01/dao/UserMapper.xml"/><mapper class="mybatis01.dao.UserMapper"/><package name="mybatis01.dao"/></mappers>
</configuration>
environment 元素体中包含了事务管理和连接池的配置。mappers 元素则包含了一组映射器(mapper),这些映射器的 XML 映射文件包含了 SQL 代码和映射定义信息。
SqlSession(SQL会话接口)
SqlSession是MyBatis执行数据库操作的主要接口,定义了执行SQL、获取映射器和管理事务的方法。
该接口定义的方法主要有:
- commit() : 提交事务
- getMapper() : 通过java接口获取映射器
SqlSessionFactory(SQL会话工厂接口)
SqlSessionFactory接口很简单,其定义了获取SQL会话对象和全局配置实例的方法。openSession()方法用来获取SqlSession类型的实例,该方法有多个不同参数重载方法,设置的参数类型包括事务是否自动提交...
使用不含任何参数的openSession()方法获取会话的行为是:
- 从数据源DataSource中获取数据库连接Connection对象和预处理语句。
- 预处理语句不会被复用,也不会批量处理更新。
- 开启一个事务(也就是不自动提交)
- 事务隔离级别使用驱动或数据源的默认设置。
SqlSessionFactoryBuilder(SQL会话工厂构建类)
SqlSessionFactoryBuilder同样提供了getConfiguration()方法获取全局配置对象,DefaultSqlSessionFactory是SqlSessionFactory接口的默认实现类,会话工厂的实例通过会话工厂接口构造器(SqlSessionFactoryBuilder)的builder()方法构建。
探究已映射的 SQL 语句
事实上 MyBatis 提供的所有特性都可以利用基于 XML 的映射语言来实现,这使得 MyBatis 在过去的数年间得以流行。
映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
配置
MyBatis全局配置文件的习惯命名是mybatis-config.xml。
MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。
属性(properties):
如果一个属性在不只一个地方进行了配置,那么,MyBatis 将按照下面的顺序来加载:
- 首先读取在 properties 元素体内指定的属性。
- 然后根据 properties 元素中的 resource 属性读取类路径下属性文件,或根据 url 属性指定的路径读取属性文件,并覆盖之前读取过的同名属性。
- 最后读取作为方法参数传递的属性,并覆盖之前读取过的同名属性。
因此,通过方法参数传递的属性具有最高优先级,resource/url 属性中指定的配置文件次之,最低优先级的则是 properties 元素中指定的属性。
XML映射文件配置
映射文件用来配置
接口方法的SQL执行语句和返回结果类型的映射,在调用映射器接口方法进行数据操作时,MyBatis框架会实际执行该配置中的SQL语句,并将数据库执行的结果转为映射配置的java类型对象。
<select>基本查询映射配置
resultType属性用来指定返回转换的Java对象类型,框架会依据此配置将数据库查询的结果进行自动转换。
JDBC的一般语句(Statement)在条件查询时,条件子句通过替换变量附加在SQL语句后执行;预编译语句()的参数支持使用占位符(?)方式,有效地避免了SQL注入的风险。MyBatis的映射文件对这两种方式都提供了支持,分别提供了${参数}和#{参数}方式进行参数替换。
设置(settings)
这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
cacheEnabled | 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 | true | false | true |
lazyLoadingEnabled | 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 | true | false | false |
aggressiveLazyLoading | 开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。 | true | false | false (在 3.4.1 及之前的版本中默认为 true) |
multipleResultSetsEnabled | 是否允许单个语句返回多结果集(需要数据库驱动支持)。 | true | false | true |
useColumnLabel | 使用列标签代替列名。实际表现依赖于数据库驱动,具体可参考数据库驱动的相关文档,或通过对比测试来观察。 | true | false | true |
useGeneratedKeys | 允许 JDBC 支持自动生成主键,需要数据库驱动支持。如果设置为 true,将强制使用自动生成主键。尽管一些数据库驱动不支持此特性,但仍可正常工作(如 Derby)。 | true | false | False |
autoMappingBehavior | 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示关闭自动映射;PARTIAL 只会自动映射没有定义嵌套结果映射的字段。 FULL 会自动映射任何复杂的结果集(无论是否嵌套)。 | NONE, PARTIAL, FULL | PARTIAL |
autoMappingUnknownColumnBehavior | 指定发现自动映射目标未知列(或未知属性类型)的行为。NONE: 不做任何反应WARNING: 输出警告日志('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日志等级必须设置为 WARN)FAILING: 映射失败 (抛出 SqlSessionException) | NONE, WARNING, FAILING | NONE |
defaultExecutorType | 配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(PreparedStatement); BATCH 执行器不仅重用语句还会执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定数据库驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | 未设置 (null) |
defaultResultSetType | 指定语句默认的滚动策略。(新增于 3.5.2) | FORWARD_ONLY | SCROLL_SENSITIVE | SCROLL_INSENSITIVE | DEFAULT(等同于未设置) | 未设置 (null) |
safeRowBoundsEnabled | 是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False |
safeResultHandlerEnabled | 是否允许在嵌套语句中使用结果处理器(ResultHandler)。如果允许使用则设置为 false。 | true | false | True |
mapUnderscoreToCamelCase | 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用和加速重复的嵌套查询。 默认值为 SESSION,会缓存一个会话中执行的所有查询。 若设置值为 STATEMENT,本地缓存将仅用于执行语句,对相同 SqlSession 的不同查询将不会进行缓存。 | SESSION | STATEMENT | SESSION |
jdbcTypeForNull | 当没有为参数指定特定的 JDBC 类型时,空值的默认 JDBC 类型。 某些数据库驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。 | JdbcType 常量,常用值:NULL、VARCHAR 或 OTHER。 | OTHER |
lazyLoadTriggerMethods | 指定对象的哪些方法触发一次延迟加载。 | 用逗号分隔的方法列表。 | equals,clone,hashCode,toString |
defaultScriptingLanguage | 指定动态 SQL 生成使用的默认脚本语言。 | 一个类型别名或全限定类名。 | org.apache.ibatis.scripting.xmltags.XMLLanguageDriver |
defaultEnumTypeHandler | 指定 Enum 使用的默认 TypeHandler 。(新增于 3.4.5) | 一个类型别名或全限定类名。 | org.apache.ibatis.type.EnumTypeHandler |
callSettersOnNulls | 指定当结果集中值为 null 的时候是否调用映射对象的 setter(map 对象时为 put)方法,这在依赖于 Map.keySet() 或 null 值进行初始化时比较有用。注意基本类型(int、boolean 等)是不能设置成 null 的。 | true | false | false |
returnInstanceForEmptyRow | 当返回行的所有列都是空时,MyBatis默认返回 null。 当开启这个设置时,MyBatis会返回一个空实例。 请注意,它也适用于嵌套的结果集(如集合或关联)。(新增于 3.4.2) | true | false | false |
logPrefix | 指定 MyBatis 增加到日志名称的前缀。 | 任何字符串 | 未设置 |
logImpl | 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 | SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING | 未设置 |
proxyFactory | 指定 Mybatis 创建可延迟加载对象所用到的代理工具。 | CGLIB | JAVASSIST | JAVASSIST (MyBatis 3.3 以上) |
vfsImpl | 指定 VFS 的实现 | 自定义 VFS 的实现的类全限定名,以逗号分隔。 | 未设置 |
useActualParamName | 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的项目必须采用 Java 8 编译,并且加上 -parameters 选项。(新增于 3.4.1) | true | false | true |
configurationFactory | 指定一个提供 Configuration 实例的类。 这个被返回的 Configuration 实例用来加载被反序列化对象的延迟加载属性值。 这个类必须包含一个签名为static Configuration getConfiguration() 的方法。(新增于 3.2.3) | 一个类型别名或完全限定类名。 | 未设置 |
一个配置完整的 settings 元素的示例如下:<settings> <setting name="cacheEnabled" value="true"/> <setting name="lazyLoadingEnabled" value="true"/> <setting name="multipleResultSetsEnabled" value="true"/> <setting name="useColumnLabel" value="true"/> <setting name="useGeneratedKeys" value="false"/> <setting name="autoMappingBehavior" value="PARTIAL"/> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <setting name="defaultExecutorType" value="SIMPLE"/> <setting name="defaultStatementTimeout" value="25"/> <setting name="defaultFetchSize" value="100"/> <setting name="safeRowBoundsEnabled" value="false"/> <setting name="mapUnderscoreToCamelCase" value="false"/> <setting name="localCacheScope" value="SESSION"/> <setting name="jdbcTypeForNull" value="OTHER"/> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> </settings>
org.apache.ibatis.io.Resources
是 MyBatis 框架中的一个类,用于读取资源文件。
getResourceAsStream
是 org.apache.ibatis.io.Resources
类中的一个方法,用于读取资源文件并返回一个输入流。
MyBatis的各种查询功能:
- 若查询出的数据只有一条:①可以通过实体类对象接受;②可以通过list集合接收
- 若查询出的数据有多条:可以通过list集合接收
- 注意:一定不能通过实体类对象接收,此时会抛异常TooManyResultException
resultType=""里面的参数值是不区分大小写的(在mybatis中类型别名是不区分大小写的)
可以将查询到的单行数据转换为map集合 !
Map<String,Object> getBirdById2Map(int id);
<select id="getBirdById2Map" resultType="map">
select * from mybird where id = #{id};
</select>
查询多行数据,并将这些数据存入到list集合中:
只需要改变一下映射方法的返回值类型即可!List<Map<String,Object>>
或者:
@MapKey("id")
Map<String,Object> getBirdById2Map(int id);//这样也能实现!
#会报错 #{}与?占位符之间的关系是什么? 呈现出的SQL语句将?当做了字符串中的一部分了!
?不会被解析为占位符!
#会自动加单引号的!
$不会自动加单引号的
模糊查询:(是建议使用${}而使用#{}会报错!(还包括批量删除、动态设置表名))
<select id="queryLike" resultType="map">
select * from mybird where namese like '%${namses}%';
</select>
上图是不会报错的! 也是最常用的!
驼峰 与下划线 的命名格式
mybatis的全局配置:
<settings>
自动将_映射为驼峰,emp_name:empName
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
resultMap:设置自定义映射关系
- id:唯一标识,不能重复
- type:设置映射关系中的实体类类型
- 子标签:
- id:设置主键的映射关系
- result:设置普通字段的映射关系
- 属性:
- property:设置映射关系中的属性名,必须是type属性所设置的实体类类型中的属性名
- column:设置映射关系中的字段名,必须是sql语句查询出的字段名。
分步查询的优点:可以实现延迟加载,但是必须在核心配置文件中设置全局配置信息:
lazyLoadingEnabled:延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
aggressiveLazyLoading:当开启时,任何方法的调用都会加载该对象的所有属性。否则,每个属性会按需加载。
此时就可以实现按需加载,获取的数据是什么,就只会执行相应的sql。此时可以通过association和collection中的fetchType属性设置当前的分步查询是否使用延迟加载,fetchType="lazy(延迟加载)|eager(立即加载)"
一对多:
分步查询一对多:
分步查询的优点能够实现延迟加载!
动态SQL
MyBatis框架的动态SQL技术是一种根据特定条件动态拼装SQL语句的功能,它存在的意义是为了解决拼接SQL语句字符串时的痛点问题。
MyBatis的一级缓存
一级缓存时SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据,就会从缓存中直接获取,不会从数据库重新访问。
使一级缓存失效的四种情况:
- 不同的SqlSession对应不同的一级缓存
- 同一个SqlSession但是查询条件不同
- 同一个SqlSession两次查询期间执行了任何一次增删改操作
- 同一个SqlSession两次查询期间手动清空缓存
一级缓存默认开启
MyBatis的二级缓存
二级缓存是SqlSessionFactory级别,通过一个SqlSessionFactory创建的SqlSession查询的结果会被缓存;此后若再次执行相同的查询语句,结果就会从缓存中获取。
二级缓存开启的条件:
- 在核心配置文件中,设置全局配置属性cacheEnabled="true",默认为true,不需要设置
- 在映射文件中设置标签<cache/>
- 二级缓存必须在SqlSession关闭或提交之后有效
- 查询的数据所转换的实体类类型必须实现序列化接口
使二级缓存失效的情况:
两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效
MyBatis缓存查询的顺序:
- 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用。
- 如果二级缓存没有命中,再查询一级缓存。
- 如果一级缓存没有命中,则查询数据库
- SqlSession关闭之后,一级缓存中的数据会写入二级缓存
MyBatis的二级缓存为什么不包含了一级缓存呢?
MyBatis的逆向工程
正向工程:先创建Java实体类,由框架负责根据实体类生成数据库表。Hibernate是支持正向工程的。
逆向工程:先创建数据库表,由框架负责根据数据库表,反向生成如下资源:
- Java实体类
- Mapper接口
- Mapper映射文件
v
MyBatis的分页和逆向工程以及二级缓存不理解!