目录
MyBatis
一、什么是ORM
ORM(对象关系映射):为了解决面向对象与关系型数据库中数据类型不匹配的技术
二、常见的ORM框架
1. MyBatis
是半自动映射框架,需要手动匹配提供POJO、SQL和映射关系
虽然需要手动编写SQL,但MyBatis可以可以配置动态SQL并且优化SQL,可以通过配置决定SQL的映射规则,支持存储过程。
2. Hibernate
全自动映射框架,只需要提供POJO和映射关系即可
三、MyBatis的核心配置
1. MyBatis核心对象
1.1 SqlSessionFactory
SqlSessionFactory是单个数据库映射关系经过编译后的内存镜像,主要作用就是创建SqlSession。SqlSessionFactory对象的实例可以通过SqlSessionFactoryBuilder对象来构建,而SqlSessionFactoryBuilder可以通过XML配置文件或一个预先定义好的Configuration实例构建出SqlSessionFactory实例
SqlSessionFactory对象是线程安全的,一旦被创建在整个应用执行期间都存在。如果多次的创建同一个数据库的SqlSessionFactory,那么此数据库的资源很容易被耗尽。所以构建SqlSessionFactory实例时,建议使用单例模式。
1.2 SqlSession
SqlSession是应用程序与持久层之间执行交互操作的一个单线程对象,主要就是执行持久化操作。SqlSession对象包含了数据库中所有执行SQL操作的方法,底层封装的是JDBC连接,所以可以直接使用其实例来执行已映射的SQL语句。
每一个线程都应该有自己的SqlSession实例,不能被共享。SqlSession实例线程是不安全的,使用范围最好在一次请求或一个方法中,使用完SqlSession对象后,要及时关闭(finally块中关闭)。
安装
要使用 MyBatis, 只需将 mybatis-x.x.x.jar 文件置于类路径(classpath)中即可。
如果使用 Maven 来构建项目,则需将下面的依赖代码置于 pom.xml 文件中:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
2. 配置文件
2.1 主要元素
configuration元素是配置文件的根元素,其他元素都要在configuration元素内配置。
<properties> | |||
---|---|---|---|
<settings> | |||
<typeAliases> | |||
<typeHandlers> | |||
<configuration>根元素 | <objectFactory> | ||
<plugins> | |||
<environments> | <environment> | <transactionManager><dataSource> | |
<datebaseIdProvider> | |||
<mappers> |
configuration的子元素必须按照上图由上到下的顺序进行配置,否则Mybatis在解析XML配置文件的时候会报错
2.2 properties元素
properties是一个配置属性的元素,通常用于将内部的配置外在化,通过外部的配置来动态地替换内部定义的属性。例如数据库的连接等属性,可以通过Java属性文件中的配置来替换
(1)在src目录下创建文件database.properties
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/user?useUnicode=true&characterEncoding=utf-8
user=root
password=root
(2)在配置文件mybatis-config.xml中配置 <properties />元素
<properties resource="database.properties"/>
(3)修改配置文件中数据库连接信息
<dataSource type="POOLED">
<!-- 数据库驱动 -->
<property name="driver" value="${driver}" />
<!-- 连接数据库的url -->
<property name="url" value="${url}" />
<!-- 连接数据库的用户名 -->
<property name="username" value="${username}" />
<!-- 连接数据库的密码 -->
<property name="password" value="${password}" />
</dataSource>
除了通过外部配置文件来定义属性值外,还可以通过配置<properties>元素的子元素<property>,以及通过方法参数传递的的方式来获取属性值。由于使用properties配置文件来配置属性值可以方便地在多个配置文件中使用这些属性值,并且方便日后修改,所以在实际开发中,使用properties配置文件来配置属性值是最常用的方式。
2.3 settings元素
settings元素主要是改变MyBatis运行时的行为,例如开启二级缓存、开启延迟加载等。
settings元素中的配置描述 https://blog.csdn.net/ZGL_cyy/article/details/111739893
<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"/>
</settings>
2.4 typeAliases元素
typeAliases元素用于为配置文件中的Java类型设置一个简短的名字(别名)。减少全限定类名的冗余
<typeAliases>
<!-- type属性用来指定需要被定义别名的类的全限定名,alias属性的属性值就是自定义的别名可以代替type的值使用在MyBatis文件的任何位置,如果没有alias属性,MyBatis会默认将类名首字母小写后的名称作为别名 -->
<typeAlias type="com.mybatis.entity" alias="user"/>
</typeAliases>
当POJO类过多时可以通过自动扫描包的形式自定义别名
<typeAliases>
<!-- typeAliases元素中的子元素package中的name属性用来指定要被定义别名的包,MyBatis会将所有com.mybatis.entity包中的POJO类以首字母小写的非限定类名作为它的别名 例如User类名别名为user -->
<package name="com.mybatis.entity"/>
</typeAliases>
注解方式(别名)
@Alias(value = "user")
public class User {
}
除了typeAliases元素自定义别名外,MyBati还为许多常见Java类型提供了相应的类型别名(可以直接在MyBatis中使用,由于别名不区分大小写,所以在使用时要注意重复定义的覆盖问题)
2.5 typeHandler元素
MyBatis在预处理语句中(PreparedStatement)中设置一个参数或者从结果集(ResultSet)中取出一个值时,都会用框架内部注册了的typeHandler(类型处理器)进行相关处理。其作用是将预处理语句中传入的参数从javaType(Java类型)转换为jdbcType(JDBC类型)或者是从数据库取出结果时将javaType转换为jdbcType
MyBatis还提供了默认的类型处理器,也可以通过自定义的方式对类型处理器进行扩展(自定义类型处理器可以通过实现typeHandler接口或者继承BaseTypeHandler类来定义)typeHandler就是用来在配置文件中注册自定义类型处理器的
(1)注册类的类型处理器
<typeHandlers>
<package name="com.dy.demo"/>
<!-- handler属性用来指定在程序中自定义的类型处理器类 -->
<typeHandler handler=""/>
</typeHandlers>
(2)注册包中所有的类型处理器
<typeHandlers>
<!-- name用来指定类型处理器所在的包名 -->
<package name="com.dy.demo"/>
</typeHandlers>
2.6 objectFactory元素
MyBatis框架每次创建结果对象的新实例时,都会使用一个对象的工厂(ObjectFactory)的实例来完成。objectFactory在MyBatis中默认的作用就是实例化目标类,可以通过默认构造方法实例化,也可以在参数映射存在的时候通过参数构造方法来实例化
2.7 plugins元素
plugins的作用就是配置用户所开发的插件
2.8 environments元素
在配置文件中,environments元素用来对环境进行配置。MyBatis的环境配置实际就是数据源的配置,可以通过environments元素配置多种数据源,即配置多种数据库。
<!-- default属性用来指定默认的环境 -->
<environments default="development">
<!-- environment是environments元素的子元素,可以定义多个,id属性用于表示所定义环境的ID值 -->
<environment id="development">
<!-- 使用jdbc事务管理 type属性为指定事务管理的方式 -->
<transactionManager type="JDBC" />
<!-- 配置数据源 type属性指定使用哪种数据源 -->
<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>
MyBatis中可以配置两种类型的事务管理器
JDBC:直接使用了JDBC的提交和回滚设置,依赖于数据源得到的连接来管理事务的作用域。
MANAGED:从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期。默认情况下,会关闭连接,可以将coloseConnection属性设置为false来阻止它默认的关闭行为。
对于数据源的配置,MyBatis提供了三种数据源类型
(1)UNPOOLED
在每次被请求时会打开和关闭连接,对性能没有要求。
(2)POOLED
利用"池"的概念将JDBC连接对象组织起来,避免了在创建新的连接实例时所需要初始化和认证的时间。这种方式是的并发Web应用可以快速地响应请求。
(3)JNDI
可以在EJB或应用服务器等容器中使用。容器可以集中或在外部配置数据源,然后放置一个JNDI上下文的引用。
2.9 mappers元素
在配置文件中,mappers元素用来指定MyBatis映射文件的位置
(1)使用类路径引入
<mappers>
<mapper resource="com/dy/dao/userDao.xml"/>
</mappers>
(2)使用本地文件路径引入
<mappers>
<mapper url="file://........"/>
</mappers>
(3)使用接口引入
<mappers>
<mapper class="com.dy.dao.UserDao"/>
</mappers>
(4)使用包名引入
<mappers>
<package name="com.dy.dao"/>
</mappers>
3. 映射文件
3.1 主要元素
在映射文件中,mapper元素是映射文件的根元素,其他都是它的子元素
3.1.1 select元素
查询语句,可以从数据库中读取出数据 select元素常用属性可自行上网了解
<!-- id表示命名空间中的唯一标识符 resultMap表示外部的命名引用 -->
<select id="" resultMap="">
<!-- 查询SQL语句 -->
</select>
3.1.2 insert元素
添加语句,添加数据
<insert id="">
<!-- 添加SQL语句 -->
</insert>
parameterType :
入参的全限定类名或类型别名
keyColumn :
设置数据表自动生成的主键名。对特定数据库(如PostgreSQL),若自动生成的主键不是第一个字段则必须设置
keyProperty :
默认值unset,用于设置getGeneratedKeys方法或selectKey子元素返回值将赋值到领域模型的哪个属性中useGeneratedKeys :
取值范围true|false(默认值),设置是否使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。MySQL和SQLServer执行auto-generated key field,因此当数据库设置好自增长主键后,可通过JDBC的getGeneratedKeys方法获取。但像Oralce等不支持auto-generated key field的数据库就不能用这种方法获取主键了
3.1.3 update、delete元素
他们的属性配置基本都相同
修改语句
<update id="">
<!-- 修改SQL语句 -->
</update>
删除语句
<delete id="">
<!-- 删除SQL语句 -->
</delete>
3.1.4 sql元素
在一个映射文件中,通常会定义多条sql语句,这些sql语句的组成可能会有一部分是相同的(如多条sql语句中都查询相同id, name, age, phone, job.....字段)如果每一个查询语句都这么写,势必会增加代码量,导致映射文件过于臃肿。
<!-- 定义可重用的SQL代码,可以在其他语句中引用这一段代码 -->
<sql id="user">id, name, age, phone, job</sql>
<select id="" resultMap="">
<!-- refid的属性值为自定义代码片段的id -->
select<include refid="user"/>
<!-- 查询SQL语句 -->
</select>
3.1.5 resultMap元素
表示结果映射集,主要作用是定义映射规则、级联的更新以及定义类型转化器等
<!-- resultMap的元素结构 -->
<resultMap id="" type="">
<constructor><!-- 类再实例化时用来注入结果到构造方法 -->
<idArg/><!-- ID参数,结果为ID -->
<arg/><!-- 注入到构造方法的一个普通结果 -->
</constructor>
<id/><!-- 用于表示哪个列是主键 -->
<result/><!-- 注入到字段或JavaBean属性的普通结果 -->
<association property=""/><!-- 用于一对一关联 -->
<collection property=""/><!-- 用于一对多、多对多关联 -->
<discriminator javaType=""><!-- 使用结果值来决定使用哪个结果映射 -->
<case value=""/><!-- 基于某些值的结果映射 -->
</discriminator>
</resultMap>
resultMap元素的type属性表示需要映射的POJO,id属性是这个resultMap的唯一标识。
在默认情况下,MyBatis程序在运行时会自动地将查询到的数据与需要返回的对象的属性进行匹配赋值(需要表中的列名与对象的属性名称完全一致)resultMap就是用来处理列名与对象名不同的
四、动态SQL
MyBatis动态SQL中的主要元素
<if> | 判断语句 |
---|---|
<choose> (<when>、<otherwise>) | 相当于Java的switch...case...default语句,用于多条件分支判断 |
<where>、<trim>、<set> | 辅助元素,用于处理一些SQL拼装、特殊字符问题 |
<foreach> | 循环语句,常用于in语句等列举条件中 |
<bind> | 从OGNL表达式中创建一个变量,并将其绑定到上下文,常用于模糊查询 |
1. if
<!-- test属性主要用于判断语句中 -->
<if test="title != null">
AND title like #{title}
</if>
2. choose (when、otherwise)
<!-- 如果第一个<when>为真的话就只动态组装第一个<when>元素内的SQL片段,否则就继续往下判断。如果当前<when>元素的条件都不为真时,则只组装<otherwise>元素内的SQL片段 -->
<choose>
<when test="username != null">
AND title like #{username}
</when>
<when test="job != null and job != ''">
AND author_name like #{job}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
3. where、trim、set
在SQL中如果where后直接跟and,在运行时肯定会报错,而加入"1=1"时即保证where后面的条件成立,又避免了where后面第一个词时and或or之类的关键词。
<where>
<if test="state != null">
state = #{state}
</if>
<if test="title != null">
AND title like #{title}
</if>
<if test="author != null and author.name != null">
AND author_name like #{author.name}
</if>
</where>
where元素会自动判断组合条件下拼装的SQL语句,只有where元素内的条件成立时,才会拼接SQL中加入where关键字,否则将不会添加;即使where之后的内容有多余的"AND"或"OR",where元素也会自动将他们去除。
还可以通过trim元素来定制需要的功能
<trim prefix="WHERE" prefixOverrides="AND |OR ">
.........
</trim>
trim元素的作用是去除一些特殊的字符串,prefix属性代表的是语句的前缀(上图是使用where来连接后面的SQL片段),而prefixOverrides属性代表的是要去除的特殊字符串(上图定义了去除SQL中的and和or)
在Hibernate中,如果想要更新某一个对象,就需要发送所有的字段给持久化对象,然而实际开发中大多数情况都是更新某一个或几个字段。如果跟新的每一条数据都要将所有的属性都更新一边,那么执行效率肯定非常差。set元素就是用来完成这一项工作的。set主要就是用来更新操作的,其主要作用是在动态包含的SQL语句前输出一个set关键字,并将SQL语句中最后一个多余的逗号去除。
<update id="updateAuthorIfNecessary">
update Author
<set>
<!-- if用来判断是否传了这个值,如果非空就将此字段进行动态SQL组装并更新。否则此字段不执行更新 -->
<if test="username != null">
username=#{username},
</if>
<if test="password != null">
password=#{password},
</if>
<if test="email != null">
email=#{email},
</if>
<if test="bio != null">
bio=#{bio}
</if>
</set>
where id=#{id}
</update>
4. foreach
同Java里的循环条件,用来筛选出符合条件的数据
<!-- item配置的是循环中当前的元素 index配置的是当前元素在集合的位置下标 -->
<!-- collection配置的list是传递过来的参数类型(首字母小写),它可以是一个array、list(或collection)、Map集合的键、POJO包装类中数组或集合类型的属性名 -->
<!-- open和close配置的是以什么符号将这些集合元素包装起来 -->
<!-- separator配置的是各个元素的间隔符 -->
<foreach item="item" index="index" collection="list" open="(" separator="," close=")">
#{item}
</foreach>
5. bind
在进行模糊查询编写SQL语句的时候,如果使用"${}"进行字符串拼接,则无法防止SQL注入问题;如果使用concat函数进行拼接,则只针对MySQL数据库有效;如果使用的是Oracle数据库,则要用连接符号"||"。这样映射文件中的SQL就要根据不同的情况提供不同形式的实现,显然比较麻烦,且不利于项目的移植。为此MyBatis提供了bind元素来解决这一问题
<select id="selectBlogsLike" resultType="Blog">
<!-- 使用bind定义一个name为pattern的变量,value属性值就是拼接的查询字符串 _parameter.getTitle()表示传递进来的参数(也可以直接写成对应的参数变量名) -->
<bind name="pattern" value="'%' + _parameter.getTitle() + '%'" />
SELECT * FROM BLOG
<!-- 在SQL语句中直接引入bind的name属性值即可进行动态SQL组装 -->
WHERE title LIKE #{pattern}
</select>
五、MyBatis的关联映射
多表间存在三种关联关系,一对一、一对多、多对多
1. 一对一
MyBatis通过resultMap元素中的子元素association来处理一对一关联关系
<association property="dept" javaType="Dept">
<result column="deptname" property="deptname"/>
</association>
association元素中,通常配置一下属性:
property:指定映射到实体类对象属性,与表字段一一对应
column:指定表中对应的字段
JavaType:指定映射到实体对象属性的类型
select:指定引入嵌套查询的子SQL语句,用于关联映射中的嵌套查询
fetchType:指定在关联查询时是否启用延迟加载。有两个属性值(lazy和eager)默认为lazy(默认关联映射延迟加载)
2. 一对多
MyBatis通过resultMap元素中的子元素collection来处理一对多关联关系
collection子元素的属性大部分与association相同,但其包含一个特殊属性ofType。ofType属性与javaType属性对应,用来指定实体对象中集合类属性所包含的元素类型
<collection property="uis" javaType="UserInfo">
<result column="username" property="username"/>
</collection>
3. 多对多
在数据库中多对多的关联关系通常使用一个中间表来维护