因为内容太多了,所以将其拆分为以下内容
参考
https://www.bilibili.com/video/BV1NE411Q7Nx
https://mybatis.org/mybatis-3/zh/index.html
动态 SQL
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC
或其它类似的框架,你应该能理解根据不同条件拼接 SQL
语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态
SQL,可以彻底摆脱这种痛苦。
使用动态 SQL 并非一件易事,但借助可用于任何 SQL
映射语句中的强大的动态 SQL 语言,MyBatis
显著地提升了这一特性的易用性。
如果你之前用过 JSTL 或任何基于类 XML 语言的文本处理器,你对动态 SQL
元素可能会感觉似曾相识。在 MyBatis
之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL
的表达式,MyBatis 3
替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
if
choose (when, otherwise)
trim (where, set)
foreach
数据库准备
1 2 3 4 5 6 7 CREATE TABLE `blog`(`id` VARCHAR (50 ) NOT NULL COMMENT '博客id' , `title` VARCHAR (100 ) NOT NULL COMMENT '博客标题' , `author` VARCHAR (30 ) NOT NULL COMMENT '博客作者' , `create_time` DATETIME NOT NULL COMMENT '创建时间' , `views` INT (30 ) NOT NULL COMMENT '浏览量' )ENGINE= INNODB DEFAULT CHARSET= utf8
实体类
1 2 3 4 5 6 7 8 9 10 @Data @NoArgsConstructor @AllArgsConstructor public class Blog { private String id; private String title; private String author; private Date createTime; private int views; }
接口和对应的 Mapper.xml
。。。
mybatis 配置略
1 2 3 4 public static SqlSession getSqlSession () { return sqlSessionFactory.openSession(true ); }
1 2 3 4 <settings > <setting name ="logImpl" value ="STDOUT_LOGGING" /> <setting name ="mapUnderscoreToCamelCase" value ="true" /> </settings >
mapUnderscoreToCamelCase:驼峰命名自动映射
If
1 2 3 4 5 6 7 8 9 <select id ="QueryBlogIf" parameterType ="map" resultType ="blog" > select * from blog where 1=1 <if test ="title!=null" > and title=#{title} </if > <if test ="author!=null" > and author=#{author} </if > </select >
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @Test public void queryBlogIf () { SqlSession sqlSession = MybatisUtil.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,Object> map=new HashMap <>(); map.put("title" ,"Java" ); map.put("author" ,"老杨" ); List<Blog> blogs = mapper.QueryBlogIf(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis
提供了 choose 元素,它有点像 Java 中的 switch 语句。
trim、where、set
where
where 元素只会在子元素返回任何内容的情况下才插入 “WHERE”
子句。而且,若子句的开头为 “AND” 或 “OR”,where
元素也会将它们去除。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <select id ="QueryBlogChoose" parameterType ="map" resultType ="blog" > select * from blog <where > <choose > <when test ="title!=null" > title=#{title} </when > <when test ="author!=null" > and author=#{author} </when > <otherwise > and views >#{view} </otherwise > </choose > </where > </select >
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Test public void queryBlogChoose () { SqlSession sqlSession = MybatisUtil.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,Object> map=new HashMap <>(); map.put("author" ,"老杨" ); map.put("view" ,3000 ); List<Blog> blogs = mapper.QueryBlogChoose(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
set
set 元素会动态地在行首插入 SET
关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)。
1 2 3 4 5 6 7 8 9 10 11 12 <update id ="updateBlog" parameterType ="map" > update blog <set > <if test ="title!=null" > title=#{title}, </if > <if test ="author!=null" > author=#{author}, </if > </set > where id=#{id} </update >
测试
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void updateBlog () { SqlSession sqlSession = MybatisUtil.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,Object> map=new HashMap <>(); map.put("id" ,"c3e4fcff19c64a4b8503883b4b999091" ); map.put("author" ,"小杨" ); mapper.updateBlog(map); sqlSession.close(); }
trim
参考
sql片段
抽取公共部分,方便复用
1 2 3 4 5 6 7 8 9 10 11 12 13 <sql id ="if-title-author" > <if test ="title!=null" > and title=#{title} </if > <if test ="author!=null" > and author=#{author} </if > </sql > <select id ="QueryBlogIf" parameterType ="map" resultType ="blog" > select * from blog where 1=1 <include refid ="if-title-author" > </include > </select >
foreach
foreach
元素的功能非常强大,它允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!
官方示例
1 2 3 4 5 6 7 8 9 <select id ="selectPostIn" resultType ="domain.blog.Post" > SELECT * FROM POST P WHERE ID in <foreach item ="item" index ="index" collection ="list" open ="(" separator ="," close =")" > #{item} </foreach > </select >
自己来
1 2 3 4 5 6 7 8 9 <select id ="queryBlogForeach" parameterType ="map" resultType ="blog" > select * from blog <where > <foreach collection ="ids" item ="id" open ="and (" separator ="or" close =")" > id=#{id} </foreach > </where > </select >
open 开始符,close 结束符,separator 分隔符
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test public void queryBlogForeach () { SqlSession sqlSession = MybatisUtil.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Map<String,Object> map=new HashMap <>(); List<Integer> ids=new ArrayList <>(); map.put("ids" ,ids); List<Blog> blogs = mapper.queryBlogForeach(map); for (Blog blog : blogs) { System.out.println(blog); } sqlSession.close(); }
缓存
MyBatis
内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制。
为了使它更加强大而且易于配置,我们对 MyBatis 3
中的缓存实现进行了许多改进。
默认情况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。
基本上就是这样。这个简单语句的效果如下:
映射语句文件中的所有 select 语句的结果将会被缓存。
映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
缓存会使用最近最少使用算法(LRU, Least Recently
Used)算法来清除不需要的缓存。
缓存不会定时进行刷新(也就是说,没有刷新间隔)。
缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
提示 缓存只作用于 cache
标签所在的映射文件中的语句。如果你混合使用 Java API 和 XML
映射文件,在共用接口中的语句将不会被默认缓存。你需要使用 @CacheNamespaceRef
注解指定缓存作用域。
1 2 3 4 5 6 7 8 9 10 11 12 @Test public void queryBlogById () { SqlSession sqlSession = MybatisUtil.getSqlSession(); BlogMapper mapper = sqlSession.getMapper(BlogMapper.class); Blog blog1 = mapper.queryBlogById(1 ); Blog blog2 = mapper.queryBlogById(1 ); System.out.println(blog1==blog2); sqlSession.close(); }
默认开启一级缓存,如下只会查询一次
1 2 3 4 5 6 7 8 9 10 Opening JDBC Connection Created connection 555273695. ==> Preparing: select * from blog where id = ? ==> Parameters: 1(Integer) <== Columns: id, title, author, create_time, views <== Row: 1, Mybatis, 老杨, 2021-02-08 11:00:41, 9999 <== Total: 1 true Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@2118cddf] Returned connection 555273695 to pool.
使用
1、开启全局缓存
1 2 <setting name ="cacheEnable" value ="true" />
2、在要使用的的 Mapper 中加上
可以自定义参数
1 2 3 4 5 <cache eviction ="FIFO" flushInterval ="60000" size ="512" readOnly ="true" />
3、测试
官网
因为内容太多了,所以将其拆分为以下内容