- 动态SQL
- Java API
- 日志
动态SQL
MyBatis 可以根据参数来动态拼接SQL, 以免为了不同业务, 而写出大量近乎雷同的SQL, 极大简化了开发
- if
- choose (when, otherwise)
- trim (where, set)
- foreach
if
1 | <select id="findActiveBlogWithTitleLike" |
如果传递了title 那么 AND title like #{title}
将会拼接到SQL中, 如果传递了author, 并且author包含了name属性, AND author_name like #{author.name}
将会被拼接到SQL.
没有
else
这点有点不习惯, 不过可以使用choose, when, otherwise
来实现if-else
choose, when, otherwise
1 | <select id="findActiveBlogLike" |
choose, when, otherwise
类似于 Java 里面的 switch
语句, 上述表示, 如果 title 不为空, 则拼接 AND title like #{title}
; 否则如果 author不为空, author.name不为空, 则拼接 AND author_name like #{author.name}
; 如果都不满足, 则拼接 AND featured = 1
;
trim, where, set
使用 if
有一个弊端, 拼接出的SQL可能会出现问题, 例如:
1 | <select id="findActiveBlogLike" |
如果都不满足, 将会拼接出:
1 | SELECT * FROM BLOG |
如果第一个不满足, 会拼接出:
1 | SELECT * FROM BLOG |
查询必定失败, 为了解决这个问题, 出现了 where
1 | <select id="findActiveBlogLike" |
where
会在至少有一个元素被拼接时插入 where 语言, 但是这样还会有 SELECT * FROM BLOG WHERE AND title like ‘someTitle’
, 这是就有了 trim
, 例如:
1 | <trim prefix="WHERE" prefixOverrides="AND |OR "> |
trim
是一个代替 where
的存在, 他能配合 if
拼接出正确的语句, 同理 set
也会出现 where
一样的问题, 这样的问题可以通过 trim
来解决.
1 | <update id="updateAuthorIfNecessary"> |
异常情况下会拼接出:
1 | update Author |
set
后的 ,
号, 会导致执行失败, 通过 trim
可写为:
1 | <trim prefix="SET" suffixOverrides=","> |
合理使用 prefix
,prefixOverrides
,suffix
,suffixOverrides
这4个标签, 可以解决这个问题
- prefix : 如果里面有字符串, 它会拼接到前面
- suffix : 如果里面有字符串, 它会拼接到后面
- prefixOverrides: 如果里面有字符串, 前面的这个字符串会被删掉
- suffixOverrides: 如果里面有字符串, 后面的这个字符串会被删掉
foreach
1 | <select id="selectPostIn" resultType="domain.blog.Post"> |
经常会出现根据id来查东西的情况, id数量不固定, 可能有多个可能有一个, 针对这种情况, 使用 foreach 可以利用变量来生成语句, 有下面的属性:
- item 类似于
for(int a in list)
中的a
- index 索引
- collection 传入的集合
- open 开头的字符
- separator 分割字符
- close 结尾的字符
其他语句
script
用于注解方式的SQL编写
1 |
|
bind
bind
元素可以从 OGNL 表达式中创建一个变量并将其绑定到上下文。比如:
1 | <select id="selectBlogsLike" resultType="Blog"> |
当sql比较复杂, 重复的比较多的使用, 用这个应该会很方便.
多数据库支持
针对不同数据库的语句不同的情况使用, 不过一般情况下, 数据库选定后不会轻易的改变, 所以这种比较少用哦.
1 | <insert id="insert"> |
动态 SQL 中的可插拔脚本语言
MyBatis 从 3.2 开始支持可插拔脚本语言,这允许你插入一种脚本语言驱动,并基于这种语言来编写动态 SQL 查询语句, MyBatis 提供了极大的可定制空间.
- 实现如下接口
1
2
3
4
5public interface LanguageDriver {
ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql);
SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType);
SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType);
} - 在 mybatis-config.xml 文件中将它设置为默认语言, 或者针对某一个语句设置特定语言.
设置为默认语言
1
2
3
4
5
6<typeAliases>
<typeAlias type="org.sample.MyLanguageDriver" alias="myLanguage"/>
</typeAliases>
<settings>
<setting name="defaultScriptingLanguage" value="myLanguage"/>
</settings>针对某一个语句设置特定语言
1
2
3<select id="selectBlog" lang="myLanguage">
SELECT * FROM BLOG
</select>or
1
2
3
4
5public interface Mapper {
List<Blog> selectBlog();
}
Java API
这里主要介绍下 SqlSessions, 他是MyBatis中比较重要的接口.
SqlSessionFactoryBuilder
SqlSessions 由 SqlSessionFactory 实例创建, SqlSessionFactory 由 SqlSessionFactoryBuilder 构建, 也可以由 XML, 注解 创建
有5个方法, 用来创建 SqlSessionFactory
1 | SqlSessionFactory build(InputStream inputStream); |
属性可以从 mybatis-config.xml 中配置, 也可以方法传入, 还可以resource 或 url 指定, 对于相同的配置在多个地方配置, 是有优先级的, 对于重复属性, 前面加载的会被后面加载的所覆盖, 加载顺序是:
- 首先读取在 mybatis-config.xml 中的 properties 元素体中指定的属性;
- 其次,读取从 properties 元素的类路径 resource 或 url 指定的属性,且会覆盖已经指定了的重复属性;
- 最后,读取作为方法参数传递的属性,且会覆盖已经从 properties 元素体和 resource 或 url 属性中加载了的重复属性。
SqlSessionFactory
SqlSessionFactory 有六个方法创建 SqlSession 实例。通常来说,当你选择这些方法时你需要考虑以下几点:
- 事务处理:我需要在 session 使用事务或者使用自动提交功能(auto-commit)吗?(通常意味着很多数据库和/或 JDBC 驱动没有事务)
- 连接:我需要依赖 MyBatis 获得来自数据源的配置吗?还是使用自己提供的配置?
- 执行语句:我需要 MyBatis 复用预处理语句和/或批量更新语句(包括插入和删除)吗?
1 | SqlSession openSession(); |
SqlSession
MyBatis 是通过 SqlSession 执行语句, 提交事务, 回滚事务 等操作的.
执行语句
这些方法被用来执行定义在 SQL 映射的 XML 文件中的 增, 删, 改, 查 语句。它们都会自行解释,每一句都使用语句的 ID 属性和参数对象,参数可以是原生类型(自动装箱或包装类)、JavaBean、POJO 或 Map。
事务控制方法
控制事务作用域有四个方法。 但是使用场景有限,如果已经设置了自动提交或你正在使用外部事务管理器,这就没有任何效果了。然而,如果你正在使用 JDBC 事务管理器,由Connection 实例来控制,那么这四个方法就会派上用场:
Mybatis 一般会结合 Spring 使用, 一般会使用Spring来管理事务
1 | void commit(); |
本地缓存
有两种: 本地缓存 和 二级缓存
每创建一个新的 session, MyBatis 会创建一个关联的本地缓存, 保证不会重复查询数据库, 本地缓存默认能在整个Session周期内使用, 也可以设置 localCacheScope=STATEMENT 表示缓存仅在语句执行时有效。
注意: 如果 localCacheScope 被设置为 SESSION,那么 MyBatis 所返回的引用将传递给保存在本地缓存里的相同对象。对返回的对象(例如 list)做出任何更新将会影响本地缓存的内容,进而影响存活在 session 生命周期中的缓存所返回的值。因此,不要对 MyBatis 所返回的对象作出更改,以防后患。
使用映射器
MyBatis的sql是一般情况写到xml中的, 所以我们需要一个映射器, 来关联这语句, 调用这些映射器方法, 即可执行相应的SQL.
1 | public interface AuthorMapper { |
可以通过 @Param
来映射参数.
映射器注解
不仅仅可以使用xml来写sql, 注解也可以使用, 注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销.
仅仅列举我用过的啊, 感觉还是xml用着方便, 注解方式会让 XXXMapper.java 变的很难看, 我更喜欢干净的 XXXMapper.java
| 注解 | 使用对象 | 相对应的 XML | 描述 |
| — | — | — | — |
| @Param
| 参数 | N/A | 如果你的映射方法的形参有多个,这个注解使用在映射方法的参数上就能为它们取自定义名字。若不给出自定义名字,多参数(不包括 RowBounds
参数)则先以 “param” 作前缀,再加上它们的参数位置作为参数别名。例如 #{param1}
, #{param2}
,这个是默认值。如果注解是 @Param("person")
,那么参数就会被命名为 #{person}
。 |
| — | — | — | — |
日志^1
Mybatis 的内置日志工厂提供日志功能,内置日志工厂将日志交给以下其中一种工具作代理:
- SLF4J
- Apache Commons Logging
- Log4j 2
- Log4j
- JDK logging
MyBatis 会运行时查找并选择合适的日志工具, 从上到下依次查找, 如果没有找到日志将被禁用.
注意: 很多应用服务器会自带 commons logging, 这种情况下MyBatis会默认其为日志工具, 如果你想用其他的日志工具, 可以在 mybatis-config.xml
中指定.
1 | <configuration> |
logImpl 可选的值有:SLF4J
、LOG4J
、LOG4J2
、JDK_LOGGING
、COMMONS_LOGGING
、STDOUT_LOGGING
、NO_LOGGING
,或者是实现了接口 org.apache.ibatis.logging.Log
的,且构造方法是以字符串为参数的类的完全限定名。
你也可以调用如下任一方法来使用日志工具:
1 | org.apache.ibatis.logging.LogFactory.useSlf4jLogging(); |
如果你决定要调用以上某个方法,请在调用其它 MyBatis 方法之前调用它。另外,仅当运行时类路径中存在该日志工具时,调用与该日志工具对应的方法才会生效,否则 MyBatis 一概忽略。如你环境中并不存在 Log4J,你却调用了相应的方法,MyBatis 就会忽略这一调用,转而以默认的查找顺序查找日志工具。
日志配置(Log4J)
- 引入Log4J
- 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
# 指定某个sql
log4j.logger.org.mybatis.example.BlogMapper.selectBlog=TRACE
# 指定某个mapper
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 指定某个包下
log4j.logger.org.mybatis.example=TRACE mybatis-config.xml
中指定LOG4J
.