Mybatis详解(一)
概述
MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生类型、接口和 Java 的 POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
mybatis安装配置
maven依赖
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
SqlSessionFactory
一个SqlSessionFactory只能连接一个数据库实例,如果需要连接多个数据库,需要构建多个SqlSessionFactory对象
从XML中构建
引入外部配置<properties>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 导入外部配置文件 -->
<properties resource="jdbc.properties"/>
</configuration>
配置参数<settings>
配置参数说明
settings支持的属性
设置名 | 描述 | 有效值 | 默认值 |
---|---|---|---|
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 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。 | SIMPLE REUSE BATCH | SIMPLE |
defaultStatementTimeout | 设置超时时间,它决定驱动等待数据库响应的秒数。 | 任意正整数 | 未设置 (null) |
defaultFetchSize | 为驱动的结果集获取数量(fetchSize)设置一个提示值。此参数只可以在查询设置中被覆盖。 | 任意正整数 | 未设置 (null) |
safeRowBoundsEnabled | 允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。 | true | false | False |
safeResultHandlerEnabled | 允许在嵌套语句中使用分页(ResultHandler)。如果允许使用则设置为 false。 | true | false | True |
mapUnderscoreToCamelCase | 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。 | true | false | False |
localCacheScope | MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。 默认值为 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 | JDKLOGGING | COMMONSLOGGING | STDOUTLOGGING | NOLOGGING | 未设置 |
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>
<!-- 覆盖JDBC驱动中默认查询结果集的数量。默认值:null(未设置) -->
<setting name="defaultFetchSize" value="10"/>
<!-- 是否自动将数据库字段映射成小驼峰样式的POJO属性名,如数据库中是create_time,会自动映射成createTime。 默认值: false -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 一级缓存生效范围: SESSION(一次会话)、STATEMENT(一次statement)。默认值:SESSION -->
<setting name="localCacheScope" value="SESSION"/>
<!-- 全局的开启、关闭所有Mapper文件中配置的二级缓存。默认值:true -->
<setting name="cacheEnabled" value="true" />
<!-- 发现无法映射字段时如何处理: NONE(不做处理)、WARNING(输出警告日志)、FAILING(抛出SQLException异常)。 默认值:NONE -->
<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
<!-- 指定 MyBatis 应如何自动映射列到字段或属性。NONE(不自动映射)、PARTIAL(只映射单表查询)、FULL(级联映射多表查询结果集)。默认值:PARTIAL -->
<setting name="autoMappingBehavior" value="NONE" />
<!-- 全局延迟加载开关(针对关联对象),可在具体Mapper中通过fetchType覆盖这里的全局开关状态。默认值:false -->
<setting name="lazyLoadingEnabled" value="true" />
<!-- 是否使用数据库自动生成主键值,默认值:false -->
<setting name="useGeneratedKeys" value="true" />
</settings>
类型别名<typeAliases>
类型别名是为 Java 类型设置一个短的名字。 它只和 XML 配置有关,存在的意义仅在于用来减少类完全限定名的冗余。例如:
<typeAliases>
<typeAlias alias="Author" type="domain.blog.Author"/>
<typeAlias alias="Blog" type="domain.blog.Blog"/>
<typeAlias alias="Comment" type="domain.blog.Comment"/>
<typeAlias alias="Post" type="domain.blog.Post"/>
<typeAlias alias="Section" type="domain.blog.Section"/>
<typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>
当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases>
<package name="domain.blog"/>
</typeAliases>
常见的内建别名
一些为常见的 Java 类型内建的相应的类型别名。它们都是不区分大小写的,注意对基本类型名称重复采取的特殊命名风格。
别名 | 映射的类型 |
---|---|
_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 |
类型转换器<typeHandlers>
无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器。
类型处理器 | Java 类型 | JDBC 类型 |
---|---|---|
BooleanTypeHandler | java.lang.Boolean , boolean | 数据库兼容的 BOOLEAN |
ByteTypeHandler | java.lang.Byte , byte | 数据库兼容的 NUMERIC 或 BYTE |
ShortTypeHandler | java.lang.Short , short | 数据库兼容的 NUMERIC 或 SMALLINT |
IntegerTypeHandler | java.lang.Integer , int | 数据库兼容的 NUMERIC 或 INTEGER |
LongTypeHandler | java.lang.Long , long | 数据库兼容的 NUMERIC 或 BIGINT |
FloatTypeHandler | java.lang.Float , float | 数据库兼容的 NUMERIC 或 FLOAT |
DoubleTypeHandler | java.lang.Double , double | 数据库兼容的 NUMERIC 或 DOUBLE |
BigDecimalTypeHandler | java.math.BigDecimal | 数据库兼容的 NUMERIC 或 DECIMAL |
StringTypeHandler | java.lang.String | CHAR , VARCHAR |
ClobReaderTypeHandler | java.io.Reader | - |
ClobTypeHandler | java.lang.String | CLOB , LONGVARCHAR |
NStringTypeHandler | java.lang.String | NVARCHAR , NCHAR |
NClobTypeHandler | java.lang.String | NCLOB |
BlobInputStreamTypeHandler | java.io.InputStream | - |
ByteArrayTypeHandler | byte[] | 数据库兼容的字节流类型 |
BlobTypeHandler | byte[] | BLOB , LONGVARBINARY |
DateTypeHandler | java.util.Date | TIMESTAMP |
DateOnlyTypeHandler | java.util.Date | DATE |
TimeOnlyTypeHandler | java.util.Date | TIME |
SqlTimestampTypeHandler | java.sql.Timestamp | TIMESTAMP |
SqlDateTypeHandler | java.sql.Date | DATE |
SqlTimeTypeHandler | java.sql.Time | TIME |
ObjectTypeHandler | Any | OTHER 或未指定类型 |
EnumTypeHandler | Enumeration Type | VARCHAR 或任何兼容的字符串类型,用以存储枚举的名称(而不是索引值) |
EnumOrdinalTypeHandler | Enumeration Type | 任何兼容的 NUMERIC 或 DOUBLE 类型,存储枚举的序数值(而不是名称)。 |
SqlxmlTypeHandler | java.lang.String | SQLXML |
InstantTypeHandler | java.time.Instant | TIMESTAMP |
LocalDateTimeTypeHandler | java.time.LocalDateTime | TIMESTAMP |
LocalDateTypeHandler | java.time.LocalDate | DATE |
LocalTimeTypeHandler | java.time.LocalTime | TIME |
OffsetDateTimeTypeHandler | java.time.OffsetDateTime | TIMESTAMP |
OffsetTimeTypeHandler | java.time.OffsetTime | TIME |
ZonedDateTimeTypeHandler | java.time.ZonedDateTime | TIMESTAMP |
YearTypeHandler | java.time.Year | INTEGER |
MonthTypeHandler | java.time.Month | INTEGER |
YearMonthTypeHandler | java.time.YearMonth | VARCHAR 或 LONGVARCHAR |
JapaneseDateTypeHandler | java.time.chrono.JapaneseDate | DATE |
你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。 具体做法为:实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的类 org.apache.ibatis.type.BaseTypeHandler, 然后可以选择性地将它映射到一个 JDBC 类型。
多环境配置
Mybatis支持多环境对应不同的配置,例如:开发、测试和生产环境需要有不同的配置
- 尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。
- 每个数据库对应一个 SqlSessionFactory 实例
根据特定的环境配置构建SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(reader, environment);
多环境配置示例
<!-- 多环境配置根节点,并设置默认启用的环境 -->
<environments default="development">
<!-- 定义development环境参数 -->
<environment id="development">
<!-- 指定事务配置 -->
<transactionManager type="JDBC">
<property name="..." value="..."/>
</transactionManager>
<!-- 配置数据源 -->
<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 中有两种类型的事务管理器(也就是 type=”[JDBC|MANAGED]”)
JDBC
这个配置就是直接使用了 JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
MANAGED
这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为,如:
<transactionManager type="MANAGED">
<property name="closeConnection" value="false"/>
</transactionManager>
通过Spring管理事务
如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器, 因为 Spring 模块会使用自带的管理器来覆盖前面的配置。
数据源
-
UNPOOLED:不使用连接池的数据源。
-
POOLED:使用连接池的数据源。
-
JNDI:使用JNDI实现的数据源。
-
通过Spring提供数据源:顾名思义使用的是spring框架中提供的数据源,
关于数据源有需要了解的更加详细的读者可以阅读下面给大家提供博客大神的文章。
作者:亦山
来源:CSDN
原文:https://blog.csdn.net/luanlouis/article/details/37671851
映射器Mappers
Mapper映射文件用来定义SQL映射语句
我们可以通过以下几种方式来指定Mapper映射文件的位置
<!-- 使用相对于类路径的资源引用 -->
<mappers>
<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
<mapper resource="org/mybatis/builder/BlogMapper.xml"/>
<mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
<mapper url="file:///var/mappers/AuthorMapper.xml"/>
<mapper url="file:///var/mappers/BlogMapper.xml"/>
<mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 导入基于注解配置的Mapper -->
<mappers>
<mapper class="org.mybatis.builder.AuthorMapper"/>
<mapper class="org.mybatis.builder.BlogMapper"/>
<mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
<package name="org.mybatis.builder"/>
</mappers>
通过硬代码构建
一般不会用到这种方式,不够灵活,且太过繁琐
SqlSession
-
用于真正执行SQL语句的对象
-
操作事务:提交、回滚
-
非线程安全的,不能作为一个类的静态变量,最好是用完就再finally块中关掉它
Mapper
mapper用于映射数据库CRUD(增删改查)操作,将SQL语句和Java接口进行绑定
基于XML方式映射SQL
定义XML SQL配置文件
<?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.spring.mapper.StudentMapper">
<select id="queryAll" resultType="Student">
select * from student
</select>
</mapper>
定义对应的Mapper接口
public interface StudentMapper {
List<Student> queryAll();
}
XML Mapper详解
<insert>、<delete>、<update>
<insert>
、<delete>
、<update>
三个标签分别用来映射插入、删除、更新语句,实现非常类似,下面是他们的使用示例
<insert id="insertAuthor">
insert into Author (id,username,password,email,bio)
values (#{id},#{username},#{password},#{email},#{bio})
</insert>
<update id="updateAuthor">
update Author set
username = #{username},
password = #{password},
email = #{email},
bio = #{bio}
where id = #{id}
</update>
<delete id="deleteAuthor">
delete from Author where id = #{id}
</delete>
处理主键的自动生成
<!-- 获取数据库(如mysql、sqlserver)自增的id -->
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username,password,email,bio)
values (#{username},#{password},#{email},#{bio})
</insert>
<!-- 批量插入,并获取自增的id -->
<insert id="insertAuthor" useGeneratedKeys="true"
keyProperty="id">
insert into Author (username, password, email, bio) values
<foreach item="item" collection="list" separator=",">
(#{item.username}, #{item.password}, #{item.email}, #{item.bio})
</foreach>
</insert>
<insert>、<delete>、<update>标签可用属性说明
属性 | 描述 |
---|---|
id | 命名空间中的唯一标识符,可被用来代表这条语句。 |
parameterType | 将要传入语句的参数的完全限定类名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap | 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:true(对于 insert、update 和 delete 语句)。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
useGeneratedKeys | (仅对 insert 和 update 有用)这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键(比如:像 MySQL 和 SQL Server 这样的关系数据库管理系统的自动递增字段),默认值:false。 |
keyProperty | (仅对 insert 和 update 有用)唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认值:未设置(unset )。如果希望得到多个生成的列,也可以是逗号分隔的属性名称列表。 |
keyColumn | (仅对 insert 和 update 有用)通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。如果希望使用多个生成的列,也可以设置为逗号分隔的属性名称列表。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
<select>
<select>
标签用于定义查询语句
简单示例
<select id="selectPerson" parameterType="int" resultType="hashmap">
SELECT * FROM PERSON WHERE ID = #{id}
</select>
上面的配置告诉mybatis需要创建一个像下面这样的预处理语句:
// 近似的 JDBC 代码,非 MyBatis 代码...
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);
select标签所支持的属性说明
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句。 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。 |
parameterMap | 这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。 |
resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。 |
resultMap | 外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃而解。可以使用 resultMap 或 resultType,但不能同时使用。 |
flushCache | 将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。 |
useCache | 将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。 |
timeout | 这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。 |
fetchSize | 这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。 |
statementType | STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。 |
resultSetType | FORWARDONLY,SCROLLSENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。 |
databaseId | 如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。 |
resultOrdered | 这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false 。 |
resultSets | 这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。 |
<sql>
<sql>
标签用来定义可复用的SQL语句片段,这些 SQL 代码可以被包含在其他语句中。它可以(在加载的时候)被静态地设置参数。 在不同的包含语句中可以设置不同的值到参数占位符上。比如:
<sql id="userColumns"> ${alias}.id,${alias}.username,${alias}.password </sql>
使用:
<select id="selectUsers" resultType="map">
select
<include refid="userColumns"><property name="alias" value="t1"/></include>,
<include refid="userColumns"><property name="alias" value="t2"/></include>
from some_table t1
cross join some_table t2
</select>
<cache>
开启当前Mapper的二级缓存,我们只需在Mapper配置文件中写一行:
<cache />
这样就开启了当前Mapper命名空间下的二级缓存,具体效果如下:
- 映射语句文件中的所有 select 语句的结果将会被缓存。
- 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
- 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
- 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
- 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
- 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
如果有必要,我们还可以进一步指定二级缓存的策略:
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突。
其他可用的缓存清除策略有:
LRU
– 最近最少使用:移除最长时间不被使用的对象。FIFO
– 先进先出:按对象进入缓存的顺序来移除它们。SOFT
– 软引用:基于垃圾回收器状态和软引用规则移除对象。WEAK
– 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
<cache-ref>
用于引用其他Mapper中定义的二级缓存策略,如:
<cache-ref namespace="com.someone.application.data.SomeMapper"/>
结果集映射
<resultMap>
resultMap通常用于比较复杂的结果集映射(如:多表关联查询)的情况,使用步骤如下:
- 显示定义
<resultMap>
标签映射结果集
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
- 在查询语句中引用我们定义的resultMap:
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
resultType
直接映射成简单数据类型
<select id="selectUsers" resultType="map">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
映射成自定义POJO
<select id="selectUsers" resultType="com.someapp.model.User">
select id, username, hashedPassword
from some_table
where id = #{id}
</select>
- 上述示例中resultType还可以通过配置别名减少代码书写量
- 当我们配置resultType是自定义的POJO类型时,其实mybatis在底层也是通过帮我们生成一个配置来实现的
如果数据库字段和POJO中不一致时
- 通过sql查询别名
<select id="selectUsers" resultType="User">
select
user_id as "id",
user_name as "userName",
hashed_password as "hashedPassword"
from some_table
where id = #{id}
</select>
- 通过显示定义
<resultMap>
标签解决
参数
简单类型参数
示例:
<select id="selectUsers" resultType="User" parameterType="int">
select id, username, password
from users
where id = #{id}
</select>
上面的这个示例说明了一个非常简单的命名参数映射。参数类型被设置为 int,这样这个参数就可以被设置成任何内容。原始类型或简单数据类型(比如 Integer 和 String)因为没有相关属性,它会完全用参数值来替代。
复杂类型参数
示例:
<insert id="insertUser" parameterType="User">
insert into users (id, username, password)
values (#{id}, #{username}, #{password})
</insert>
我们将User 类型的参数对象传递到了语句中,id、username 和 password 属性将会被查找,然后将它们的值传入预处理语句的参数中。
#{}与${}
默认情况下,使用 #{} 格式的语法会导致 MyBatis 创建 PreparedStatement 参数占位符并安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中插入一个不转义的字符串。 比如,像 ORDER BY,你可以这样来使用:
ORDER BY ${columnName}
这里 MyBatis 不会修改或转义字符串。
典型的应用场景:
像这样的三个方法
@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);
@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);
@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);
我们可以直接用一个替代
@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);
按名称引用参数
由于Java编译是默认只会保留方法参数类型,方法参数名称会被丢掉,mybatis 3.4.3之前我们在映射文件中只能通过#, ...来按顺序引用传进来的参数
<select id="queryByIdAndAge" resultType="Teacher">
select * from teacher where id = #{param1} and age <= #{param2};
</select>
@Param注解
我们在处理一个带有多个形参的构造方法时,很容易搞乱 arg 元素的顺序。 从版本 3.4.3 开始, 我们可以通过名称来引用构造方法参数,通过给方法参数添加 @Param 注解。用法:
Java代码
List<Teacher> queryByIdAndAge(@Param("tid") int id, @Param("age") int age);
Xml代码
<select id="queryByIdAndAge" parameterType="int" resultType="Teacher">
select * from teacher where id = #{tid} and age <= #{age};
</select>
另外,想使用参数名引用参数,我们也可以使用JDK8里面新增的 '-parameters' 编译选项保留方法参数,并启用mybatis中的useActualParamName 选项(默认开启)来编译项目
用法:
javac -parameters xxx.java
maven 中用法:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<compilerArgument>-parameters</compilerArgument>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
基于注解方式映射SQL
示例:
public interface TeacherMapper {
@Insert("insert into teacher(tname) values (#{tname})")
int insertTeacher(Teacher teacher);
}
mybatis最初设计时就是一个基于XML驱动的框架。虽然从Mybatis3开始Mybatis支持了很多基于注解方式的配置,但从实际使用来看,也仅适用于比较简单的场景下。像一些比较复杂的结果集映射用注解写出来可读性和可维护性就很低。
上面并不是说注解配置就一无是处, 比如一些简单的单表CRUD语句我们就可以直接通过注解来配置, 而不在需要单独写一个XML映射文件
Mybatis支持的所有注解说明
注解 | 使用对象 | 相对应的 XML | 描述 |
---|---|---|---|
@CacheNamespace | 类 | <cache> | 为给定的命名空间(比如类)配置缓存。属性有:implemetation , eviction , flushInterval , size , readWrite , blocking 和properties 。 |
@Property | N/A | <property> | 指定参数值或占位值(placeholder)(能被 mybatis-config.xml 内的配置属性覆盖)。属性有:name , value 。(仅在MyBatis 3.4.2以上版本生效) |
@CacheNamespaceRef | 类 | <cacheRef> | 参照另外一个命名空间的缓存来使用。属性有:value , name 。如果你使用了这个注解,你应设置 value 或者 name 属性的其中一个。value 属性用于指定 Java 类型而指定命名空间(命名空间名就是指定的 Java 类型的全限定名),name 属性(这个属性仅在MyBatis 3.4.2以上版本生效)直接指定了命名空间的名字。 |
@ConstructorArgs | 方法 | <constructor> | 收集一组结果传递给一个结果对象的构造方法。属性有:value ,它是形式参数数组。 |
@Arg | N/A | <arg>``<idArg> | 单参数构造方法,是 ConstructorArgs 集合的一部分。属性有:id , column , javaType , jdbcType , typeHandler , select 和 resultMap 。id 属性是布尔值,来标识用于比较的属性,和<idArg> XML 元素相似。 |
@TypeDiscriminator | 方法 | <discriminator> | 一组实例值被用来决定结果映射的表现。属性有:column , javaType , jdbcType , typeHandler 和 cases 。cases 属性是实例数组。 |
@Case | N/A | <case> | 单独实例的值和它对应的映射。属性有:value , type , results 。results 属性是结果数组,因此这个注解和实际的 ResultMap 很相似,由下面的 Results 注解指定。 |
@Results | 方法 | <resultMap> | 结果映射的列表,包含了一个特别结果列如何被映射到属性或字段的详情。属性有:value , id 。value 属性是 Result 注解的数组。这个 id 的属性是结果映射的名称。 |
@Result | N/A | <result>``<id> | 在列和属性或字段之间的单独结果映射。属性有:id , column , javaType , jdbcType , typeHandler , one , many 。id 属性是一个布尔值,来标识应该被用于比较(和在 XML 映射中的<id> 相似)的属性。one 属性是单独的联系,和 <association> 相似,而 many 属性是对集合而言的,和<collection> 相似。它们这样命名是为了避免名称冲突。 |
@One | N/A | <association> | 复杂类型的单独属性值映射。属性有:select ,已映射语句(也就是映射器方法)的全限定名,它可以加载合适类型的实例。fetchType 会覆盖全局的配置参数 lazyLoadingEnabled 。注意 联合映射在注解 API中是不支持的。这是因为 Java 注解的限制,不允许循环引用。 |
@Many | N/A | <collection> | 映射到复杂类型的集合属性。属性有:select ,已映射语句(也就是映射器方法)的全限定名,它可以加载合适类型的实例的集合,fetchType 会覆盖全局的配置参数 lazyLoadingEnabled 。注意 联合映射在注解 API中是不支持的。这是因为 Java 注解的限制,不允许循环引用 |
@MapKey | 方法 | 这是一个用在返回值为 Map 的方法上的注解。它能够将存放对象的 List 转化为 key 值为对象的某一属性的 Map。属性有: value ,填入的是对象的属性名,作为 Map 的 key 值。 | |
@Options | 方法 | 映射语句的属性 | 这个注解提供访问大范围的交换和配置选项的入口,它们通常在映射语句上作为属性出现。Options 注解提供了通俗易懂的方式来访问它们,而不是让每条语句注解变复杂。属性有:useCache=true , flushCache=FlushCachePolicy.DEFAULT , resultSetType=DEFAULT , statementType=PREPARED , fetchSize=-1 , timeout=-1 , useGeneratedKeys=false , keyProperty="" , keyColumn="" , resultSets="" 。值得一提的是, Java 注解无法指定 null 值。因此,一旦你使用了 Options 注解,你的语句就会被上述属性的默认值所影响。要注意避免默认值带来的预期以外的行为。 注意: keyColumn 属性只在某些数据库中有效(如 Oracle、PostgreSQL等)。请在插入语句一节查看更多关于 keyColumn 和 keyProperty 两者的有效值详情。 |
@Insert @Update @Delete @Select | 方法 | <insert> <update> <delete> <select> | 这四个注解分别代表将会被执行的 SQL 语句。它们用字符串数组(或单个字符串)作为参数。如果传递的是字符串数组,字符串之间先会被填充一个空格再连接成单个完整的字符串。这有效避免了以 Java 代码构建 SQL 语句时的“丢失空格”的问题。然而,你也可以提前手动连接好字符串。属性有:value ,填入的值是用来组成单个 SQL 语句的字符串数组。 |
@InsertProvider @UpdateProvider @DeleteProvider @SelectProvider | 方法 | <insert> <update> <delete> <select> | 允许构建动态 SQL。这些备选的 SQL 注解允许你指定类名和返回在运行时执行的 SQL 语句的方法。(自从MyBatis 3.4.6开始,你可以用 CharSequence 代替 String 来返回类型返回值了。)当执行映射语句的时候,MyBatis 会实例化类并执行方法,类和方法就是填入了注解的值。你可以把已经传递给映射方法了的对象作为参数,"Mapper interface type" 和 "Mapper method" and "Database ID" 会经过 ProviderContext (仅在MyBatis 3.4.5及以上支持)作为参数值。(MyBatis 3.4及以上的版本,支持多参数传入) 属性有: type , method 。 type 属性需填入类。 method 需填入该类定义了的方法名 (Since 3.5.1, you can omit method attribute, the MyBatis will resolve a target method via the ProviderMethodResolver interface. If not resolve by it, the MyBatis use the reserved fallback method that named provideSql )。 注意 接下来的小节将会讨论类,能帮助你更轻松地构建动态 SQL。 |
@Param | 参数 | N/A | 如果你的映射方法的形参有多个,这个注解使用在映射方法的参数上就能为它们取自定义名字。若不给出自定义名字,多参数(不包括 RowBounds 参数)则先以 "param" 作前缀,再加上它们的参数位置作为参数别名。例如 #{param1} , #{param2} ,这个是默认值。如果注解是 @Param("person") ,那么参数就会被命名为 #{person} 。 |
@SelectKey | 方法 | <selectKey> | 这个注解的功能与 <selectKey> 标签完全一致,用在已经被 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 注解了的方法上。若在未被上述四个注解的方法上作 @SelectKey 注解则视为无效。如果你指定了 @SelectKey 注解,那么 MyBatis 就会忽略掉由 @Options 注解所设置的生成主键或设置(configuration)属性。属性有:statement 填入将会被执行的 SQL 字符串数组,keyProperty 填入将会被更新的参数对象的属性的值,before 填入 true 或 false 以指明 SQL 语句应被在插入语句的之前还是之后执行。resultType 填入 keyProperty 的 Java 类型和用 Statement 、 PreparedStatement 和 CallableStatement 中的 STATEMENT 、 PREPARED 或 CALLABLE 中任一值填入 statementType 。默认值是 PREPARED 。 |
@ResultMap | 方法 | N/A | 这个注解给 @Select 或者 @SelectProvider 提供在 XML 映射中的 <resultMap> 的id。这使得注解的 select 可以复用那些定义在 XML 中的 ResultMap。如果同一 select 注解中还存在 @Results 或者 @ConstructorArgs ,那么这两个注解将被此注解覆盖。 |
@ResultType | 方法 | N/A | 此注解在使用了结果处理器的情况下使用。在这种情况下,返回类型为 void,所以 Mybatis 必须有一种方式决定对象的类型,用于构造每行数据。如果有 XML 的结果映射,请使用 @ResultMap 注解。如果结果类型在 XML 的 <select> 节点中指定了,就不需要其他的注解了。其他情况下则使用此注解。比如,如果 @Select 注解在一个将使用结果处理器的方法上,那么返回类型必须是 void 并且这个注解(或者@ResultMap)必选。这个注解仅在方法返回类型是 void 的情况下生效。 |
@Flush | 方法 | N/A | 如果使用了这个注解,定义在 Mapper 接口中的方法能够调用 SqlSession#flushStatements() 方法。(Mybatis 3.3及以上) |
获取Mapper接口
通过SqlSession对象调用相应的Mapper接口完成对数据库的操作,示例:
BlogMapper mapper = session.getMapper(BlogMapper.class);
// 调用mapper中的查询一个blog对象的方法
Blog blog = mapper.selectBlog(101);
到了这里mybatis的基本的增删改查操作都已经说完了,但是我们这一章讲述的都是怎么操作一章表的数据,那么多张表的关联操作应该怎么做呢?那就需要看下一章的内容了。
下章内容:动态SQL、缓存、关联查询,以及通过工具生成一个数据库表在Java对应的实体类、mapper接口、mapper配置文件和Spring Mybatis的整合等。